1 /********************************************************************************
2 *                                                                               *
3 *                         D o c u m e n t   O b j e c t                         *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1998,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXDocument.cpp 3297 2015-12-14 20:30:04Z arthurcnorman $                      *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxkeys.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXPath.h"
36 #include "FXSettings.h"
37 #include "FXRegistry.h"
38 #include "FXAccelTable.h"
39 #include "FXObjectList.h"
40 #include "FXApp.h"
41 #include "FXCursor.h"
42 #include "FXFrame.h"
43 #include "FXRootWindow.h"
44 #include "FXShell.h"
45 #include "FXDocument.h"
46 
47 
48 /*
49   Notes:
50 
51   - How to use:
52 
53     1) You construct a FXDocument class, e.g. when your app loads a file.
54 
55     2) FXDocument constructs one or more FXMDIChild widgets, and makes itself the target
56        of the each of them so that it will be notified when the FXMDIChild minimizes,
57        maximizes, or gets closed etc.
58 
59     3) MenuCommands, Buttons and what have you which need to send messages to FXDocument
60        will do so through delegation via FXMDIClient, and FXMDIChild.
61 
62        Thus, the only places pointing to a specific FXDocument are FXMDIChild windows,
63        and their sub-widgets (such as for example the FXGLViewer).
64 
65     4) When the user interacts with one of the FXMDIChild's controls, data in the
66        FXDocument is changed.  If any other FXMDIChild windows are used this same
67        data, they may need to be updated.
68 
69        FXDocument can do this through message ``broadcast'' from the FXMDIClient
70        to its list FXMDIChild windows:
71 
72 
73        mdiclient->forallWindows(sender,sel,ptr)
74 
75 
76        sends a message to ALL FXMDIChild windows under mdiclient. Also:
77 
78 
79        mdiclient->forallDocWindows(document,sender,sel,ptr)
80 
81        sends a message to all FXMDIChild windows whose target is document.
82 
83        A new message, understood by ALL FXWindows, has been added if you want to
84        simply force a repaint; so in order to just repaint everything:
85 
86         long MyDocument::onCmdChangedSomething(FXObject* sender, FXSelector sel,void* ptr){
87           forallWindows(sender,FXSEL(SEL_COMMAND,ID_UPDATE),ptr);
88           return 1;
89           }
90 
91 
92     5) Thus,
93 
94          - There is only ONE place that keeps track of all the FXMDIChild windows
95            pertaining to a certain document.
96 
97            Your application may want to cycle through the FXMDIChild list itself;
98            this can be done by:
99 
100              mdichild = mdiclient->getMDIChildFirst();
101 
102              mdichild = mdichild->getMDINext();
103 
104              and so on.
105 
106            The FXMDIChild windows are linked into a doubly-linked list.
107 
108          - After a change, FXMDIChild window contents may be updated by a simple
109            message broadcast to all FXMDIChild windows; in many cases, the
110            original FXMDIChild with which the user interacted should be skipped.
111            This can be accomplished by simply passing the same sender which
112            sent the change to the FXDocument back to the broadcast message,
113            so if a message is received by the FXMDIChild it could simply test
114            if it itself was the originator.
115 
116          - Applications which don't ``buy into'' this whole multi-document business
117            but still want to have multiple viewer windows won't have to
118            bother with FXDocuments at all!
119 
120            Just create FXMDIChild widgets and make them send the messages to the
121            right place...
122 
123 
124     6) FXMainWindow and FXMDIChild can ask their target to supply the title to be
125        displayed in the titlebar; this is done through GUI Updating.
126 
127     7) New FXMDIChildren should be created by FXDocument; when an FXMDIChild is closed,
128        the FXDocument should be asked first; if its the last window, FXDocument
129        should prompt to save the data if modified. After data has been saved, the
130        FXDocument returns 1 in the SEL_CLOSE handler which causes the FXMDIChild
131        to delete itself.
132 
133     8) A message ID_CLOSE_DOCUMENT to FXDocument (via FXMDIClient and FXMDIChild) checks
134        if document needs to be saved; once saved, the document can delete all child
135        windows.  It could do this via:
136 
137          mdiclient->forallDocWindows(this,this,FXSEL(SEL_COMMAND,FXWindow::ID_DELETE),NULL);
138 
139        forAllfirst sends a SEL_CLOSEALL
140        to each document; if this returns 1, FXMDIClient
141        proceeds to send ID_MDI_CLOSE to each FXMDIChild belonging to the same document.
142        Each FXMDIChild will then ask the FXDocument whether its OK to close this
143        FXMDIChild; since the FXDocument was already saved in response to the SEL_CLOSEALL,
144        the FXDocument is no longer dirty and the answer will be OK to close for all of
145        them [except perhaps in unusual circumstances].
146 
147 
148 */
149 
150 using namespace FX;
151 
152 /*******************************************************************************/
153 
154 namespace FX {
155 
156 
157 // Map
158 FXDEFMAP(FXDocument) FXDocumentMap[]={
159   FXMAPFUNC(SEL_UPDATE,FXDocument::ID_TITLE,FXDocument::onUpdTitle),
160   FXMAPFUNC(SEL_UPDATE,FXDocument::ID_FILENAME,FXDocument::onUpdFilename),
161   };
162 
163 
164 // Object implementation
FXIMPLEMENT(FXDocument,FXObject,FXDocumentMap,ARRAYNUMBER (FXDocumentMap))165 FXIMPLEMENT(FXDocument,FXObject,FXDocumentMap,ARRAYNUMBER(FXDocumentMap))
166 
167 
168 // Construct
169 FXDocument::FXDocument(){
170   modified=FALSE;
171   }
172 
173 
174 // Change title
setTitle(const FXString & name)175 void FXDocument::setTitle(const FXString& name){
176   title=name;
177   }
178 
179 
180 // Set file name, and the title also
setFilename(const FXString & path)181 void FXDocument::setFilename(const FXString& path){
182   filename=FXPath::absolute(path);
183   title=FXPath::title(filename);
184   }
185 
186 
187 // Update document title
onUpdTitle(FXObject * sender,FXSelector,void *)188 long FXDocument::onUpdTitle(FXObject* sender,FXSelector,void*){
189   FXString string=title;
190   if(modified) string+="*";
191   sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETSTRINGVALUE),(void*)&string);
192   return 1;
193   }
194 
195 
196 // Update document filename
onUpdFilename(FXObject * sender,FXSelector,void *)197 long FXDocument::onUpdFilename(FXObject* sender,FXSelector,void*){
198   FXString string=filename;
199   if(modified) string+="*";
200   sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETSTRINGVALUE),(void*)&string);
201   return 1;
202   }
203 
204 
205 // Save object to stream
save(FXStream & store) const206 void FXDocument::save(FXStream& store) const {
207   FXObject::save(store);
208   }
209 
210 
211 // Load object from stream
load(FXStream & store)212 void FXDocument::load(FXStream& store){
213   FXObject::load(store);
214   }
215 
216 
217 // Destruct
~FXDocument()218 FXDocument::~FXDocument(){
219   }
220 
221 }
222