home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / cxabstra.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  40.5 KB  |  1,368 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "stdafx.h"
  20.  
  21. #include "cxabstra.h"
  22.  
  23. #include "xp_thrmo.h"
  24. #include "timer.h"  // for nettimer since can't call base class
  25. #include "libi18n.h"    // International function 
  26. #include "template.h"
  27. #include "dialog.h"
  28. #include "mainfrm.h"
  29. #ifdef MOZ_MAIL_NEWS
  30. #include "fldrfrm.h"
  31. #include "thrdfrm.h"
  32. #include "msgfrm.h"
  33. #include "msgcom.h"
  34. #include "wfemsg.h"
  35. #endif /* MOZ_MAIL_NEWS */
  36. #include "winclose.h"
  37. #include "libevent.h"
  38. #include "np.h"
  39. #include "intl_csi.h"
  40. #include "mkhelp.h"    // for HelpInfoStruct
  41. #include "feimage.h"
  42. #include "cxicon.h"
  43. #ifdef EDITOR
  44. #include "edt.h"
  45. #endif /* EDITOR */
  46. #include "mozilla.h"
  47.  
  48. CAbstractCX::CAbstractCX()  {
  49. //    Purpose:    Constructor for the abstract base class.
  50. //    Arguments:  void
  51. //    Returns:    none
  52. //    Comments:   Responsible for creating the XP context.
  53.  
  54.     m_pLastStatus = NULL;
  55.  
  56.     //  First set our context type.
  57.     //  This is really irrelevant, just a reminder to those which derive from us.
  58.     m_cxType = Abstract;
  59.  
  60.     //  Create the XP context.
  61.     m_pXPCX = XP_NewContext();
  62.     m_pImageGroupContext = 0;
  63.     m_bImagesLoading = FALSE;
  64.     m_bImagesLooping = FALSE;
  65.     m_bImagesDelayed = FALSE;
  66.     m_bMochaImagesLoading = FALSE;
  67.     m_bMochaImagesLooping = FALSE;
  68.     m_bMochaImagesDelayed = FALSE;
  69.  
  70.     m_bNetHelpWnd = FALSE;
  71.     
  72.     //    Set its type to an invalid default.
  73.     //    Up to others to correctly set.
  74.     m_pXPCX->type = MWContextAny;
  75.  
  76.     m_pXPCX->fontScalingPercentage = 1.0;
  77.  
  78.     //  Assign in the common front end functions.
  79.     m_pXPCX->funcs = new ContextFuncs;
  80. #define MAKE_FE_FUNCS_PREFIX(funkage) CFE_##funkage
  81. #define MAKE_FE_FUNCS_ASSIGN m_pXPCX->funcs->
  82. #include "mk_cx_fn.h"
  83.  
  84.     //  Set the FE data to simply point to this class.
  85.     m_pXPCX->fe.cx = this;
  86.  
  87.     //    Initialize the global history of the object.
  88.     SHIST_InitSession(m_pXPCX);
  89.  
  90.     //    We haven't been told to attempt to interrupt the load.
  91.     //  Nor have we decided to self destruct.
  92.     m_bIdleInterrupt = FALSE;
  93.     m_bIdleDestroy = FALSE;
  94.  
  95.     //  We have no client pull information.
  96.     m_pClientPullData = FALSE;
  97.     m_pClientPullTimeout = FALSE;
  98.  
  99.     //    Reset our stopwatch, in case it never gets initialized.
  100.     ResetStopwatch();
  101.  
  102.     //    We haven't been destroyed yet.
  103.     m_bDestroyed = FALSE;
  104.  
  105.     //    We have ncapi data yet.
  106.     m_pNcapiUrlData = NULL;
  107.  
  108.     //    We are initially allowing clicks.
  109.     GetContext()->waitingMode = FALSE;
  110.  
  111.     //    Add the context to the XP list.
  112.     XP_AddContextToList(GetContext());
  113.  
  114.     //    No levels of interruptedness.
  115.     m_iInterruptNest = 0;
  116. }
  117.  
  118. int16  CAbstractCX::GetWinCsid()
  119. {
  120.     return INTL_GetCSIWinCSID(LO_GetDocumentCharacterSetInfo(m_pXPCX));
  121. }
  122. /*
  123.  * Mocha has removed all of its info from this context, it's
  124.  *   safe to trash it now
  125.  */
  126. void CAbstractCX::MochaDestructionComplete()
  127. {
  128.     //    Now, attempt to interrupt.  This allows us to clean up a context, even
  129.     //        if the network library is blocking.
  130.     //    Eventually, this will cause this context to delete itself.
  131.     Interrupt();
  132. }
  133.  
  134. /*
  135.  * Mocha has removed all of its info from this context
  136.  */
  137. void mocha_done_callback(void * data)
  138. {
  139.     ((CAbstractCX *)data)->MochaDestructionComplete();
  140. }
  141.  
  142. void CAbstractCX::DestroyContext()    {
  143. //    Purpose:    Before deleting a context, you must destroy it for proper cleanup.
  144. //    Arguments:    void
  145. //    Returns:    void
  146. //    Comments:    Because the XP libraries perform calls on a context when it is going
  147. //                    away, and those calls are virtual, we must first "destroy" a context,
  148. //                    and then we are able to delete it properly.
  149.  
  150.     if(m_bDestroyed == FALSE)   {
  151.         //    Only call in here once, please.
  152.         //  We have to lock the application from exiting until we receive
  153.         //      a series of callbacks and eventually remove the context
  154.         //      from memory.
  155.         //  This lock is removed in the destructor.
  156.         AfxOleLockApp();
  157.  
  158.         //    Have the document interrupt.
  159.         //    We call again when we get the mocha complete callback, but that 
  160.         //      causes us to get deleted physically after the destroyed flag 
  161.         //      is set.
  162.         Interrupt();
  163.  
  164.         //  Layout needs to cleanup.
  165.         LO_DiscardDocument(m_pXPCX);
  166.  
  167.         //    End the session history of the context.
  168.         SHIST_EndSession(m_pXPCX);
  169.  
  170. #ifdef MOZ_MAIL_NEWS
  171.         // Free any memory used for MIME objects
  172.         MimeDestroyContextData(m_pXPCX);
  173. #endif /* MOZ_MAIL_NEWS */
  174.  
  175.         //    We are now destroyed, set a member to let us know.
  176.         m_bDestroyed = TRUE;
  177.  
  178.         if(m_pImageGroupContext)   {
  179.             IL_RemoveGroupObserver(m_pImageGroupContext, ImageGroupObserver, (void*)GetContext());
  180.             IL_DestroyGroupContext(m_pImageGroupContext);
  181.             m_pXPCX->img_cx = NULL;
  182.         }
  183.  
  184.          if (m_pXPCX->color_space) {
  185.             IL_ReleaseColorSpace(m_pXPCX->color_space);
  186.             m_pXPCX->color_space = NULL;
  187.         }
  188.             
  189.         //    Remove ourselves from the XP context list.
  190.         //  Must be done before call to mocha, or lists in
  191.         //      unstable state.
  192.         XP_RemoveContextFromList(m_pXPCX);
  193.  
  194.         //  Have mocha perform cleanup and continue destruction in the
  195.         //    callback
  196.         ET_RemoveWindowContext(m_pXPCX, mocha_done_callback, this);
  197.     }
  198. }
  199.  
  200. /*-----------------------------------------------**
  201. ** Let a load complete before self destructing.  **
  202. **-----------------------------------------------*/
  203. void CAbstractCX::NiceDestroyContext() {
  204.     m_bIdleDestroy = FALSE;
  205.     if(m_bDestroyed == FALSE && GetContext()) {
  206.         if(XP_IsContextBusy(GetContext())) {
  207.             //  Try again later.
  208.             m_bIdleDestroy = TRUE;
  209.             FEU_RequestIdleProcessing(GetContext());
  210.         }
  211.         else {
  212.             //  Time's up.
  213.             DestroyContext();
  214.             return;
  215.         }
  216.     }
  217. }
  218.  
  219. //  Routine to detect when we can exit.
  220. void fe_finish_exit(void *pClosure)
  221. {
  222.     BOOL bCanExit = TRUE;
  223.     static void *pExitTimer = NULL;
  224.  
  225.     if(pClosure != NULL)    {
  226.         //  Called via timeout.
  227.         //  Clear the timeout backpointer.
  228.         pExitTimer = NULL;
  229.     }
  230.     else    {
  231.         //  Called via destructor (anal).
  232.         //  Make sure we haven't already set the timer.
  233.         if(pExitTimer != NULL)  {
  234.             return;
  235.         }
  236.     }
  237.  
  238. #ifdef MOZ_LOC_INDEP
  239.     /* li_stuff - time to do last synch */
  240.     if (theApp.LIStuffEnd() == FALSE) {
  241.         //  synching files.
  242.         bCanExit = FALSE;
  243.     }
  244. #endif // MOZ_LOC_INDEP
  245.  
  246.     if(AfxOleCanExitApp() == FALSE) {
  247.         //  Outstanding com lock.
  248.         bCanExit = FALSE;
  249.     }
  250.  
  251.     if(XP_ListCount(XP_GetGlobalContextList()) != 0) {
  252.         //  Context is out there.
  253.         bCanExit = FALSE;
  254.     }
  255.  
  256.     if(theApp.m_pMainWnd != NULL)   {
  257.         if(bCanExit)    {
  258.             TRACE("Posting WM_CLOSE to %p hidden frame to exit app.\n", theApp.m_pMainWnd);
  259.             theApp.m_pMainWnd->PostMessage(WM_CLOSE);
  260.         }
  261.         else    {
  262.             //  Have to retry in a little while.
  263.             pExitTimer = FE_SetTimeout(fe_finish_exit, (void *)-1, 1000);
  264.             ASSERT(pExitTimer != NULL);
  265.         }
  266.     }
  267. }
  268.  
  269. CAbstractCX::~CAbstractCX() {
  270. //    Purpose:    Destroy the context.
  271. //    Arguments:  void
  272. //    Returns:    none
  273. //    Comments:   Perform any necessary cleanup also.
  274.  
  275.     //  Can remove lock set in DestroyContext.
  276.     //  Window of instability gone.
  277.     AfxOleUnlockApp();
  278.  
  279.     //  Let those watching this context that it is no more (NCAPI).
  280.     CWindowChangeItem::Closing(GetContextID());
  281.  
  282.     //    If you get this ASSERTION, then you should call DestroyContext and
  283.     //        NEVER delete the context.
  284.     ASSERT(m_bDestroyed == TRUE);
  285.  
  286.     //    Get rid of the last and default status.
  287.     if (m_pLastStatus)    {
  288.         XP_FREE(m_pLastStatus);
  289.         m_pLastStatus = NULL;
  290.     }
  291.     if(m_pXPCX->defaultStatus != NULL)    {
  292.         XP_FREE(m_pXPCX->defaultStatus);
  293.         m_pXPCX->defaultStatus = NULL;
  294.     }
  295.  
  296.     //    If we allocated a title for the context, get rid of it.
  297.     if(m_pXPCX->title != NULL)    {
  298.         XP_FREE(m_pXPCX->title);
  299.         m_pXPCX->title = NULL;
  300.     }
  301.  
  302.     //    Get rid of its name.
  303.     if(m_pXPCX->name != NULL)    {
  304.         XP_FREE(m_pXPCX->name);
  305.         m_pXPCX->name = NULL;
  306.     }
  307.  
  308.     // Free the transparent pixel used by the Image Library.
  309.     if(m_pXPCX->transparent_pixel) {
  310.         XP_FREE(m_pXPCX->transparent_pixel);
  311.         m_pXPCX->transparent_pixel = NULL;
  312.     }
  313.  
  314.     /* EA: Remove any help information associated with this context */    
  315.      if (m_pXPCX && (m_pXPCX->pHelpInfo != NULL)) {
  316.          if (((HelpInfoStruct *) m_pXPCX->pHelpInfo)->topicURL != NULL) {
  317.              XP_FREE(((HelpInfoStruct *) m_pXPCX->pHelpInfo)->topicURL);
  318.              ((HelpInfoStruct *) m_pXPCX->pHelpInfo)->topicURL = NULL;
  319.          }
  320.  
  321.           XP_FREE(m_pXPCX->pHelpInfo);
  322.           m_pXPCX->pHelpInfo = NULL;
  323.      }
  324.  
  325.     //  Delete our function table in the XP context.
  326.     memset(m_pXPCX->funcs, 0, sizeof(*(m_pXPCX->funcs)));
  327.     delete m_pXPCX->funcs;
  328.     m_pXPCX->funcs = NULL;
  329.  
  330.     //  Delete our XP context.
  331.     XP_DeleteContext(m_pXPCX);
  332.     m_pXPCX = NULL;
  333.  
  334.     // NOTE: Frames and Views should be taken care of by sub-classes
  335.  
  336.     // There are three "hiding" contexts
  337. #ifdef MOZ_MAIL_NEWS
  338. #define HIDDENCXS 4
  339. #else
  340. #define HIDDENCXS 2
  341. #endif /* MOZ_MAIL_NEWS */
  342.     //  bookmarks window
  343.     //  address book window
  344.     //  biff / check mail context
  345.     //  Misc. URL loader context which switch context, ie: NetHelp, etc.
  346.     // Check the number of items in the context list to see if we should exit.
  347.     if(XP_ListCount(XP_GetGlobalContextList()) == HIDDENCXS)    {
  348.         //  These are the stragglers that we need to see if visible,
  349.         //      and if not, remove them at this time.
  350.         //  All or none.
  351.         //  Do in seperate for loops or list state is undefined.
  352.         CAbstractCX *pCXs[HIDDENCXS];
  353.         int iTraverse;
  354.         for(iTraverse = 0; iTraverse < HIDDENCXS; iTraverse++)  {
  355.             pCXs[iTraverse] = ABSTRACTCX((MWContext *)XP_ListGetObjectNum(XP_GetGlobalContextList(), iTraverse + 1));
  356.         }
  357.         for(iTraverse = 0; iTraverse < HIDDENCXS; iTraverse++)  {
  358.             if(pCXs[iTraverse]) {
  359.                 pCXs[iTraverse]->DestroyContext();
  360.             }
  361.         }
  362.         
  363.         //  Because we've killed off the hidden contexts, clear pointers
  364.         //      to them.
  365.         theApp.m_pSlaveCX = NULL;
  366.         theApp.m_pRDFCX = NULL;
  367.  
  368.         //  Start to detect when we can exit the application.
  369.         fe_finish_exit(NULL);
  370.     }
  371. }
  372.  
  373. void CAbstractCX::SetContextName(const char *pName)    {
  374.     //    Set the context name.
  375.     if(GetContext()->name != NULL)    {
  376.         XP_FREE(GetContext()->name);
  377.     }
  378.     if(pName != NULL)    {
  379.         GetContext()->name = XP_STRDUP(pName);
  380.     }
  381.     else    {
  382.         GetContext()->name = NULL;
  383.     }
  384. }
  385.  
  386. void CAbstractCX::SetParentContext(MWContext *pParentContext)    {
  387.     //    Set the context's parent context.
  388.     GetContext()->grid_parent = pParentContext;
  389.  
  390.     //    Also set that this is a grid cell.
  391.     //    Can't have a grid parent if not a true grid.
  392.     GetContext()->is_grid_cell = TRUE;
  393.  
  394.     //    Finally, update what is called the parent's list of children.
  395.     //    Removal is taken care of automagically.
  396.     XP_UpdateParentContext(GetContext());
  397. }
  398.  
  399. BOOL CAbstractCX::IsGridCell() const    {
  400.     return(GetContext()->is_grid_cell);
  401. }
  402.  
  403. BOOL CAbstractCX::IsGridParent() const    {
  404.     BOOL bRetval = FALSE;
  405.     MWContext *pContext = GetContext();
  406.     if(pContext) {
  407.         bRetval = !XP_ListIsEmpty(pContext->grid_children);
  408.     }
  409.     return bRetval;
  410. }
  411.  
  412. CWnd *CAbstractCX::GetDialogOwner() const    {
  413. //    Purpose:    Return the parent/owner of any dialogs for the context.
  414. //    Arguments:  void
  415. //    Returns:    CWnd *    The parent as needed.
  416. //    Comments:   Generic use function to more easily define the owner
  417. //                    of any dialogs.
  418.  
  419.     //    As a default, we'll be returning the desktop window.
  420.     return(CWnd::GetDesktopWindow());
  421. }
  422.  
  423. // This routine changes the context of the specified URL structure to be
  424. // a browser context. Returns the new context if successful and NULL otherwise
  425. MWContext *SwitchToBrowserContext(URL_Struct* pUrlStruct)
  426. {
  427.     ASSERT(NET_IsSafeForNewContext(pUrlStruct));
  428.  
  429.     // Use an existing browser window if we have one
  430.     CFrameWnd*    pFrameWnd = FEU_GetLastActiveFrame(MWContextBrowser, FEU_FINDBROWSERONLY);
  431.     MWContext*    pNewContext = NULL;
  432.  
  433.     if (pFrameWnd) {
  434.         CFrameGlue *pGlue = CFrameGlue::GetFrameGlue(pFrameWnd);
  435.         CWinCX*        pWinCX;
  436.  
  437.         if (pGlue && ((pWinCX = pGlue->GetMainWinContext()) != NULL)) {
  438.             pNewContext = pWinCX->GetContext();
  439.  
  440.             // Don't use this context if it's busy or doesn't want to be used.
  441.             if (ABSTRACTCX(pNewContext)->IsContextStoppable() 
  442.                             || pNewContext->restricted_target)
  443.                 pNewContext = NULL;  // create a new context instead
  444.             else {    
  445.                 pWinCX->GetUrl( pUrlStruct, FO_CACHE_AND_PRESENT, TRUE );
  446.                 // Make sure the window is visible
  447.                 if(pFrameWnd->IsIconic())
  448.                     pFrameWnd->ShowWindow(SW_RESTORE);
  449.                 else {
  450. #ifdef XP_WIN16
  451.                     pFrameWnd->BringWindowToTop();
  452. #else
  453.                     pFrameWnd->SetForegroundWindow();
  454. #endif
  455.                 }
  456.             }
  457.         }
  458.     }
  459.  
  460.     // If we couldn't find an existing browser window, then create a new one
  461.     if (!pNewContext) {
  462.         // Create a new browser window
  463.         pNewContext = CFE_CreateNewDocWindow(NULL, pUrlStruct);
  464.     }
  465.  
  466.     return pNewContext;
  467. }
  468.  
  469. int CAbstractCX::NormalGetUrl(const char *pUrl, const char *pReferrer, const char *pTarget, BOOL bForceNew)    {
  470.     //    Generic brain dead interface to GetUrl.
  471.     URL_Struct *pUrlStruct = NET_CreateURLStruct(pUrl, NET_DONT_RELOAD);
  472.  
  473.     //    Add the referrer field.
  474.     if(pReferrer != NULL)    {
  475.         pUrlStruct->referer = XP_STRDUP(pReferrer);
  476.     }
  477.  
  478.     //    Add the target name.
  479.     if(pTarget != NULL)    {
  480.         if (pTarget[0] == '_')    {
  481.             pUrlStruct->window_target = XP_STRDUP("");
  482.         }
  483.         else    {
  484.             pUrlStruct->window_target = XP_STRDUP(pTarget);
  485.         }
  486.     }
  487.  
  488.     //    Load it.
  489. #ifdef EDITOR
  490.     // Use Edit present type to filter mime types we can't edit
  491.     return( GetUrl(pUrlStruct, EDT_IS_EDITOR(GetContext()) ? FO_CACHE_AND_EDIT : FO_CACHE_AND_PRESENT, TRUE, bForceNew));
  492. #else
  493.     return(GetUrl(pUrlStruct, FO_CACHE_AND_PRESENT, TRUE, bForceNew));
  494. #endif
  495. }
  496.  
  497. int CAbstractCX::GetUrl(URL_Struct *pUrl, FO_Present_Types iFormatOut, BOOL bReallyLoad, BOOL bForceNew)    {
  498. //    Purpose:    Load a url into the context class.
  499. //    Arguments:    pUrl    The URL to load
  500. //                iFormatOut    The format out of the load (helps determine the content type converter
  501. //                                along with the mime type).
  502. //                bReallyLoading    Is a switch to tell us not to actually request the URL.
  503. //                                This helps and context changing URLs to bootstrap the loading UI.
  504. //    Returns:    int    As NET_GetURL
  505. //    Comments:    Use this instead of NET_GetURL
  506.  
  507.     //  Determine URL type.  -1 is out of range.
  508.     int iUrlType = -1;
  509.     if(pUrl && pUrl->address) {
  510.         iUrlType = NET_URL_Type(pUrl->address);
  511.     }
  512.  
  513.     //  Switch on URL type to see how we should handle.
  514.     int iRetval = MK_NO_ACTION;
  515.     switch(iUrlType) {
  516.         case NETHELP_TYPE_URL: {
  517.             MWContext *pNetHelpCX = FE_GetNetHelpContext();
  518.             if(pNetHelpCX) {
  519.                 iRetval = NET_GetURL(pUrl, FO_PRESENT, pNetHelpCX, CFE_SimpleGetUrlExitRoutine);
  520.             }
  521.             break;
  522.         }
  523.         default: {
  524.             //    See if this is the current page (named anchor), if so don't load.
  525.             //    But don't do this if we're not really initiating the load ourselves.
  526.             //    Also make sure that this is a present type, if not, don't check
  527.             //        for this named anchor stuff.
  528.             //    If this isn't acceptable behaviour, we really need to split what
  529.             //        you're doing into a new context (view source dialog could be this
  530.             //        way as an example).
  531.             int32 lX, lY;
  532.             BOOL bNamedAnchor = FALSE;
  533.             if(((iFormatOut & 0x1f ) == FO_PRESENT) && bReallyLoad == TRUE && XP_FindNamedAnchor(GetContext(), pUrl, &lX, &lY) == TRUE)    {
  534.                 if(IsWindowContext())    {
  535.                     //    Make the location visible on the screen....
  536.                     PANECX(GetContext())->MakeElementVisible(lX, lY);
  537.                 }
  538.                 if(pUrl->history_num == 0)    {
  539.                     //  Create URL from prev history entry to preserve security attributes, etc.
  540.                     History_entry *pHist = SHIST_GetCurrent(&GetContext()->hist);
  541.                     URL_Struct *pCopyURL = SHIST_CreateURLStructFromHistoryEntry(GetContext(), pHist);
  542.  
  543.                     //  Swap addresses.
  544.                     char *pSaveAddr = pUrl->address;
  545.                     pUrl->address = pCopyURL->address;
  546.                     pCopyURL->address = pSaveAddr;
  547.  
  548.                     //  Free old URL, and reassign.
  549.                     NET_FreeURLStruct(pUrl);
  550.                     pUrl = pCopyURL;
  551.  
  552.                     SHIST_AddDocument(GetContext(), SHIST_CreateHistoryEntry(pUrl, pHist->title));
  553.                 }
  554.                 else    {
  555.                     SHIST_SetCurrent(&GetContext()->hist, pUrl->history_num);
  556.                 }
  557.  
  558.                 //    Didn't have to perform a load.
  559.                 //    However, we should call the normal routines to stop all the UI....
  560.                 bReallyLoad = FALSE;
  561.                 bNamedAnchor = TRUE;
  562.             }
  563.  
  564.             //    The URLs anchor and referrer may be a local file path.
  565.             //    Change them to be network worthy.
  566.             CString csUrl;
  567.             if(pUrl->address != NULL)    {
  568.                 WFE_ConvertFile2Url(csUrl, pUrl->address);
  569.                 XP_FREE(pUrl->address);
  570.                 pUrl->address = XP_STRDUP(csUrl);
  571.             }
  572.             if(pUrl->referer != NULL)    {
  573.                 WFE_ConvertFile2Url(csUrl, pUrl->referer);
  574.                 XP_FREE(pUrl->referer);
  575.                 pUrl->referer = XP_STRDUP(csUrl);
  576.             }
  577.  
  578. #ifdef MOZ_MAIL_NEWS
  579.             if ((((iFormatOut & 0x1f ) == FO_PRESENT) 
  580.                   && (GetContext()->type != MWContextMetaFile) 
  581.                   && MSG_NewWindowRequired(GetContext(), pUrl->address)) 
  582.                   || bForceNew)
  583.  
  584.             {
  585.                 MWContextType type = MWContextBrowser;
  586.                 if ( MSG_RequiresMailWindow ( pUrl->address ) )    
  587.                     type = MWContextMail;
  588.                 else if ( MSG_RequiresNewsWindow ( pUrl->address ) )
  589.                     type = MWContextNews;
  590.                
  591.                 if (( ( type == MWContextNews ) || ( type == MWContextMail ) ) && !bForceNew )
  592.                 {
  593.                     CMailNewsFrame *pMailNewsFrame = NULL;
  594.                     MSG_PaneType paneType = MSG_PaneTypeForURL(pUrl->address);
  595.  
  596.                     switch ( paneType )
  597.                     {
  598.                     case MSG_THREADPANE:
  599.                         {
  600.                         MSG_FolderInfo *folder = MSG_GetFolderInfoFromURL(WFE_MSGGetMaster(), pUrl->address);
  601.                         BOOL bContinue = FALSE;
  602.                         if (folder){
  603.                             C3PaneMailFrame::Open(folder, MSG_MESSAGEKEYNONE, &bContinue);
  604.                         }
  605.                         if (!bContinue)
  606.                             return MK_CHANGING_CONTEXT;
  607.                         else
  608.                             break;
  609.                         }
  610.                     case MSG_MESSAGEPANE:
  611.                         {
  612.                         C3PaneMailFrame *pThreadFrame = CMailNewsFrame::GetLastThreadFrame();
  613.                         if (pThreadFrame && pThreadFrame == CWnd::GetActiveWindow() &&
  614.                             pThreadFrame->GetMainContext() == this)
  615.                             break;
  616.                         pMailNewsFrame = CMessageFrame::Open();
  617.                         if ( pMailNewsFrame ) {
  618.                             pUrl->msg_pane = pMailNewsFrame->GetPane();
  619.                             pMailNewsFrame->GetContext()->GetUrl( pUrl, iFormatOut, bReallyLoad );
  620.                         }
  621.                         return MK_CHANGING_CONTEXT;
  622.                         }
  623.                     case MSG_FOLDERPANE:
  624.                     default:
  625.                         pMailNewsFrame = CFolderFrame::Open();
  626.                         if ( pMailNewsFrame )
  627.                             pMailNewsFrame->GetContext()->GetUrl( pUrl, iFormatOut, bReallyLoad );
  628.                         return MK_CHANGING_CONTEXT;
  629.                     }
  630.                 }
  631.                 else if (GetContextType() != IconCX && GetContextType() != Pane) {
  632.                     MWContext* pNewContext = SwitchToBrowserContext(pUrl);
  633.                     return MK_CHANGING_CONTEXT;
  634.                 }
  635.             }
  636. #endif // MOZ_MAIL_NEWS
  637.  
  638.             //    Our first (well, almost) task is to interrupt the load.
  639.             //    Only one load per window should be instantiated by the front end.
  640.             //  Do this only if this is the context which is going to handle it.
  641.             //  If this is a view source request, don't interrupt the context
  642.             //  because we will be creating a new window.
  643.             if(bNamedAnchor == FALSE && bReallyLoad == TRUE &&
  644.                 iFormatOut != FO_CACHE_AND_VIEW_SOURCE)    {
  645.                 Interrupt();
  646.             }
  647.  
  648.             //    Disable clicking.
  649.             GetContext()->waitingMode = TRUE;
  650.  
  651.             //    The fun part about all this is, is that we don't want to call reentrantly
  652.             //        into the netlib, or else our idle interrupt routine will interrupt
  653.             //        both requests.  Check to see if we're waiting for an idle interrupt.
  654.             //    Use the client pull mechanism to get around this.
  655.             //    Also, if we're not supposed to really call to load this URL, then don't.
  656.             if(bReallyLoad == TRUE)    {
  657.                 if(m_bIdleInterrupt == FALSE)    {
  658.                     //    Simply call the netlib routine, filling in some default data.
  659.                     //    Pass along the common exit routine, which will call the appropriate
  660.                     //        contexts exit routine.
  661.                     int iOldInProcessNet = winfeInProcessNet; 
  662.                     winfeInProcessNet = TRUE;
  663.                     StartAnimation();
  664.                     if ( m_cxType == IconCX)
  665.                         iRetval = NET_GetURL(pUrl, iFormatOut, GetContext(), Icon_GetUrlExitRoutine);
  666.                     else
  667.                         iRetval = NET_GetURL(pUrl, iFormatOut, GetContext(), CFE_GetUrlExitRoutine);
  668.                     FE_UpdateStopState(GetContext());
  669.  
  670.                     winfeInProcessNet = iOldInProcessNet;
  671.                 }
  672.                 else    {
  673.                     //    Set client pull on this URL.
  674.                     FEU_ClientPull(GetContext(), 250, pUrl, iFormatOut, TRUE);
  675.  
  676.                     //    Return that no action was taken, yet.
  677.                     iRetval = MK_NO_ACTION;
  678.                 }
  679.             }
  680.             else    {
  681.                 //    Indicate that we skipped loading since we're allowing someone to change
  682.                 //        context.
  683.                 iRetval = MK_CHANGING_CONTEXT;
  684.             }
  685.  
  686.             //    If we were a named anchor, clean everything we did up.
  687.             if(bNamedAnchor == TRUE)    {
  688.                 iRetval = MK_DATA_LOADED;
  689.  
  690.                 //    We need to update the location bar's text, since LayoutNewDocument was never
  691.                 //        called (routine responsible for this).
  692.                 if(IsFrameContext() && GetContext()->type == MWContextBrowser && !EDT_IS_EDITOR(GetContext())){
  693.  
  694.                     if(IsGridCell() == FALSE)    {
  695.                         TRACE("Updating location bar for named anchor\n");
  696.                         CWinCX *pWinCX = WINCX(GetContext());
  697.                         CFrameGlue *pFrame = pWinCX->GetFrame();
  698.  
  699.                         if(pFrame){
  700.                             CURLBar *pUrlBar = (CURLBar *)pFrame->GetChrome()->GetToolbar(ID_LOCATION_TOOLBAR);
  701.                             if(pUrlBar)
  702.                                 pUrlBar->UpdateFields(pUrl->address);
  703.                         }
  704.                     }
  705.                 }
  706.  
  707.                 //    Call the exit routine on the URL.
  708.                 //    Just use the common one that would have been used anyhow.
  709.                 CFE_GetUrlExitRoutine(pUrl, iRetval, GetContext());
  710.  
  711.                 //    If there aren't any connections for the window, also call all connections
  712.                 //        complete.
  713.                 //    Context by context version, don't use XP_IsContextBusy.
  714.                 if(NET_AreThereActiveConnectionsForWindow(GetContext()) == FALSE)    {
  715.                     FE_AllConnectionsComplete(GetContext());
  716.                 }
  717.             }
  718.             break;
  719.         }
  720.     }
  721.  
  722.     //  All Done.
  723.     return(iRetval);
  724. }
  725.  
  726. void CAbstractCX::Reload(NET_ReloadMethod iReloadType)    {
  727. //    Purpose:    Reloads the current document in the context's history.
  728. //    Arguments:    void
  729. //    Returns:    void
  730. //    Comments:    Standard stuff.
  731.  
  732.     if(CanCreateUrlFromHist())    {
  733.         URL_Struct *pUrl = CreateUrlFromHist(FALSE, NULL, iReloadType == NET_RESIZE_RELOAD);
  734.  
  735.         //    Force the load (normally).
  736.         if(pUrl)    {
  737.             pUrl->force_reload = iReloadType;
  738.  
  739.             GetUrl(pUrl, FO_CACHE_AND_PRESENT);
  740.         }
  741.     }
  742. }
  743.  
  744. extern "C" Bool LO_LayingOut(MWContext * context);
  745.  
  746. void CAbstractCX::NiceReload(int usePassInType, NET_ReloadMethod iReloadType )    {
  747. //    Purpose:    Reloads the current document in the context's history, only
  748. //                    if we're currently not loading.
  749. //    Arguments:    void
  750. //    Returns:    void
  751. //    Comments:    Standard stuff.
  752.  
  753.     MWContext * context = GetContext();
  754.     if(XP_IsContextBusy(context) == TRUE || LO_LayingOut(context))    {
  755.         FEU_RequestIdleProcessing(context);
  756.         context->reSize = TRUE;
  757.     }
  758.     else    {
  759.         context->reSize = FALSE;
  760.         NPL_SamePage(context);
  761.         if( usePassInType ) {
  762.             Reload( iReloadType );
  763.             return;
  764.         }
  765.  
  766.         if (MAIL_NEWS_TYPE(context->type)) {
  767.             Reload(NET_NORMAL_RELOAD);
  768.         }
  769.         else {
  770.             Reload(NET_RESIZE_RELOAD);
  771.         }
  772.     }
  773. }
  774.  
  775. void CAbstractCX::Back()    {
  776. //    Purpose:    Goes back one in the history.
  777. //    Arguments:    void
  778. //    Returns:    void
  779. //    Comments:    Standard stuff.
  780.  
  781.     History_entry *pHist = SHIST_GetPrevious(GetContext());
  782.     if (GetContext()->grid_children) {
  783.         if (LO_BackInGrid(GetDocumentContext())) {
  784.         return;
  785.         }
  786.     }
  787.     if(pHist)    {
  788.         GetUrl(SHIST_CreateURLStructFromHistoryEntry(GetContext(), pHist), FO_CACHE_AND_PRESENT);
  789.     }
  790. }
  791.  
  792. void CAbstractCX::Forward()    {
  793. //    Purpose:    Goes forward one in the history.
  794. //    Arguments:    void
  795. //    Returns:    void
  796. //    Comments:    Standard stuff.
  797.  
  798.     History_entry *pHist = SHIST_GetNext(GetContext());
  799.     if (GetContext()->grid_children) {
  800.         if (LO_ForwardInGrid(GetDocumentContext())) {
  801.         return;
  802.         }
  803.     }
  804.     if(pHist)    {
  805.         GetUrl(SHIST_CreateURLStructFromHistoryEntry(GetContext(), pHist), FO_CACHE_AND_PRESENT);
  806.     }
  807. }
  808.  
  809. XL_TextTranslation CAbstractCX::TranslateText(URL_Struct *pUrl, const char *pFileName, const char *pPrefix, int iWidth)  {
  810. //    Purpose:    Translate a url into text.
  811. //    Arguments:  pUrl        The URL to translate.
  812. //              pFileName   The file in which to save the translation, CANNOT BE NULL.
  813. //              pPrefix     A prefix for each line, CANNOT BE NULL.
  814. //              iWidth      The width in characters of each line.
  815. //    Returns:    XL_TextTranslation as XL_TranslateText
  816. //    Comments:   Wraps all the work of manually calling the text translation routines.
  817. //              There's no need to track the PrintSetup struct we create in this function,
  818. //                  as it will come back in the translation exit routine and can be
  819. //                  freed there.
  820.  
  821.     //  Create a new print setup.
  822.     PrintSetup *pTextFE = XP_NEW(PrintSetup);
  823.  
  824.     //  Initialize.
  825.     XL_InitializeTextSetup(pTextFE);
  826.  
  827.     //  Assign in the needed members.
  828.     pTextFE->width = iWidth;
  829.     if(pPrefix)
  830.         pTextFE->prefix = XP_STRDUP(pPrefix);
  831.     else
  832.         pTextFE->prefix = XP_STRDUP("");
  833.     pTextFE->eol = "\r\n";
  834.     pTextFE->filename = XP_STRDUP(pFileName);
  835.     pTextFE->out = fopen(pFileName, "wb");
  836.     pTextFE->completion = CFE_TextTranslationExitRoutine;   //  Abstracted exit routine.
  837.     pTextFE->url = pUrl;
  838.     pTextFE->carg = CX2VOID(this, CAbstractCX);
  839.  
  840.     //  Do it.
  841.     return(XL_TranslateText(GetContext(), pUrl, pTextFE));
  842. }
  843.  
  844. void CAbstractCX::Interrupt()    {
  845. //    Purpose:    Interrupt any loads in a context.
  846. //    Arguments:    void
  847. //    Returns:    void
  848. //    Comments:    If able, this will interrupt any loads in a context.
  849. //                    If unable, then sets a flag for idle time interrupting.
  850.  
  851.     //    Increment our level of nested ness in the Interrupt function.
  852.     //    Problem is, that this is the only function which actually deletes
  853.     //        a context.
  854.     //    If we're nested several levels, then each tries to free the context.
  855.     m_iInterruptNest++;
  856.  
  857.     //    Provide a way to interrupt even if we're winfeInProcessNet but there
  858.     //        is currently no activity.
  859.     //    If we're not busy, then there's no need to interrupt.
  860.     if(IsContextStoppable() == FALSE)    {
  861.         //    Clear the idle interrupt if already set.
  862.         m_bIdleInterrupt = FALSE;
  863.     }
  864.     //    Reentrant safe version.
  865.     else if(winfeInProcessNet == FALSE)    {
  866.         winfeInProcessNet = TRUE;
  867.         XP_InterruptContext(GetContext());
  868.         winfeInProcessNet = FALSE;
  869.  
  870.         //    Set the flag that we need no idle interrupt.
  871.         //    This is to avoid cases where we have set to idle interrupt, and get
  872.         //        called again where we actually do interrupt.
  873.         m_bIdleInterrupt = FALSE;
  874.     }
  875.     else    {
  876.         //  Request some idle processing.
  877.         FEU_RequestIdleProcessing(GetContext());
  878.         m_bIdleInterrupt = TRUE;
  879.     }
  880.  
  881.     //    Decrement the level of nestedness.
  882.     m_iInterruptNest--;
  883.  
  884.     //    Check to see if we're supposed to delete this thing.
  885.     //    Idle interrupt will be true if unable to do anything, and will need
  886.     //        idle time so we don't destroy it then.
  887.     //    m_bDestroyed will be true, requesting the deletion.
  888.     //    m_iInterruptNest will be 0, indicating that we are at the bottom
  889.     //        most level of interrupt call.
  890.     if(m_bDestroyed == TRUE &&
  891.         m_bIdleInterrupt == FALSE &&
  892.         m_iInterruptNest == 0)    {
  893.  
  894.         //    Delete.
  895.         delete this;
  896.     }
  897.  
  898.     return;
  899. }
  900.  
  901. BOOL CAbstractCX::IsContextStoppableRecurse() {
  902.    MWContext *pChild;
  903.  
  904.    if (!GetContext())
  905.        return FALSE;
  906.    if ((m_bImagesLoading  || m_bImagesLooping) && !m_bImagesDelayed)
  907.        return TRUE;
  908.  
  909.    if ((m_bMochaImagesLoading || m_bMochaImagesLooping) && !m_bMochaImagesDelayed)
  910.        return TRUE;
  911.  
  912.    XP_List *pTraverse = GetContext()->grid_children;
  913.    while (pChild = (MWContext *)XP_ListNextObject(pTraverse)) {
  914.        if (ABSTRACTCX(pChild)->IsContextStoppableRecurse())
  915.             return TRUE;
  916.    }   
  917.    
  918.    return FALSE;
  919. }
  920.  
  921. // A wrapper around XP_IsContextStoppable.  This is necessary
  922. // because a context is stoppable if its image context is
  923. // stoppable, and the image context is owned by the Front End.
  924. BOOL CAbstractCX::IsContextStoppable() {
  925.     return (IsContextStoppableRecurse() ||
  926.             XP_IsContextStoppable(GetContext()));
  927. }
  928.  
  929. void CAbstractCX::MailDocument()    {
  930. #ifdef MOZ_MAIL_NEWS
  931.     if(CanMailDocument())    {
  932. #ifdef EDITOR
  933.     if (EDT_IS_EDITOR(GetContext())) {
  934.       // Don't need to force saving document, EDT_MailDocument
  935.       // will do the right thing.
  936.       EDT_MailDocument(GetContext());
  937.     }
  938.     else {
  939.       MSG_MailDocumentURL(GetContext(),NULL);
  940.     }
  941. #endif
  942.     }
  943. #endif /* MOZ_MAIL_NEWS */
  944. }
  945.  
  946. BOOL CAbstractCX::CanMailDocument()    {
  947.     BOOL bRetval = TRUE;
  948.    
  949. #ifdef MOZ_MAIL_NEWS
  950.     if (!theApp.m_hPostalLib)
  951.       return(FALSE);
  952. #endif // MOZ_MAIL_NEWS
  953.  
  954.     if(IsDestroyed())    {
  955.         bRetval = FALSE;
  956.     }
  957.     else if(CanCreateUrlFromHist() == FALSE)    {
  958.         bRetval = FALSE;
  959.     }
  960.     else if(IsGridParent())    {
  961.         bRetval = FALSE;
  962.     }
  963.  
  964.     return(bRetval);
  965. }
  966.  
  967. void CAbstractCX::OpenUrl()    {
  968.     //    If we've a parent context, let them deal with this.
  969.     if( GetParentContext() )    {
  970.         ABSTRACTCX(GetParentContext())->OpenUrl();
  971.     } else if( !IsDestroyed() )    {
  972.         ASSERT( GetDialogOwner() );
  973.         //    Have the frame bring up the open url dialog.
  974.         if( GetDialogOwner() ) {
  975.             CDialogURL urlDlg(GetDialogOwner(), GetContext());
  976.             urlDlg.DoModal();
  977.         }
  978.     }
  979. }
  980.  
  981. BOOL CAbstractCX::CanOpenUrl()    {
  982.     //    If we've a parent context, let them deal with this.
  983.     if(GetParentContext())    {
  984.         return(ABSTRACTCX(GetParentContext())->CanOpenUrl());
  985.     } else if(IsDestroyed())    {
  986.         return(FALSE);
  987.     } else {
  988.         //    Perhaps not if we're in some kiosk mode.
  989.         return( GetDialogOwner() ? TRUE : FALSE);
  990.     }
  991. }
  992.  
  993. void CAbstractCX::NewWindow()    {
  994.     //    Create a new window.
  995.     if(CanNewWindow())    {
  996.         CFE_CreateNewDocWindow(GetContext(), NULL);
  997.     }
  998. }
  999.  
  1000. BOOL CAbstractCX::CanNewWindow()    {
  1001.     //    Can always get a new window (well....)
  1002.     BOOL bRetval = TRUE;
  1003.     if(IsDestroyed() == TRUE)    {
  1004.         bRetval = FALSE;
  1005.     }
  1006.     else    {
  1007.         // Limit windows only for win16
  1008. #ifdef XP_WIN16
  1009.         //    Limit to 8 top level browser contexts.
  1010.         //  We may have Edit windows open and we run into
  1011.         //   the limit of four real quick!
  1012.         if(XP_ContextCount(MWContextBrowser, TRUE) >= 8)    {
  1013.             bRetval = FALSE;
  1014.         }
  1015. #endif
  1016.     }
  1017.  
  1018.     return(bRetval);
  1019. }
  1020.  
  1021. static void UpdateUI(CAbstractCX *pCX)
  1022. {
  1023.     if(pCX->IsFrameContext() == TRUE)    {
  1024.         CWinCX *pWinCX = WINCX(pCX->GetContext());
  1025.         CFrameGlue *pFrame = pWinCX->GetFrame();
  1026.         // We need to make sure the toolbar buttons are correctly updated. 
  1027.         // Most importantly, the stop button needs to be updated
  1028.         if(pFrame){
  1029.             CFrameWnd*    pFrameWnd = pFrame->GetFrameWnd();
  1030.  
  1031.             if (pFrameWnd)
  1032.                 pFrameWnd->SendMessageToDescendants(WM_IDLEUPDATECMDUI, (WPARAM)TRUE, (LPARAM)0);
  1033.         }
  1034.     }
  1035. }
  1036.  
  1037. void CAbstractCX::AllBack()    {
  1038.     //    Pass up to the parent for the ALL effect.
  1039.     if(GetParentContext())    {
  1040.         ABSTRACTCX(GetParentContext())->AllBack();
  1041.     }
  1042.     else if(IsDestroyed() == FALSE)    {
  1043.         Back();
  1044.         UpdateUI(this);
  1045.     }
  1046. }
  1047.  
  1048. BOOL CAbstractCX::CanAllBack()    {
  1049.     //    Ask the parent for the ALL effect.
  1050.     if(GetParentContext())    {
  1051.         return(ABSTRACTCX(GetParentContext())->CanAllBack());
  1052.     }
  1053.  
  1054.     BOOL bRetval = TRUE;
  1055.     if(IsDestroyed())    {
  1056.         bRetval = FALSE;
  1057.     }
  1058.     else    {
  1059.         //    Ask the session history.
  1060.         bRetval = SHIST_CanGoBack((GetContext()));
  1061.     }
  1062.  
  1063.     return(bRetval);
  1064. }
  1065.  
  1066. void CAbstractCX::AllForward()    {
  1067.     //    Pass up to the parent for the ALL effect.
  1068.     if(GetParentContext())    {
  1069.         ABSTRACTCX(GetParentContext())->AllForward();
  1070.     }
  1071.     else if(IsDestroyed() == FALSE)    {
  1072.         Forward();
  1073.         UpdateUI(this);
  1074.     }
  1075. }
  1076.  
  1077. BOOL CAbstractCX::CanAllForward()    {
  1078.     //    Ask the parent for the ALL effect.
  1079.     if(GetParentContext())    {
  1080.         return(ABSTRACTCX(GetParentContext())->CanAllForward());
  1081.     }
  1082.  
  1083.     BOOL bRetval = TRUE;
  1084.     if(IsDestroyed())    {
  1085.         bRetval = FALSE;
  1086.     }
  1087.     else    {
  1088.         //    Ask the session history.
  1089.         bRetval = SHIST_CanGoForward((GetContext()));
  1090.     }
  1091.  
  1092.     return(bRetval);
  1093. }
  1094.  
  1095. void CAbstractCX::AllInterrupt()    {
  1096.     //    Pass up to the parent for the ALL effect.
  1097.     if(GetParentContext())    {
  1098.         ABSTRACTCX(GetParentContext())->AllInterrupt();
  1099.     }
  1100.     else if(IsDestroyed() == FALSE)    {
  1101.         Interrupt();
  1102.     }
  1103. }
  1104.  
  1105. BOOL CAbstractCX::CanAllInterrupt()    {
  1106.     //    Ask the parent for the ALL effect.
  1107.     if(GetParentContext())    {
  1108.         return(ABSTRACTCX(GetParentContext())->CanAllInterrupt());
  1109.     }
  1110.  
  1111.     BOOL bRetval = TRUE;
  1112.     if(IsDestroyed())    {
  1113.         bRetval = FALSE;
  1114.     }
  1115.     else    {
  1116.         //    See if the context is busy.
  1117.         bRetval = IsContextStoppable();
  1118.     }
  1119.  
  1120.     return(bRetval);
  1121. }
  1122.  
  1123. void CAbstractCX::AllReload(NET_ReloadMethod iReloadType)    {
  1124.     //    Pass up to the parent for the ALL effect.
  1125.     if(GetParentContext())    {
  1126.         ABSTRACTCX(GetParentContext())->AllReload(iReloadType);
  1127.     }
  1128.     else if(IsDestroyed() == FALSE)    {
  1129.         Reload(iReloadType);
  1130.     }
  1131. }
  1132.  
  1133. BOOL CAbstractCX::CanAllReload()    {
  1134.     //    Ask the parent for the ALL effect.
  1135.     if(GetParentContext())    {
  1136.         return(ABSTRACTCX(GetParentContext())->CanAllReload());
  1137.     }
  1138.  
  1139.     BOOL bRetval = TRUE;
  1140.     if(IsDestroyed())    {
  1141.         bRetval = FALSE;
  1142.     }
  1143.     else    {
  1144.         //    See if the context can be reloaded (has history).
  1145.         History_entry *pHist = SHIST_GetCurrent(&(GetContext()->hist));
  1146.         if(pHist == NULL)    {
  1147.             bRetval = FALSE;
  1148.         }
  1149.     }
  1150.  
  1151.     return(bRetval);
  1152. }
  1153.  
  1154. BOOL CAbstractCX::CanAddToBookmarks()
  1155. {
  1156.     if( GetParentContext() )    {
  1157.         return(ABSTRACTCX(GetParentContext())->CanAddToBookmarks());
  1158.     }
  1159.  
  1160.     if( IsDestroyed() )    {
  1161.         return(FALSE);
  1162.     }
  1163.  
  1164.     //    Can only do this if we have something currently loaded.
  1165.     if( !CanCreateUrlFromHist() )    {
  1166.         return(FALSE);
  1167.     }
  1168.  
  1169.     return(TRUE);
  1170. }
  1171.  
  1172. void CAbstractCX::AddToBookmarks()
  1173. {
  1174.     if( GetParentContext() )    {
  1175.         ABSTRACTCX(GetParentContext())->AddToBookmarks();
  1176.         return;
  1177.     }
  1178.  
  1179.     if( !CanAddToBookmarks() )    {
  1180.         return;
  1181.     }
  1182.  
  1183.     History_entry *pHistEnt = SHIST_GetCurrent( &(GetContext()->hist) );
  1184.     ASSERT(pHistEnt);
  1185.  
  1186.     HT_AddBookmark( pHistEnt->address, GetContext()->title );
  1187. }
  1188.  
  1189. void CAbstractCX::CopySelection()    {
  1190.     if(CanCopySelection() == FALSE)    {
  1191.         return;
  1192.     }
  1193.  
  1194.     HANDLE h;
  1195.     HANDLE hData;
  1196.     char * string;
  1197.     char * text;
  1198.  
  1199.     text = (char *)LO_GetSelectionText(GetDocumentContext());
  1200.     if(!text)    {
  1201.         //    Layout is reporting a selection, but we can't get it.
  1202.         ASSERT(0);
  1203.         return;
  1204.     }
  1205.  
  1206.     if(!::OpenClipboard(NULL)) {
  1207.         FE_Alert(GetContext(), szLoadString(IDS_OPEN_CLIPBOARD));
  1208.         return;
  1209.     }
  1210.  
  1211.     if(!::EmptyClipboard()) {
  1212.         FE_Alert(GetContext(), szLoadString(IDS_EMPTY_CLIPBOARD));
  1213.         return;
  1214.     }
  1215.       
  1216.     int len = XP_STRLEN(text) + 1;
  1217.  
  1218.     hData = GlobalAlloc(GMEM_MOVEABLE, (DWORD) len);
  1219.     string = (char *) GlobalLock(hData);
  1220.     strncpy(string, text, len);
  1221.     string[len - 1] = '\0';
  1222.     GlobalUnlock(hData);
  1223.  
  1224.     h = ::SetClipboardData(CF_TEXT, hData); 
  1225.  
  1226. #ifdef XP_WIN32
  1227.     int datacsid = GetWinCsid() & ~CS_AUTO;
  1228.     if((CS_USER_DEFINED_ENCODING != datacsid) && (0 != datacsid))
  1229.     {
  1230.         len = CASTINT((INTL_StrToUnicodeLen(datacsid, (unsigned char*)text)+1) * 2);
  1231.         hData = GlobalAlloc(GMEM_MOVEABLE, (DWORD) len);
  1232.         string = (char *) GlobalLock(hData);
  1233.         INTL_StrToUnicode(datacsid, (unsigned char*)text, (INTL_Unicode*)string, len);
  1234.  
  1235.         GlobalUnlock(hData);        
  1236.     }
  1237.     h = ::SetClipboardData(CF_UNICODETEXT, hData); 
  1238.  
  1239. #endif
  1240.  
  1241.     ::CloseClipboard();
  1242.     XP_FREE(text);
  1243. }
  1244.  
  1245. BOOL CAbstractCX::CanCopySelection()    {
  1246.     BOOL bRetval;
  1247.     History_entry *pHist = SHIST_GetCurrent(&(GetContext()->hist));
  1248.     if(IsDestroyed())    {
  1249.         bRetval = FALSE;
  1250.     }
  1251.     else if(pHist == NULL)    {
  1252.             bRetval = FALSE;
  1253.     }
  1254.     else    {
  1255.         //    Is there anything selected to be copied?
  1256.         bRetval = LO_HaveSelection(GetDocumentContext());
  1257.     }
  1258.  
  1259.     return(bRetval);
  1260. }
  1261.  
  1262. //    Look up a context via ID.
  1263. //    Used mainly by DDE and external application context lookup (out of process).
  1264. //    Returns NULL on failure.
  1265. //    To get the context ID, call FE_GetContextID or CAbstractCX::GetContextID
  1266. CAbstractCX *CAbstractCX::FindContextByID(DWORD dwID)
  1267. {
  1268.     MWContext *pTraverseContext = NULL;
  1269.     CAbstractCX *pTraverseCX = NULL;
  1270.  
  1271.     XP_List * thelist = XP_GetGlobalContextList();
  1272.     while (pTraverseContext = (MWContext *)XP_ListNextObject(thelist))  {
  1273.         if(pTraverseContext != NULL && ABSTRACTCX(pTraverseContext) != NULL)    {
  1274.             pTraverseCX = ABSTRACTCX(pTraverseContext);
  1275.  
  1276.             if(pTraverseCX->GetContextID() == dwID)    {
  1277.                 break;
  1278.             }
  1279.             pTraverseCX = NULL;
  1280.         }
  1281.     }
  1282.  
  1283.     return(pTraverseCX);
  1284. }
  1285.  
  1286. //    Create a url struct from the history, with appropriate checking
  1287. //        for NULL and such, so that we don't have this code scattered
  1288. //        throughout the client.
  1289. //    bClearStateData is a flag set to erase any data that can't be
  1290. //        tossed around without upsetting the client (form data).
  1291. //    It's off by default, so be careful out there.
  1292. URL_Struct *CAbstractCX::CreateUrlFromHist(BOOL bClearStateData, SHIST_SavedData *pSavedData, BOOL bWysiwyg)
  1293. {
  1294.     TRACE("Creating URL from the current history entry.\n");
  1295.  
  1296.     //    Make sure that we're not destroyed.
  1297.     if(IsDestroyed())    {
  1298.         return(NULL);
  1299.     }
  1300.  
  1301.     //    Do we have a history entry from which to create
  1302.     //        the url?
  1303.     History_entry *pHistoryEntry = SHIST_GetCurrent(&(GetContext()->hist));
  1304.     if(pHistoryEntry == NULL || pHistoryEntry->address == NULL)    {
  1305.         return(NULL);
  1306.     }
  1307.  
  1308.     URL_Struct *pUrl = NULL;
  1309.     if(!bWysiwyg)   {
  1310.         pUrl = SHIST_CreateURLStructFromHistoryEntry(GetContext(), pHistoryEntry);
  1311.     }
  1312.     else    {
  1313.         pUrl = SHIST_CreateWysiwygURLStruct(GetContext(), pHistoryEntry);
  1314.     }
  1315.  
  1316.     if(pUrl == NULL)    {
  1317.         return(NULL);
  1318.     }
  1319.     
  1320.     if(bClearStateData != FALSE)    {
  1321.         TRACE("Clearing URL state data.\n");
  1322.  
  1323.         //  We may be wanting to copy the form data beyond the scope of this function.
  1324.         //  Make sure layout saves the current state.
  1325.         LO_SaveFormData(GetDocumentContext());
  1326.  
  1327.         //  Are we to copy the session history to the parameter passed in (used in
  1328.         //      subsequent call to copy the form data)?
  1329.         if(pSavedData)  {
  1330.             memcpy(pSavedData, (void *)&(pUrl->savedData), sizeof(SHIST_SavedData));
  1331.         }
  1332.  
  1333.         //    If this structure changes in the future to hold data which can be carried
  1334.         //        across contexts, then we lose.
  1335.         memset((void *)&(pUrl->savedData), 0, sizeof(SHIST_SavedData));
  1336.     }
  1337.  
  1338.     return(pUrl);
  1339. }
  1340.  
  1341. //    Used mainly in cmdui enablers to determine if we could load from 
  1342. //        the current history entry.
  1343. BOOL CAbstractCX::CanCreateUrlFromHist()
  1344. {
  1345.     //    Make sure that we're not destroyed.
  1346.     if(IsDestroyed())    {
  1347.         return(FALSE);
  1348.     }
  1349.  
  1350.     //    Do we have a history entry from which to create
  1351.     //        the url?
  1352.     History_entry *pHistoryEntry = SHIST_GetCurrent(&(GetContext()->hist));
  1353.     if(pHistoryEntry == NULL || pHistoryEntry->address == NULL)    {
  1354.         return(FALSE);
  1355.     }
  1356.  
  1357.     //    Looks safe.
  1358.     return(TRUE);
  1359. }
  1360.  
  1361. void CAbstractCX::ResetStopwatch()
  1362. {
  1363.         m_ttStopwatch = theApp.GetTime();
  1364.         m_ttOldwatch = m_ttStopwatch - 1;
  1365. }
  1366.  
  1367.  
  1368.