sgallery.cpp

Go to the documentation of this file.
00001 // $Id: sgallery.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // SGallery.h - the SuperGallery class
00099 
00100 #include "camtypes.h"
00101 
00102 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00103 #include "camelot.h"
00104 #include "dragmsg.h"
00105 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "galstr.h"
00107 //#include "galres.h"
00108 //#include "jason.h"
00109 #include "keypress.h"
00110 #include "camframe.h"
00111 #include "progress.h"
00112 //#include "resource.h" // For _R(IDS_OK) (dammit!)
00113 //#include "sgallery.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00114 #include "sgdrag.h"
00115 #include "sgmenu.h"
00116 //#include "sgtree.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 #include "thumbmsg.h"
00118 //#include "sglinepr.h"
00119 
00120 #include "ccdc.h"       // For render-into-dialogue support
00121 #include "dlgcol.h"
00122 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "grnddib.h"
00124 
00125 #include "sgindgen.h"   // For ReplaceCharacters function (which should be in stringbase)
00126 #include "sglib.h"      // For Searching stuff, which will be removed shortly
00127 //#include "sglbase.h"  // For searching stuff
00128 //#include "sglcart.h"  // For searching stuff
00129 //#include "sglfills.h" // For searching stuff
00130 
00131 //#include "richard3.h" // Few extra text resources
00132 
00133 #include "brushmsg.h"   // for the screen change message
00134 
00135 // Implement the dynamic class bits...
00136 CC_IMPLEMENT_DYNCREATE(SuperGallery, DialogOp)
00137 CC_IMPLEMENT_DYNCREATE(SGalleryOptionsDlg, DialogOp)
00138 CC_IMPLEMENT_DYNCREATE(SGallerySortDlg, DialogOp)
00139 CC_IMPLEMENT_DYNCREATE(SGallerySearchDlg, DialogOp)
00140 
00141 // OpParam class for opening the options and search dlgs - local to this .cpp file
00142 class GalDlgParam : public OpParam
00143 {
00144 CC_DECLARE_MEMDUMP(GalDlgParam)
00145 public:
00146     GalDlgParam(SuperGallery *Parent) : OpParam(0, 0) { ParentGal = Parent; };
00147     SuperGallery *ParentGal;
00148 };
00149 
00150 CC_IMPLEMENT_MEMDUMP(GalDlgParam, OpParam)
00151 
00152 
00153 
00154 
00155 // This line mustn't go before any CC_IMPLEMENT_... macros
00156 #define new CAM_DEBUG_NEW
00157 
00158 
00159 // Static variables
00160 SuperGallery *SuperGallery::CurrentSortGallery = NULL;  // Points at the gallery doing the current sort
00161                                                         // Used inside the qsort comparator function
00162 
00163 
00164 // Preferences
00165 INT32 SuperGallery::UseFixedColourSet = FALSE;          // Use Fixed colour set (or read 
00166                                                         // redraw colours from Windows settings)
00167 
00168 
00169 #define MyIdlePriority (IDLEPRIORITY_LOW)
00170 
00171 
00172 /********************************************************************************************
00173 
00174 >   void SuperGallery::InitData(void)
00175                                                  
00176     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00177     Created:    10/4/95
00178 
00179     Purpose:    Internal method to initialise data mambers. Shared code for constructors.
00180 
00181 ********************************************************************************************/
00182 
00183 void SuperGallery::InitData(void)
00184 {
00185     GallerySize         = wxSize(0,0);
00186 
00187     DisplayTree         = NULL;
00188     DisplayMode         = 0;
00189 
00190     FormatIsCached      = FALSE;
00191 
00192     LastWindowDX = LastWindowDY = 0;
00193 
00194     AmShaded            = FALSE;
00195     AmRedrawing         = FALSE;
00196 
00197     LastSelectedNode    = NULL;
00198 
00199     CurrentOptionsDlg           = NULL;
00200     CurrentSortDlg              = NULL;
00201     CurrentSearchDlg            = NULL;
00202     CurrentLinePropertiesDlg    = NULL;
00203 
00204     DblClickPending     = FALSE;        // We aren't in the middle of a double click
00205 
00206     PendingRedraws      = 0;
00207     LastBGNode          = NULL;
00208 
00209     for (INT32 i = 0; i < MaxSGSortKeys; i++)
00210     {
00211         SortKeys[i].SortKey  = 0;
00212         SortKeys[i].Reversed = FALSE;
00213     }
00214 }
00215 
00216 
00217 
00218 /********************************************************************************************
00219 
00220 >   SuperGallery::SuperGallery(CCRuntimeClass *Class = CC_RUNTIME_CLASS(DialogOp)): DialogOp(_R(IDD_BLANKBAR), MODELESS,0,GSAFECLASS(Class))
00221                                                  
00222     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00223     Created:    21/10/94
00224     Purpose:    SuperGallery constructor (Identical to DialogOp)
00225 
00226 ********************************************************************************************/
00227 
00228 SuperGallery::SuperGallery(CCRuntimeClass *Class): DialogOp(_R(IDD_BLANKBAR), MODELESS,0,GSAFECLASS(Class)) 
00229 {
00230     String_32 str = String_32(_R(IDS_K_BARS_NONAME));
00231     Name=str;
00232     InitData();
00233 } 
00234 
00235 
00236 
00237 /********************************************************************************************
00238 
00239 >   SuperGallery::SuperGallery(String_32 &NewName,CCRuntimeClass *Class = CC_RUNTIME_CLASS(DialogOp): 
00240     DialogOp(NewName, Class) 
00241 
00242     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00243     Created:    21/10/94
00244     Purpose:    SuperGallery constructor (Identical to DialogOp)
00245 
00246 ********************************************************************************************/
00247 
00248 SuperGallery::SuperGallery(String_32 &NewName,CCRuntimeClass *Class)
00249         : DialogOp(_R(IDD_BLANKBAR), MODELESS,0,GSAFECLASS(Class))
00250 {
00251     String_32 str = String_32(_R(IDS_K_BARS_NONAME));
00252     Name=str;
00253     InitData();
00254 } 
00255 
00256 
00257 
00258 /********************************************************************************************
00259 
00260 >   SuperGallery::~SuperGallery()
00261 
00262     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00263     Created:    21/10/94
00264     Purpose:    SuperGallery destructor.
00265 
00266 ********************************************************************************************/
00267 
00268 SuperGallery::~SuperGallery()
00269 {
00270     if (DisplayTree != NULL)
00271     {
00272         DisplayTree->DestroySubtree();  // Destroy the tree, destructing all nodes except root
00273         delete DisplayTree;             // And delete the root as well
00274         DisplayTree = NULL;
00275     }
00276 
00277     CloseOwnedDialogs();
00278 
00279     // Remove any idle event processor we had registered for BG redraws
00280     GetApplication()->RemoveIdleProcessor(MyIdlePriority, this);
00281 }
00282 
00283 
00284 
00285 /********************************************************************************************
00286 
00287 >   void SuperGallery::FillInMiscInfo(SGMiscInfo *MiscInfo,
00288                                         ReDrawInfoType *DlgRedrawInfo = NULL)
00289 
00290     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00291     Created:    19/1/95
00292 
00293     Inputs:     DlgRedrawInfo - If you happen to have one of these lying around, pass
00294                 it in to save me having to find this out again.
00295 
00296     Outputs:    MiscInfo  - will be filled in, ready to be passed to SG event handlers
00297 
00298     Purpose:    Sets up a MiscInfo structure, ready for use.
00299 
00300     Scope:      private (Internal shared code for SuperGallery)
00301 
00302 ********************************************************************************************/
00303 
00304 void SuperGallery::FillInMiscInfo(SGMiscInfo *MiscInfo, ReDrawInfoType *DlgRedrawInfo)
00305 {
00306     // If the RedrawInfo was not passed in for us, go and get it for ourselves
00307     ReDrawInfoType TempDlgRedrawInfo;
00308     if (DlgRedrawInfo == NULL)
00309     {
00310         DlgRedrawInfo = &TempDlgRedrawInfo;
00311         GetKernelRenderedGadgetInfo(GetListGadgetID(), DlgRedrawInfo);
00312     }
00313 
00314     // Fill in the MiscInfo
00315     MiscInfo->DisplayMode   = DisplayMode;
00316     MiscInfo->PixelSize     = 72000 / DlgRedrawInfo->Dpi;
00317     MiscInfo->MaxWidth      = DlgRedrawInfo->dx;        // Window/virtualsize width
00318     MiscInfo->WindowHeight  = DlgRedrawInfo->dy;        // Window height
00319 }
00320 
00321 
00322 
00323 /********************************************************************************************
00324 
00325 >   void SuperGallery::BroadcastEvent(SGEventType EventType, void *EventInfo,
00326                                         SGMiscInfo *MiscInfo = NULL)
00327 
00328     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00329     Created:    19/1/95
00330 
00331     Inputs:     EventType - the type of the event to broadcast
00332                 EventInfo - the information to pass in 'EventInfo' to all event handlers
00333                             (FormatInfo/RedrawInfo/MouseInfo, etc, depending upon EventType)
00334                 MiscInfo  - the MiscInfo to pass to the event handlers. If this is passed in
00335                             as NULL, a MiscInfo structure will be set up automatically and
00336                             passed in (as MiscInfo must *always* be supplied)
00337 
00338     Purpose:    Passes the given event through the DisplayTree.
00339 
00340     SeeAlso:    SGDisplayNode::HandleEvent
00341 
00342 ********************************************************************************************/
00343 
00344 void SuperGallery::BroadcastEvent(SGEventType EventType, void *EventInfo,
00345                                     SGMiscInfo *MiscInfo)
00346 {
00347     if (DisplayTree == NULL)
00348         return;
00349 
00350     SGMiscInfo TheMiscInfo;
00351 
00352     if (MiscInfo == NULL && IsVisible())
00353     {
00354         FillInMiscInfo(&TheMiscInfo);
00355         MiscInfo = &TheMiscInfo;
00356     }
00357 
00358     ERROR3IF(MiscInfo == NULL && (EventType != SGEVENT_THUMBMSG && EventType != SGEVENT_BGFLUSH), 
00359             "Attempt to broadcast an event when the gallery is closed could be dangerous. Tell Jason");
00360 
00361     DisplayTree->HandleEvent(EventType, EventInfo, MiscInfo);
00362 }
00363 
00364 
00365 
00366 /********************************************************************************************
00367 
00368 >   virtual MsgResult SuperGallery::Message(Msg* Message)
00369 
00370     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00371     Created:    21/10/94
00372     Inputs:     Message - The message to handle
00373 
00374     Purpose:    A standard message handler, really. If you override this in a derived
00375                 class, you must pass any unhandled event on to this base class method
00376                 after handling the messages you are interested in.
00377 
00378     SeeAlso:    DialogOp::Message
00379 
00380 ********************************************************************************************/
00381 
00382 MsgResult SuperGallery::Message(Msg* Message)
00383 {
00384     if (MESSAGE_IS_A(Message,DeathMsg))     // We must destroy the dialog if the application is dying
00385     {
00386         // Destroy the entire DisplayList (which should be empty by now),
00387         // just to be on the safe side, in case a derived gallery forgot to do it
00388         if (DisplayTree != NULL)
00389         {
00390             DisplayTree->DestroySubtree();  // Destroy the display tree, destructing all nodes
00391             delete DisplayTree;
00392             DisplayTree = NULL;
00393         }
00394 
00395         // Ensure that all doc/view pointers for this Op are NULL to stop
00396         // 'FlushRedraw' access violations occurring.
00397         pOurDoc = NULL;
00398         pOurView = NULL;
00399 
00400         End();
00401         return(OK);
00402     }
00403 
00404         
00405     if ( Message->IsKindOf(CC_RUNTIME_CLASS(DialogMsg)) &&
00406             ((DialogMsg*)Message)->DlgMsg == DIM_BAR_DEATH )
00407     {
00408         DialogOp::Message(Message);
00409         return(OK);
00410     }
00411 
00412     if (IS_OUR_DIALOG_MSG(Message))
00413     {
00414         DialogMsg* Msg = (DialogMsg*)Message;
00415 
00416         BOOL WasRightButton = FALSE;        // What type of click was it (if any)
00417                                         // (allows code-sharing in the case statement)
00418 
00419         switch (Msg->DlgMsg)
00420         {
00421             case DIM_CREATE:
00422                 {
00423                     String_32 name(CamResource::GetObjectName(DlgResID));
00424                     SetGalName(name);
00425                 }
00426                 break;
00427 
00428             case DIM_CANCEL:            // We're closing - close our owned dlgs
00429                 CloseOwnedDialogs();
00430 
00431                 // Ensure all items pending background redraws are flushed
00432                 FlushBackgroundRedraws();
00433                 
00434                 // tell everyone the screen will be changing
00435                 TRACEUSER( "Diccon", _T("Gallery closing\n"));
00436                 BROADCAST_TO_ALL(ScreenChangeMsg());
00437                 break;
00438 
00439             case DIM_MOUSEWHEEL_UP:
00440                 {
00441                     //MouseWheel Scrolled Upwards...
00442                     TRACEUSER( "Matt", _T("SuperGallery::Message() Received MouseWheel UPWARDS Message!\n"));
00443 
00444                     ReDrawInfoType DlgRedrawInfo;
00445                     GetKernelRenderedGadgetInfo(GetListGadgetID(), &DlgRedrawInfo);
00446 
00447                     // Make a SGMiscInfo with, well, MiscInfo in it...
00448                     SGMiscInfo MiscInfo;
00449                     FillInMiscInfo(&MiscInfo, &DlgRedrawInfo);
00450 
00451                     //Get the old scroll offset, adjust it accordingly and set it to be the current one...
00452                     INT32 newScrollOffset = DisplayTree->GetScrollOffset() - (750 * 30);
00453                     DisplayTree->SetScrollOffset(newScrollOffset, &MiscInfo);
00454                 }
00455                 break;
00456 
00457             case DIM_MOUSEWHEEL_DOWN:
00458                 {
00459                     //MouseWheel Scrolled Downwards...
00460                     TRACEUSER( "Matt", _T("SuperGallery::Message() Received MouseWheel DOWNWARDS Message!\n"));
00461 
00462                     ReDrawInfoType DlgRedrawInfo;
00463                     GetKernelRenderedGadgetInfo(GetListGadgetID(), &DlgRedrawInfo);
00464 
00465                     // Make a SGMiscInfo with, well, MiscInfo in it...
00466                     SGMiscInfo MiscInfo;
00467                     FillInMiscInfo(&MiscInfo, &DlgRedrawInfo);
00468 
00469                     //Get the old scroll offset, adjust it accordingly and set it to be the current one...
00470                     INT32 newScrollOffset = DisplayTree->GetScrollOffset() + (750 * 30);
00471                     DisplayTree->SetScrollOffset(newScrollOffset, &MiscInfo);
00472                 }
00473                 break;
00474 
00475             case DIM_RGT_BN_DOWN:
00476                 WasRightButton = TRUE;
00477                 // (Note: We treat a right click like a left click now. DIM_RGT_BN_UP is used
00478                 // to pop up the menu when the button is released)
00479 
00480                 // Drop through to LFT_BN_DOWN handler...
00481 
00482             case DIM_LFT_BN_DOWN:
00483                 if ((Msg->GadgetID == GetListGadgetID()) && Msg->DlgMsgParam)
00484                 {
00485                     // Get our kernel-rendered-dlg info, and calculate our virtual coord space
00486                     ReDrawInfoType *DlgRedrawInfo = (ReDrawInfoType*) Msg->DlgMsgParam;
00487 
00488                     // Determine where the mouse was clicked, within the virtual coord space
00489                     SGMouseInfo ClickInfo;
00490 
00491                     // Was it a ctrl-click? (Adjust/right clicks now pop up the menu)
00492                     ClickInfo.Adjust = KeyPress::IsGalleryCtrlPressed();
00493 
00494                     // Was it a click to extend the selection? (shift-click)
00495                     ClickInfo.Extend = KeyPress::IsGalleryShiftPressed();
00496 
00497                     // Was it a pop-up-menu (right button) click?
00498                     ClickInfo.MenuClick = WasRightButton;
00499 
00500                     // Is it the second installment in a double-click?
00501                     ClickInfo.DoubleClick = FALSE;
00502                     if (DblClickPending && !WasRightButton)
00503                     {
00504                         // Double-click Distance (millipoints). If the second click is more than this
00505                         // distance away from the forst click point, it is not regarded as a dble click.
00506                         const INT32 DblClickDist = 12000;       // **** !!!! Read dbl-click-dist preference
00507                         INT32 ClickDistX = ABS(LastClickPos.x - DlgRedrawInfo->pMousePos->x);
00508                         INT32 ClickDistY = ABS(LastClickPos.y - DlgRedrawInfo->pMousePos->y);
00509                         
00510                         if (ClickDistX <= DblClickDist && ClickDistY <= DblClickDist)
00511                         {
00512                             const INT32 DblClickTime = 400;     // **** !!!! Read OS dbl-click time!
00513 
00514                             if (!LastClickTime.Elapsed(DblClickTime))
00515                                 ClickInfo.DoubleClick= TRUE;
00516                         }
00517                     }
00518                     LastClickPos = *(DlgRedrawInfo->pMousePos); // Remember last click position
00519 
00520                     if (ClickInfo.DoubleClick)
00521                         DblClickPending = FALSE;    // No longer pending double click
00522                     else
00523                     {
00524                         DblClickPending = TRUE;     // Double click is now pending
00525                         LastClickTime.Sample();     // Start the "double-click timeout" timer
00526                     }
00527 
00528                     ClickInfo.Position = *(DlgRedrawInfo->pMousePos);
00529                     ConvertToVirtualCoords(DlgRedrawInfo, &ClickInfo.Position);
00530 
00531                     // And request that the tree decides what to do with the event
00532                     BroadcastEvent(SGEVENT_MOUSECLICK, &ClickInfo);
00533                 }
00534                 break;
00535 
00536 
00537             case DIM_RGT_BN_UP:
00538                 {
00539                     // Give the gallery a chance to do something before popping up the context menu
00540                     // At present, used by the bitmap gallery to ensure that the plug-ins have all
00541                     // been parsed.
00542                     PreContextMenu();
00543                     // Right button has been released - pop up a context-sensitive menu
00544                     GalleryContextMenu *TheMenu = new GalleryContextMenu(SGMENU_OVERITEM, this);
00545                     if (TheMenu != NULL)
00546                         TheMenu->Show();
00547                 }
00548                 break;
00549 
00550 
00551             case DIM_LFT_BN_CLICKED:
00552             {
00553                 if (Msg->GadgetID == _R(IDC_GALLERY_NEW))
00554                 {
00555                     ApplyAction(SGACTION_CREATE);
00556                 }
00557                 else if (Msg->GadgetID == _R(IDC_GALLERY_APPLY))
00558                 {
00559                     // NB. changed to use Control key here, to be consistent with the
00560                     // way Adjust works when clicking on items.
00561                     if (KeyPress::IsGalleryCtrlPressed())
00562                     {
00563                         // If the gallery doesn't respond to Adjust-click then try a plain
00564                         // click instead.
00565                         if (!ApplyAction(SGACTION_APPLYADJUST)) ApplyAction(SGACTION_APPLY);
00566                     }
00567                     else
00568                     {
00569                         ApplyAction(SGACTION_APPLY);
00570                     }
00571                 }
00572                 else if (Msg->GadgetID == _R(IDC_GALLERY_REDEFINE))
00573                 {
00574                     ApplyAction(SGACTION_REDEFINE);
00575                 }
00576                 else if (Msg->GadgetID == _R(IDC_GALLERY_EDIT))
00577                 {
00578                     ApplyAction(SGACTION_EDIT);
00579                 }
00580                 else if (Msg->GadgetID == _R(IDC_GALLERY_DELETE))
00581                 {
00582                     ApplyAction(SGACTION_DELETE);
00583                 }
00584                 else if (Msg->GadgetID == _R(IDC_GALLERY_MENU))
00585                 {
00586                     // Pop up the options menu/dialogue
00587 //                  SGalleryOptionsDlg::InvokeDialog(this);
00588                     GalleryContextMenu *TheMenu = new GalleryContextMenu(SGMENU_OPTIONS, this);
00589                     if (TheMenu != NULL)
00590                         TheMenu->Show();
00591                 }
00592                 break;
00593             }
00594             case DIM_RGT_BN_CLICKED:
00595                 if (Msg->GadgetID == _R(IDC_GALLERY_APPLY))
00596                 {
00597                     if (!ApplyAction(SGACTION_APPLYADJUST))
00598                         ApplyAction(SGACTION_APPLY);
00599                 }
00600                 break;
00601 
00602 
00603             case DIM_REDRAW:
00604                 if (Msg->GadgetID == _R(IDC_GALLERY_LISTBOX))       // Render the list box
00605                 {
00606                     RenderListBox((ReDrawInfoType*) Msg->DlgMsgParam);
00607                 }
00608                 break;
00609             
00610             default:
00611                 break;
00612         }
00613     }
00614     else if (MESSAGE_IS_A(Message, DocChangingMsg))
00615     {
00616         DocChangingMsg *Msg = (DocChangingMsg *) Message;
00617         switch (Msg->State)
00618         {
00619             case DocChangingMsg::TITLECHANGED:
00620                 if (DisplayTree != NULL && IsVisible())
00621                 {
00622                     // If we have any 'categories' which represent this document,
00623                     // ask them to redraw themselves to update their titles.
00624                     SGDisplayNode *Category =
00625                         DisplayTree->FindSubtree(this, Msg->pChangingDoc, NULL);
00626 
00627                     if (Category != NULL)
00628                         Category->ForceRedrawOfMyself();
00629                 }
00630                 break;
00631 
00632 
00633             case DocChangingMsg::ABOUTTODIE:        // Document dying - remove from tree
00634                 if (DisplayTree != NULL)
00635                 {
00636                     // If the gallery has a subtree for this document, we'll scrap it for 'em
00637                     SGDisplayNode *Ptr = DisplayTree->FindSubtree(this, Msg->pChangingDoc, NULL);
00638                     if (Ptr != NULL)
00639                     {
00640                         Ptr->DestroySubtree();
00641                         ForceRedrawOfList();
00642                     }
00643                 }
00644                 break;
00645 
00646 
00647             case DocChangingMsg::SELCHANGED:
00648                 if (Msg->pNewDoc == NULL)
00649                 {
00650                     // There is no selected doc - this can only mean there are no docs
00651                     // at all, so we had better shade the gallery
00652                     ShadeGallery(TRUE);
00653                 }
00654                 break;
00655 
00656             default:
00657                 break;
00658         }
00659     }
00660 
00661     else if (MESSAGE_IS_A(Message, DragMessage) && IsVisible() && DisplayTree != NULL)
00662     {
00663         // If a drag starting message comes around, pass it on to the tree
00664         DragMessage *Msg = (DragMessage *) Message;
00665         if (Msg->State == DragMessage::DRAGSTARTED)
00666         {
00667             BroadcastEvent(SGEVENT_DRAGSTARTED, (SGEventInfo *) Msg);
00668 
00669             // And then call our virtual function to add a drag target (if appropriate)
00670             // for the entire gallery listbox.
00671             HandleDragStart(Msg);
00672         }
00673     }
00674 
00675     else if (MESSAGE_IS_A(Message, ThumbMessage) && DisplayTree != NULL)
00676     {
00677         // If a library Thumb message comes around, pass it on to the tree
00678         // (do this even if the gallery is closed, as libraries may cache stuff even when closed)
00679         BroadcastEvent(SGEVENT_THUMBMSG, (SGEventInfo *) Message);
00680     }
00681     
00682     // Pass the call down to the base class
00683     return(DialogOp::Message(Message));
00684 
00685     return OK;
00686 }    
00687 
00688 
00689 
00690 /********************************************************************************************
00691 
00692 >   BOOL SuperGallery::Create(void)
00693 
00694     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00695     Created:    21/10/94
00696     Returns:    TRUE if the window was successfully created
00697                 FALSE => ERROR2
00698     Purpose:    The SuperGallery Create method
00699                 This method has been overridden to de-specialize the DialogOp. 
00700 
00701     Notes:      Before doing anything else, the PreCreate handler is called.
00702                 Secondly, the InitMenuCommands() method is called to init any
00703                 required gallery menu items.
00704                 Then, the gallery window is created and initialised
00705                 The last thing done is to invoke the PostCreate method
00706                 (these upcalls should be overridden by derived classes to do stuff)
00707 
00708                 This finally calls SelectionHasChanged() to ensure the buttons etc
00709                 are updated appropriately to the selection state.
00710 
00711 ********************************************************************************************/
00712 
00713 BOOL SuperGallery::Create(void)
00714 {
00715     if (!DialogOp::Create())
00716         return(FALSE);
00717 
00718     // Call derived class PreCreate handler (to create display tree, usually)
00719     if (!PreCreate())
00720         return(FALSE);
00721 
00722     // Call the derived class Menu creation handler, to create any needed menu items
00723     if (!InitMenuCommands())
00724         return(FALSE);
00725 
00726     // Ensure any items pending background-redraws are 'flushed'
00727     FlushBackgroundRedraws();
00728 
00729 #ifndef EXCLUDE_FROM_XARALX
00730 PORTNOTE("galleries", "Removed docking stuff")
00731     // Bar initialisation and creation
00732     SetDockBarType(Dock);
00733     SetSlot(Slot);
00734     SetOffset(Offset);
00735     SetFloatingCPoint(FloatPos);
00736 #endif
00737 
00738 //  if (!DialogOp::Create())
00739 //      return(FALSE);
00740 
00741     AmShaded = FALSE;
00742 
00743     // Call derived class PostCreate handler
00744     if (!PostCreate())
00745         return(FALSE);
00746 
00747     SelectionHasChanged();      // Ensure we update appropriately for the selection state
00748 
00749     return(TRUE);
00750 }
00751 
00752 
00753 
00754 /********************************************************************************************
00755 
00756 >   virtual void SuperGallery::SetVisibility(BOOL Open)
00757 
00758     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00759     Created:    22/1/96
00760     Inputs:     Open -  if TRUE then open SuperGallery in its last pos if it is
00761                         currently closed.
00762                         if FALSE, it is closed
00763 
00764     Purpose:    Used by the tool bar customize system to open and close a tool bar.
00765 
00766                 SuperGallery overrides this virtual function so that it can be aware
00767                 of when its window is closed/hidden, so that it may remove its owned
00768                 dialogues (sort/search/properties).
00769 
00770                 It always calls the base class in order to show/hide the gallery
00771 
00772                 NOTE THAT THIS CAN DELETE THE OBJECT CONCERNED!
00773 
00774 ********************************************************************************************/
00775 
00776 void SuperGallery::SetVisibility(BOOL Open)
00777 {
00778     if (!Open)
00779     {
00780         // If we're being hidden, make sure that any owned dialogues are closed
00781         CloseOwnedDialogs();
00782     }   
00783 
00784     // Now call the base class to show/hide ourselves
00785     DialogOp::SetVisibility(Open);
00786     if (!Open)
00787         End(); // Return quick, this deletes the super gallery
00788 }
00789 
00790 
00791 /********************************************************************************************
00792 
00793 >   virtual void SuperGallery::CloseOwnedDialogs(void)
00794 
00795     Author:     Richard_Millican (Xara Group Ltd) <camelotdev@xara.com>
00796     Created:    05/03/97
00797 
00798     Purpose:    Checks and closes the various dialogs which can be owned by galleries.
00799 
00800     SeeAlso:    SuperGallery::SetVisibility, SuperGallery::~SuperGallery()
00801                 SuperGallery::Message(Msg* Message)
00802 
00803 ********************************************************************************************/
00804 
00805 void SuperGallery::CloseOwnedDialogs(void)
00806 {
00807     if (CurrentOptionsDlg != NULL)
00808     {
00809         CurrentOptionsDlg->Close();
00810         CurrentOptionsDlg->End();
00811     }
00812 
00813     if (CurrentSortDlg != NULL)
00814     {
00815         CurrentSortDlg->Close();
00816         CurrentSortDlg->End();
00817     }
00818 
00819     if (CurrentSearchDlg != NULL)
00820     {
00821         CurrentSearchDlg->Close();
00822         CurrentSearchDlg->End();
00823     }
00824 
00825 PORTNOTE("dialogs", "Removed CurrentLinePropertiesDlg from SuperGallery::CloseOwnedDialogs(void)")
00826 #ifndef EXCLUDE_FROM_XARALX
00827     if (CurrentLinePropertiesDlg != NULL)
00828     {
00829         CurrentLinePropertiesDlg->Close();
00830         CurrentLinePropertiesDlg->End();
00831     }
00832 #endif
00833 }
00834 
00835 /********************************************************************************************
00836 
00837 >   virtual BOOL SuperGallery::PreCreate(void)
00838 
00839     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00840     Created:    24/10/94
00841     Returns:    TRUE if the gallery was successfully initialised
00842 
00843     Purpose:    A call to be overridden by the derived class.
00844                 This is called BEFORE the SuperGallery::Create function tries to create
00845                 the gallery window.
00846                 Derived galleries then initialise any unintialised data, and return
00847                 TRUE if it is safe to continue creating the gallery window.
00848 
00849     Notes:      Generally speaking, most initialisation code should go into the post create
00850                 handler method. Override this method with care.
00851 
00852     SeeAlso:    SuperGallery::PostCreate
00853 
00854 ********************************************************************************************/
00855 
00856 BOOL SuperGallery::PreCreate(void)
00857 {
00858     return(TRUE);
00859 }
00860 
00861 
00862 
00863 /********************************************************************************************
00864 
00865 >   virtual BOOL SuperGallery::PostCreate(void)
00866 
00867     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00868     Created:    24/10/94
00869     Returns:    TRUE if the gallery was successfully initialised
00870     Purpose:    A call to be overridden by the derived class.
00871                 This is called AFTER the SuperGallery::Create function has succeeded.
00872                 Derived galleries can then initialise any unintialised data, and return
00873                 TRUE if it is safe to open the gallery window.
00874 
00875     SeeAlso:    SuperGallery::PreCreate
00876 
00877 ********************************************************************************************/
00878 
00879 BOOL SuperGallery::PostCreate(void)
00880 {
00881     return(TRUE);
00882 }
00883 
00884 
00885 
00886 /********************************************************************************************
00887 
00888 >   void SuperGallery::ShadeGallery(BOOL ShadeIt)
00889 
00890     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00891     Created:    18/1/95
00892 
00893     Inputs:     ShadeIt - TRUE to shade, FALSE to un-shade, the gallery
00894 
00895     Purpose:    Shades (disables) the SuperGallery window.
00896                 This calls the DoShadeGallery upcall to allow derived classes to take
00897                 special action for any extra controls they may own, etc.
00898 
00899                 If un-shading the gallery, it also calls SelectionHasChanged method to
00900                 ensure that the buttons are in an appropriate state for the selection.
00901 
00902     Notes:      If the gallery is already in the requested state, or if it is closed
00903                 (not visible on screen) then nothing happens (other than that the shaded
00904                 flag is updated to reflect the desired state)
00905 
00906     SeeAlso:    SuperGallery::DoShadeGallery; SuperGallery::SelectionHasChanged
00907 
00908 ********************************************************************************************/
00909 
00910 void SuperGallery::ShadeGallery(BOOL ShadeIt)
00911 {
00912     if (AmShaded != ShadeIt && IsVisible())
00913     {
00914         EnableGadget(_R(IDC_GALLERY_APPLY),     !ShadeIt);
00915         EnableGadget(_R(IDC_GALLERY_NEW),       !ShadeIt);
00916         EnableGadget(_R(IDC_GALLERY_DELETE),    !ShadeIt);
00917         EnableGadget(_R(IDC_GALLERY_REDEFINE),  !ShadeIt);
00918         EnableGadget(_R(IDC_GALLERY_EDIT),      !ShadeIt);
00919 //      EnableGadget(_R(IDC_GALLERY_UNDO),      !ShadeIt);
00920         EnableGadget(_R(IDC_GALLERY_MENU),      !ShadeIt);
00921         EnableGadget(_R(IDC_GALLERY_NAME),      !ShadeIt);
00922 
00923         DoShadeGallery(ShadeIt);
00924     }
00925 
00926     AmShaded = ShadeIt;
00927 
00928     if (!AmShaded)                  // If unshading, ensure the buttons are updated
00929         SelectionHasChanged();      // to reflect the new selection state
00930 }
00931 
00932 
00933 
00934 /********************************************************************************************
00935 
00936 >   virtual void SuperGallery::DoShadeGallery(BOOL ShadeIt);
00937 
00938     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00939     Created:    18/1/95
00940 
00941     Inputs:     ShadeIt - TRUE to shade, FALSE to un-shade, the gallery
00942 
00943     Purpose:    Shades (disables) the SuperGallery window.
00944                 This calls the DoShadeGallery upcall to allow derived classes to take
00945                 special action for any extra controls they may own, etc.
00946 
00947     Notes:      This base class method does nothing - it is expected to be overridden if
00948                 derived classes need to do anything when shading state changes
00949 
00950     SeeAlso:    SuperGallery::DoShadeGallery
00951 
00952 ********************************************************************************************/
00953 
00954 void SuperGallery::DoShadeGallery(BOOL ShadeIt)
00955 {
00956     // The base class does nothing
00957 }
00958 
00959 
00960 
00961 /********************************************************************************************
00962 
00963 >   virtual void SuperGallery::HandleDragStart(DragMessage *DragMsg)
00964 
00965     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00966     Created:    14/3/95
00967 
00968     Inputs:     DragMsg - The DRAGSTARTED message that we've just recieved, indicating
00969                 the type of drag which is just starting.
00970 
00971     Purpose:    Checks a DragMessage to see if it is a gallery list-drag. If so, it
00972                 adds a new drag target to handle drops on the gallery list box.
00973 
00974     Notes:      This method should be overridden by derived galleries to:
00975                 a) Stop the gallery from allowing recieving of these drags, or
00976                 b) Add handlers for specific drag types you're interested in - e.g.
00977                 the colour gallery will use less generic colour drags to handle
00978                 gallery reorganisation, so that you can also drag colours out of the
00979                 gallery.
00980 
00981 ********************************************************************************************/
00982 
00983 void SuperGallery::HandleDragStart(DragMessage *DragMsg)
00984 {
00985     // If this is a gallery list-reorganising drag which originated from this gallery,
00986     // then create a target for the gallery listbox.
00987     if (DragMsg->pInfo->IsKindOf(CC_RUNTIME_CLASS(SGListDragInfo)) &&
00988         ((SGListDragInfo *)DragMsg->pInfo)->GetParentGallery() == this)
00989     {
00990         // Note this sort of auto-attaches it seems - AMB
00991         /*SGListDragTarget *NewTarget = */new SGListDragTarget(this, GetListGadgetID());
00992     }
00993 }
00994 
00995 
00996 
00997 /********************************************************************************************
00998 
00999 >   virtual BOOL SuperGallery::ApplyAction(SGActionType Action)
01000 
01001     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01002     Created:    18/1/95
01003 
01004     Inputs:     Action - Indicates what action to apply
01005 
01006     Returns     FALSE (Derived classes will return TRUE to indicate successful handling
01007                 of the action, or FALSE to indicate failure)
01008 
01009     Purpose:    Applies certain conventional gallery actions (usually associated with
01010                 gallery buttons, for new, edit, delete, etc)
01011 
01012     Notes:      This base-class method should be overridden by derived classes. It
01013                 does nothing by default, and returns FALSE.
01014 
01015     SeeAlso:    SGActionType
01016 
01017 ********************************************************************************************/
01018 
01019 BOOL SuperGallery::ApplyAction(SGActionType Action)
01020 {
01021     return(FALSE);
01022 }
01023 
01024 
01025 
01026 /********************************************************************************************
01027 
01028 >   static INT32 __cdecl SuperGallery::SortComparator(const void *Item1, const void *Item2)
01029 
01030     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01031     Created:    10/4/95
01032 
01033     Inputs:     Item1, Item2 - the display nodes to be compared
01034 
01035     Returns:    a negative, zero, or positive result of comparing the items with the
01036                 current gallery multi-key sort mode.
01037 
01038     Purpose:    'qsort' comparator function, used when quicksorting the display list
01039 
01040     Notes:      Relies on the static var. 'CurrentSortGallery' to contain a pointer to
01041                 the gallery which requested this sort.
01042 
01043     SeeAlso:    SuperGallery::ApplySortNow
01044 
01045 ********************************************************************************************/
01046 
01047 INT32 __cdecl SuperGallery::SortComparator(const void *Item1, const void *Item2)
01048 {
01049     SGDisplayNode *Node1 = *((SGDisplayNode **)Item1);
01050     SGDisplayNode *Node2 = *((SGDisplayNode **)Item2);
01051 
01052     INT32 Result = Node1->CompareTo(Node2, CurrentSortGallery->SortKeys[0].SortKey);
01053     if (CurrentSortGallery->SortKeys[0].Reversed)
01054         Result = -Result;
01055 
01056     if (Result == 0)
01057     {
01058         Result = Node1->CompareTo(Node2, CurrentSortGallery->SortKeys[1].SortKey);
01059         if (CurrentSortGallery->SortKeys[1].Reversed)
01060             Result = -Result;
01061     }
01062 
01063     return(Result);
01064 }
01065 
01066 
01067 
01068 /********************************************************************************************
01069 
01070 >   virtual void SuperGallery::ApplySortNow(BOOL ApplyToEntireList)
01071 
01072     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01073     Created:    10/4/95
01074 
01075     Inputs:     ApplyToEntireList - TRUE to sort the entire DisplayList,
01076                 FALSE to sort only groups which contain a selection
01077 
01078     Purpose:    Applies the current gallery sort mode (member array SortKeys) to the
01079                 display list.
01080 
01081     SeeAlso:    SuperGallery::SortComparator; ::qsort
01082 
01083 ********************************************************************************************/
01084 
01085 void SuperGallery::ApplySortNow(BOOL ApplyToEntireList)
01086 {
01087     if (SortKeys[0].SortKey == 0 || DisplayTree == NULL)
01088         return;
01089     
01090     CurrentSortGallery = this;
01091 
01092     SGDisplayNode *CurrentGroup = DisplayTree->GetChild();
01093     if (CurrentGroup == NULL)   // Nothing to sort
01094         return;
01095 
01096     SGDisplayNode *Ptr = CurrentGroup;
01097 
01098     // Pre-run progress indicator
01099     String_64 ProgMsg(_R(IDS_GALLERY_PREPARE_FOR_SORT));
01100     BeginSlowJob(-1, FALSE, &ProgMsg);
01101 
01102     // For library galleries we need to set the Quiet button status ready to un-supress errors
01103     SetQuietStatus(FALSE);
01104 
01105     // Count the number of available items to sort
01106     BOOL HasSelection = FALSE;
01107     INT32 NumItemsToSort = 0;
01108     while (Ptr != NULL)
01109     {
01110         if(ApplyToEntireList || ((SGDisplayGroup *)Ptr)->IsSelected())
01111             if(((SGDisplayGroup *)Ptr)->IsVirtualised())
01112                 ((SGDisplayGroup *)Ptr)->DeVirtualise();
01113 
01114         if (ApplyToEntireList || ((SGDisplayGroup *)Ptr)->FindNextSelectedItem(NULL) != NULL)
01115         {
01116             SGDisplayNode *Item = Ptr->GetChild();  // Count number of items to sort in this group
01117             INT32 ItemsInThisGroup = 0;
01118             while (Item != NULL)
01119             {
01120                 ItemsInThisGroup++;
01121                 if (Item->Flags.Selected)
01122                     HasSelection = TRUE;
01123                 Item = Item->GetNext();
01124             }
01125 
01126             if (ItemsInThisGroup > 1 && (ApplyToEntireList || HasSelection))
01127                 NumItemsToSort += ItemsInThisGroup;
01128         }
01129         Ptr = Ptr->GetNext();
01130     }
01131 
01132     EndSlowJob();
01133 
01134     // If there is no point in trying to sort, abort now
01135     if (NumItemsToSort < 2)
01136         return;
01137 
01138     // Start progress indicators, with a percentage based upon the number of items.
01139     // We will update twice for each group (after qsort and shuffle-items stages)
01140     String_64 Description(_R(IDS_SGOPTS_SORTING));
01141     BeginSlowJob(NumItemsToSort * 2, FALSE, &Description);
01142     NumItemsToSort = 0;
01143 
01144     INT32 NumItems;
01145     INT32 i;
01146     BOOL GroupHasChanged = FALSE;
01147 
01148     while (CurrentGroup != NULL)
01149     {
01150         // Don't sort virtualised-out groups ! (they should have all been devirtualised before)
01151         if(!((SGDisplayGroup *)CurrentGroup)->IsVirtualised())
01152         {
01153             HasSelection = FALSE;
01154             Ptr = CurrentGroup->GetChild();
01155             ERROR3IF(Ptr != NULL && !Ptr->IsKindOf(CC_RUNTIME_CLASS(SGDisplayItem)),
01156                         "Sort hasn't found items! Heinous failure imminent!" );
01157             // Count the number of items we have to sort
01158             NumItems = 0;
01159             while (Ptr != NULL)
01160             {
01161                 NumItems++;
01162                 if (Ptr->Flags.Selected)
01163                     HasSelection = TRUE;
01164                 Ptr = Ptr->GetNext();
01165             }
01166 
01167             // If there are 2 or more items, and we are either applying to all groups, or this
01168             // group contains selected item(s), then we will sort it..
01169             if (NumItems > 1 && (ApplyToEntireList || HasSelection))
01170             {
01171                 // Get memory for an array of pointers to these items
01172                 SGDisplayNode **SortArray = (SGDisplayNode **)CCMalloc(NumItems * sizeof(SGDisplayNode *));
01173                 if (SortArray == NULL)
01174                 {
01175                     CurrentSortGallery = NULL;
01176                     InvalidateCachedFormat();
01177                     EndSlowJob();
01178                     InformError();
01179                     return;
01180                 }
01181 
01182                 // Fill in the array with pointers to display items to sort
01183                 i = 0;
01184                 Ptr = CurrentGroup->GetChild();
01185                 while (Ptr != NULL)
01186                 {
01187                     SortArray[i++] = Ptr;
01188                     Ptr = Ptr->GetNext();
01189                 }
01190 
01191                 // Sort the array of pointers
01192                 qsort(SortArray, NumItems, sizeof(SGDisplayNode *), SuperGallery::SortComparator);
01193 
01194                 NumItemsToSort += NumItems;
01195                 if (!ContinueSlowJob(NumItemsToSort)) // Update percentage complete for the number of items processed
01196                 {
01197                     // User has cancelled by pressing escape
01198                     CCFree(SortArray);
01199                     break;
01200                 }
01201 
01202 
01203                 GroupHasChanged = FALSE;
01204 
01205                 // Now, take the sorted array, and rearrange the display items to be in that order      
01206                 // Special case the first item
01207                 if (SortArray[0]->GetPrevious() != NULL)
01208                 {
01209                     SortArray[1]->MoveBefore(SortArray[0]);
01210                     GroupHasChanged =