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