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