]> git.saurik.com Git - wxWidgets.git/blob - contrib/samples/ogl/studio/doc.cpp
reversed change
[wxWidgets.git] / contrib / samples / ogl / studio / doc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: doc.cpp
3 // Purpose: Implements document functionality
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 12/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 // #pragma implementation
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <wx/wx.h>
25 #endif
26
27 #include "studio.h"
28 #include "doc.h"
29 #include "view.h"
30 #include <wx/ogl/basicp.h>
31
32 IMPLEMENT_DYNAMIC_CLASS(csDiagramDocument, wxDocument)
33
34 #ifdef _MSC_VER
35 #pragma warning(disable:4355)
36 #endif
37
38 csDiagramDocument::csDiagramDocument():m_diagram(this)
39 {
40 }
41
42 #ifdef _MSC_VER
43 #pragma warning(default:4355)
44 #endif
45
46 csDiagramDocument::~csDiagramDocument()
47 {
48 }
49
50 bool csDiagramDocument::OnCloseDocument()
51 {
52 m_diagram.DeleteAllShapes();
53 return TRUE;
54 }
55
56 bool csDiagramDocument::OnSaveDocument(const wxString& file)
57 {
58 if (file == wxEmptyString)
59 return FALSE;
60
61 if (!m_diagram.SaveFile(file))
62 {
63 wxString msgTitle;
64 if (wxTheApp->GetAppName() != wxEmptyString)
65 msgTitle = wxTheApp->GetAppName();
66 else
67 msgTitle = wxString(_T("File error"));
68
69 (void)wxMessageBox(_T("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION,
70 GetDocumentWindow());
71 return FALSE;
72 }
73
74 Modify(FALSE);
75 SetFilename(file);
76 return TRUE;
77 }
78
79 bool csDiagramDocument::OnOpenDocument(const wxString& file)
80 {
81 if (!OnSaveModified())
82 return FALSE;
83
84 wxString msgTitle;
85 if (wxTheApp->GetAppName() != wxEmptyString)
86 msgTitle = wxTheApp->GetAppName();
87 else
88 msgTitle = wxString(_T("File error"));
89
90 m_diagram.DeleteAllShapes();
91 if (!m_diagram.LoadFile(file))
92 {
93 (void)wxMessageBox(_T("Sorry, could not open this file."), msgTitle, wxOK|wxICON_EXCLAMATION,
94 GetDocumentWindow());
95 return FALSE;
96 }
97 SetFilename(file, TRUE);
98 Modify(FALSE);
99 UpdateAllViews();
100
101 return TRUE;
102 }
103
104
105 /*
106 * Implementation of drawing command
107 */
108
109 csDiagramCommand::csDiagramCommand(const wxString& name, csDiagramDocument *doc,
110 csCommandState* onlyState):
111 wxCommand(TRUE, name)
112 {
113 m_doc = doc;
114
115 if (onlyState)
116 {
117 AddState(onlyState);
118 }
119 }
120
121 csDiagramCommand::~csDiagramCommand()
122 {
123 wxNode* node = m_states.GetFirst();
124 while (node)
125 {
126 csCommandState* state = (csCommandState*) node->GetData();
127 delete state;
128 node = node->GetNext();
129 }
130 }
131
132 void csDiagramCommand::AddState(csCommandState* state)
133 {
134 state->m_doc = m_doc;
135 // state->m_cmd = m_cmd;
136 m_states.Append(state);
137 }
138
139 // Insert a state at the beginning of the list
140 void csDiagramCommand::InsertState(csCommandState* state)
141 {
142 state->m_doc = m_doc;
143 // state->m_cmd = m_cmd;
144 m_states.Insert(state);
145 }
146
147 // Schedule all lines connected to the states to be cut.
148 void csDiagramCommand::RemoveLines()
149 {
150 wxNode* node = m_states.GetFirst();
151 while (node)
152 {
153 csCommandState* state = (csCommandState*) node->GetData();
154 wxShape* shape = state->GetShapeOnCanvas();
155 wxASSERT( (shape != NULL) );
156
157 wxNode *node1 = shape->GetLines().GetFirst();
158 while (node1)
159 {
160 wxLineShape *line = (wxLineShape *)node1->GetData();
161 if (!FindStateByShape(line))
162 {
163 csCommandState* newState = new csCommandState(ID_CS_CUT, NULL, line);
164 InsertState(newState);
165 }
166
167 node1 = node1->GetNext();
168 }
169 node = node->GetNext();
170 }
171 }
172
173 csCommandState* csDiagramCommand::FindStateByShape(wxShape* shape)
174 {
175 wxNode* node = m_states.GetFirst();
176 while (node)
177 {
178 csCommandState* state = (csCommandState*) node->GetData();
179 if (shape == state->GetShapeOnCanvas() || shape == state->GetSavedState())
180 return state;
181 node = node->GetNext();
182 }
183 return NULL;
184 }
185
186 bool csDiagramCommand::Do()
187 {
188 wxNode* node = m_states.GetFirst();
189 while (node)
190 {
191 csCommandState* state = (csCommandState*) node->GetData();
192 if (!state->Do())
193 return FALSE;
194 node = node->GetNext();
195 }
196 return TRUE;
197 }
198
199 bool csDiagramCommand::Undo()
200 {
201 // Undo in reverse order, so e.g. shapes get added
202 // back before the lines do.
203 wxNode* node = m_states.GetLast();
204 while (node)
205 {
206 csCommandState* state = (csCommandState*) node->GetData();
207 if (!state->Undo())
208 return FALSE;
209 node = node->GetPrevious();
210 }
211 return TRUE;
212 }
213
214 csCommandState::csCommandState(int cmd, wxShape* savedState, wxShape* shapeOnCanvas)
215 {
216 m_cmd = cmd;
217 m_doc = NULL;
218 m_savedState = savedState;
219 m_shapeOnCanvas = shapeOnCanvas;
220 m_linePositionFrom = 0;
221 m_linePositionTo = 0;
222 }
223
224 csCommandState::~csCommandState()
225 {
226 if (m_savedState)
227 {
228 m_savedState->SetCanvas(NULL);
229 delete m_savedState;
230 }
231 }
232
233 bool csCommandState::Do()
234 {
235 switch (m_cmd)
236 {
237 case ID_CS_CUT:
238 {
239 // New state is 'nothing' - maybe pass shape ID to state so we know what
240 // we're talking about.
241 // Then save old shape in m_savedState (actually swap pointers)
242
243 wxASSERT( (m_shapeOnCanvas != NULL) );
244 wxASSERT( (m_savedState == NULL) ); // new state will be 'nothing'
245 wxASSERT( (m_doc != NULL) );
246
247 wxShapeCanvas* canvas = m_shapeOnCanvas->GetCanvas();
248
249 // In case this is a line
250 wxShape* lineFrom = NULL;
251 wxShape* lineTo = NULL;
252 int attachmentFrom = 0, attachmentTo = 0;
253
254 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
255 {
256 // Store the from/to info to save in the line shape
257 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
258 lineFrom = lineShape->GetFrom();
259 lineTo = lineShape->GetTo();
260 attachmentFrom = lineShape->GetAttachmentFrom();
261 attachmentTo = lineShape->GetAttachmentTo();
262
263 m_linePositionFrom = lineFrom->GetLinePosition(lineShape);
264 m_linePositionTo = lineTo->GetLinePosition(lineShape);
265 }
266
267 m_shapeOnCanvas->Select(FALSE);
268 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
269
270 m_shapeOnCanvas->Unlink();
271
272 m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
273
274 m_savedState = m_shapeOnCanvas;
275
276 if (m_savedState->IsKindOf(CLASSINFO(wxLineShape)))
277 {
278 // Restore the from/to info for future reference
279 wxLineShape* lineShape = (wxLineShape*) m_savedState;
280 lineShape->SetFrom(lineFrom);
281 lineShape->SetTo(lineTo);
282 lineShape->SetAttachments(attachmentFrom, attachmentTo);
283
284 wxClientDC dc(canvas);
285 canvas->PrepareDC(dc);
286
287 lineFrom->MoveLinks(dc);
288 lineTo->MoveLinks(dc);
289 }
290
291 m_doc->Modify(TRUE);
292 m_doc->UpdateAllViews();
293 break;
294 }
295 case ID_CS_ADD_SHAPE:
296 case ID_CS_ADD_SHAPE_SELECT:
297 {
298 // The app has given the command state a new m_savedState
299 // shape, which is the new shape to add to the canvas (but
300 // not actually added until this point).
301 // The new 'saved state' is therefore 'nothing' since there
302 // was nothing there before.
303
304 wxASSERT( (m_shapeOnCanvas == NULL) );
305 wxASSERT( (m_savedState != NULL) );
306 wxASSERT( (m_doc != NULL) );
307
308 m_shapeOnCanvas = m_savedState;
309 m_savedState = NULL;
310
311 m_doc->GetDiagram()->AddShape(m_shapeOnCanvas);
312 m_shapeOnCanvas->Show(TRUE);
313
314 wxClientDC dc(m_shapeOnCanvas->GetCanvas());
315 m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
316
317 csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
318 m_shapeOnCanvas->FormatText(dc, handler->m_label);
319
320 m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
321
322 if (m_cmd == ID_CS_ADD_SHAPE_SELECT)
323 {
324 m_shapeOnCanvas->Select(TRUE, &dc);
325 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
326 }
327
328 m_doc->Modify(TRUE);
329 m_doc->UpdateAllViews();
330 break;
331 }
332 case ID_CS_ADD_LINE:
333 case ID_CS_ADD_LINE_SELECT:
334 {
335 wxASSERT( (m_shapeOnCanvas == NULL) );
336 wxASSERT( (m_savedState != NULL) );
337 wxASSERT( (m_doc != NULL) );
338
339 wxLineShape *lineShape = (wxLineShape *)m_savedState;
340 wxASSERT( (lineShape->GetFrom() != NULL) );
341 wxASSERT( (lineShape->GetTo() != NULL) );
342
343 m_shapeOnCanvas = m_savedState;
344 m_savedState = NULL;
345
346 m_doc->GetDiagram()->AddShape(lineShape);
347
348 lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
349 lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo());
350
351 lineShape->Show(TRUE);
352
353 wxClientDC dc(lineShape->GetCanvas());
354 lineShape->GetCanvas()->PrepareDC(dc);
355
356 // It won't get drawn properly unless you move both
357 // connected images
358 lineShape->GetFrom()->Move(dc, lineShape->GetFrom()->GetX(), lineShape->GetFrom()->GetY());
359 lineShape->GetTo()->Move(dc, lineShape->GetTo()->GetX(), lineShape->GetTo()->GetY());
360
361 if (m_cmd == ID_CS_ADD_LINE_SELECT)
362 {
363 lineShape->Select(TRUE, &dc);
364 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
365 }
366
367 m_doc->Modify(TRUE);
368 m_doc->UpdateAllViews();
369 break;
370 }
371 case ID_CS_CHANGE_BACKGROUND_COLOUR:
372 case ID_CS_MOVE:
373 case ID_CS_SIZE:
374 case ID_CS_EDIT_PROPERTIES:
375 case ID_CS_FONT_CHANGE:
376 case ID_CS_ARROW_CHANGE:
377 case ID_CS_ROTATE_CLOCKWISE:
378 case ID_CS_ROTATE_ANTICLOCKWISE:
379 case ID_CS_CHANGE_LINE_ORDERING:
380 case ID_CS_CHANGE_LINE_ATTACHMENT:
381 case ID_CS_ALIGN:
382 case ID_CS_NEW_POINT:
383 case ID_CS_CUT_POINT:
384 case ID_CS_MOVE_LINE_POINT:
385 case ID_CS_STRAIGHTEN:
386 case ID_CS_MOVE_LABEL:
387 {
388 // At this point we have been given a new shape
389 // just like the old one but with a changed colour.
390 // It's now time to apply that change to the
391 // shape on the canvas, saving the old state.
392 // NOTE: this is general enough to work with MOST attribute
393 // changes!
394
395 wxASSERT( (m_shapeOnCanvas != NULL) );
396 wxASSERT( (m_savedState != NULL) ); // This is the new shape with changed colour
397 wxASSERT( (m_doc != NULL) );
398
399 wxClientDC dc(m_shapeOnCanvas->GetCanvas());
400 m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
401
402 bool isSelected = m_shapeOnCanvas->Selected();
403 if (isSelected)
404 m_shapeOnCanvas->Select(FALSE, & dc);
405
406 if (m_cmd == ID_CS_SIZE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
407 m_cmd == ID_CS_CHANGE_LINE_ORDERING || m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
408 {
409 m_shapeOnCanvas->Erase(dc);
410 }
411
412 // TODO: make sure the ID is the same. Or, when applying the new state,
413 // don't change the original ID.
414 wxShape* tempShape = m_shapeOnCanvas->CreateNewCopy();
415
416 // Apply the saved state to the shape on the canvas, by copying.
417 m_savedState->CopyWithHandler(*m_shapeOnCanvas);
418
419 // Delete this state now it's been used (m_shapeOnCanvas currently holds this state)
420 delete m_savedState;
421
422 // Remember the previous state
423 m_savedState = tempShape;
424
425 // Redraw the shape
426
427 if (m_cmd == ID_CS_MOVE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
428 m_cmd == ID_CS_ALIGN)
429 {
430 m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
431
432 csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
433 m_shapeOnCanvas->FormatText(dc, handler->m_label);
434 m_shapeOnCanvas->Draw(dc);
435 }
436 else if (m_cmd == ID_CS_CHANGE_LINE_ORDERING)
437 {
438 m_shapeOnCanvas->MoveLinks(dc);
439 }
440 else if (m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
441 {
442 wxLineShape *lineShape = (wxLineShape *)m_shapeOnCanvas;
443
444 // Have to move both sets of links since we don't know which links
445 // have been affected (unless we compared before and after states).
446 lineShape->GetFrom()->MoveLinks(dc);
447 lineShape->GetTo()->MoveLinks(dc);
448 }
449 else if (m_cmd == ID_CS_SIZE)
450 {
451 double width, height;
452 m_shapeOnCanvas->GetBoundingBoxMax(&width, &height);
453
454 m_shapeOnCanvas->SetSize(width, height);
455 m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
456
457 m_shapeOnCanvas->Show(TRUE);
458
459 // Recursively redraw links if we have a composite.
460 if (m_shapeOnCanvas->GetChildren().GetCount() > 0)
461 m_shapeOnCanvas->DrawLinks(dc, -1, TRUE);
462
463 m_shapeOnCanvas->GetEventHandler()->OnEndSize(width, height);
464 }
465 else if (m_cmd == ID_CS_EDIT_PROPERTIES || m_cmd == ID_CS_FONT_CHANGE)
466 {
467 csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
468 m_shapeOnCanvas->FormatText(dc, handler->m_label);
469 m_shapeOnCanvas->Draw(dc);
470 }
471 else
472 {
473 m_shapeOnCanvas->Draw(dc);
474 }
475
476 if (isSelected)
477 m_shapeOnCanvas->Select(TRUE, & dc);
478
479 m_doc->Modify(TRUE);
480 m_doc->UpdateAllViews();
481
482 break;
483 }
484 }
485 return TRUE;
486 }
487
488 bool csCommandState::Undo()
489 {
490 switch (m_cmd)
491 {
492 case ID_CS_CUT:
493 {
494 wxASSERT( (m_savedState != NULL) );
495 wxASSERT( (m_doc != NULL) );
496
497 m_doc->GetDiagram()->AddShape(m_savedState);
498 m_shapeOnCanvas = m_savedState;
499 m_savedState = NULL;
500
501 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
502 {
503 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
504 lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
505 lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo(),
506 m_linePositionFrom, m_linePositionTo);
507
508 wxShapeCanvas* canvas = lineShape->GetFrom()->GetCanvas();
509
510 wxClientDC dc(canvas);
511 canvas->PrepareDC(dc);
512
513 lineShape->GetFrom()->MoveLinks(dc);
514 lineShape->GetTo()->MoveLinks(dc);
515
516 }
517 m_shapeOnCanvas->Show(TRUE);
518
519 m_doc->Modify(TRUE);
520 m_doc->UpdateAllViews();
521 break;
522 }
523 case ID_CS_ADD_SHAPE:
524 case ID_CS_ADD_LINE:
525 case ID_CS_ADD_SHAPE_SELECT:
526 case ID_CS_ADD_LINE_SELECT:
527 {
528 wxASSERT( (m_shapeOnCanvas != NULL) );
529 wxASSERT( (m_savedState == NULL) );
530 wxASSERT( (m_doc != NULL) );
531
532 // In case this is a line
533 wxShape* lineFrom = NULL;
534 wxShape* lineTo = NULL;
535 int attachmentFrom = 0, attachmentTo = 0;
536
537 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
538 {
539 // Store the from/to info to save in the line shape
540 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
541 lineFrom = lineShape->GetFrom();
542 lineTo = lineShape->GetTo();
543 attachmentFrom = lineShape->GetAttachmentFrom();
544 attachmentTo = lineShape->GetAttachmentTo();
545 }
546
547 wxClientDC dc(m_shapeOnCanvas->GetCanvas());
548 m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
549
550 m_shapeOnCanvas->Select(FALSE, &dc);
551 ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
552 m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
553 m_shapeOnCanvas->Unlink(); // Unlinks the line, if it is a line
554
555 if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
556 {
557 // Restore the from/to info for future reference
558 wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
559 lineShape->SetFrom(lineFrom);
560 lineShape->SetTo(lineTo);
561 lineShape->SetAttachments(attachmentFrom, attachmentTo);
562 }
563
564 m_savedState = m_shapeOnCanvas;
565 m_shapeOnCanvas = NULL;
566
567 m_doc->Modify(TRUE);
568 m_doc->UpdateAllViews();
569 break;
570 }
571 case ID_CS_CHANGE_BACKGROUND_COLOUR:
572 case ID_CS_MOVE:
573 case ID_CS_SIZE:
574 case ID_CS_EDIT_PROPERTIES:
575 case ID_CS_FONT_CHANGE:
576 case ID_CS_ARROW_CHANGE:
577 case ID_CS_ROTATE_CLOCKWISE:
578 case ID_CS_ROTATE_ANTICLOCKWISE:
579 case ID_CS_CHANGE_LINE_ORDERING:
580 case ID_CS_CHANGE_LINE_ATTACHMENT:
581 case ID_CS_ALIGN:
582 case ID_CS_NEW_POINT:
583 case ID_CS_CUT_POINT:
584 case ID_CS_MOVE_LINE_POINT:
585 case ID_CS_STRAIGHTEN:
586 case ID_CS_MOVE_LABEL:
587 {
588 // Exactly like the Do case; we're just swapping states.
589 Do();
590 break;
591 }
592 }
593
594 return TRUE;
595 }
596