-/////////////////////////////////////////////////////////////////////////////
-// Name: doc.cpp
-// Purpose: Implements document functionality
-// Author: Julian Smart
-// Modified by:
-// Created: 12/07/98
-// RCS-ID: $Id$
-// Copyright: (c) Julian Smart
-// Licence: wxWindows licence
-/////////////////////////////////////////////////////////////////////////////
-
-#ifdef __GNUG__
-// #pragma implementation
-#endif
-
-// For compilers that support precompilation, includes "wx.h".
-#include <wx/wxprec.h>
-
-#ifdef __BORLANDC__
-#pragma hdrstop
-#endif
-
-#ifndef WX_PRECOMP
-#include <wx/wx.h>
-#endif
-
-#include <wx/wxexpr.h>
-
-#include "studio.h"
-#include "doc.h"
-#include "view.h"
-#include "basicp.h"
-
-IMPLEMENT_DYNAMIC_CLASS(csDiagramDocument, wxDocument)
-
-#ifdef _MSC_VER
-#pragma warning(disable:4355)
-#endif
-
-csDiagramDocument::csDiagramDocument():m_diagram(this)
-{
-}
-
-#ifdef _MSC_VER
-#pragma warning(default:4355)
-#endif
-
-csDiagramDocument::~csDiagramDocument()
-{
-}
-
-bool csDiagramDocument::OnCloseDocument()
-{
- m_diagram.DeleteAllShapes();
- return TRUE;
-}
-
-bool csDiagramDocument::OnSaveDocument(const wxString& file)
-{
- if (file == "")
- return FALSE;
-
- if (!m_diagram.SaveFile(file))
- {
- wxString msgTitle;
- if (wxTheApp->GetAppName() != "")
- msgTitle = wxTheApp->GetAppName();
- else
- msgTitle = wxString("File error");
-
- (void)wxMessageBox("Sorry, could not open this file for saving.", msgTitle, wxOK | wxICON_EXCLAMATION,
- GetDocumentWindow());
- return FALSE;
- }
-
- Modify(FALSE);
- SetFilename(file);
- return TRUE;
-}
-
-bool csDiagramDocument::OnOpenDocument(const wxString& file)
-{
- if (!OnSaveModified())
- return FALSE;
-
- wxString msgTitle;
- if (wxTheApp->GetAppName() != "")
- msgTitle = wxTheApp->GetAppName();
- else
- msgTitle = wxString("File error");
-
- m_diagram.DeleteAllShapes();
- if (!m_diagram.LoadFile(file))
- {
- (void)wxMessageBox("Sorry, could not open this file.", msgTitle, wxOK|wxICON_EXCLAMATION,
- GetDocumentWindow());
- return FALSE;
- }
- SetFilename(file, TRUE);
- Modify(FALSE);
- UpdateAllViews();
-
- return TRUE;
-}
-
-
-/*
- * Implementation of drawing command
- */
-
-csDiagramCommand::csDiagramCommand(const wxString& name, csDiagramDocument *doc,
- csCommandState* onlyState):
- wxCommand(TRUE, name)
-{
- m_doc = doc;
-
- if (onlyState)
- {
- AddState(onlyState);
- }
-}
-
-csDiagramCommand::~csDiagramCommand()
-{
- wxNode* node = m_states.First();
- while (node)
- {
- csCommandState* state = (csCommandState*) node->Data();
- delete state;
- node = node->Next();
- }
-}
-
-void csDiagramCommand::AddState(csCommandState* state)
-{
- state->m_doc = m_doc;
-// state->m_cmd = m_cmd;
- m_states.Append(state);
-}
-
-// Insert a state at the beginning of the list
-void csDiagramCommand::InsertState(csCommandState* state)
-{
- state->m_doc = m_doc;
-// state->m_cmd = m_cmd;
- m_states.Insert(state);
-}
-
-// Schedule all lines connected to the states to be cut.
-void csDiagramCommand::RemoveLines()
-{
- wxNode* node = m_states.First();
- while (node)
- {
- csCommandState* state = (csCommandState*) node->Data();
- wxShape* shape = state->GetShapeOnCanvas();
- wxASSERT( (shape != NULL) );
-
- wxNode *node1 = shape->GetLines().First();
- while (node1)
- {
- wxLineShape *line = (wxLineShape *)node1->Data();
- if (!FindStateByShape(line))
- {
- csCommandState* newState = new csCommandState(ID_CS_CUT, NULL, line);
- InsertState(newState);
- }
-
- node1 = node1->Next();
- }
- node = node->Next();
- }
-}
-
-csCommandState* csDiagramCommand::FindStateByShape(wxShape* shape)
-{
- wxNode* node = m_states.First();
- while (node)
- {
- csCommandState* state = (csCommandState*) node->Data();
- if (shape == state->GetShapeOnCanvas() || shape == state->GetSavedState())
- return state;
- node = node->Next();
- }
- return NULL;
-}
-
-bool csDiagramCommand::Do()
-{
- wxNode* node = m_states.First();
- while (node)
- {
- csCommandState* state = (csCommandState*) node->Data();
- if (!state->Do())
- return FALSE;
- node = node->Next();
- }
- return TRUE;
-}
-
-bool csDiagramCommand::Undo()
-{
- // Undo in reverse order, so e.g. shapes get added
- // back before the lines do.
- wxNode* node = m_states.Last();
- while (node)
- {
- csCommandState* state = (csCommandState*) node->Data();
- if (!state->Undo())
- return FALSE;
- node = node->Previous();
- }
- return TRUE;
-}
-
-csCommandState::csCommandState(int cmd, wxShape* savedState, wxShape* shapeOnCanvas)
-{
- m_cmd = cmd;
- m_doc = NULL;
- m_savedState = savedState;
- m_shapeOnCanvas = shapeOnCanvas;
- m_linePositionFrom = 0;
- m_linePositionTo = 0;
-}
-
-csCommandState::~csCommandState()
-{
- if (m_savedState)
- {
- m_savedState->SetCanvas(NULL);
- delete m_savedState;
- }
-}
-
-bool csCommandState::Do()
-{
- switch (m_cmd)
- {
- case ID_CS_CUT:
- {
- // New state is 'nothing' - maybe pass shape ID to state so we know what
- // we're talking about.
- // Then save old shape in m_savedState (actually swap pointers)
-
- wxASSERT( (m_shapeOnCanvas != NULL) );
- wxASSERT( (m_savedState == NULL) ); // new state will be 'nothing'
- wxASSERT( (m_doc != NULL) );
-
- wxShapeCanvas* canvas = m_shapeOnCanvas->GetCanvas();
-
- // In case this is a line
- wxShape* lineFrom = NULL;
- wxShape* lineTo = NULL;
- int attachmentFrom = 0, attachmentTo = 0;
-
- if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
- {
- // Store the from/to info to save in the line shape
- wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
- lineFrom = lineShape->GetFrom();
- lineTo = lineShape->GetTo();
- attachmentFrom = lineShape->GetAttachmentFrom();
- attachmentTo = lineShape->GetAttachmentTo();
-
- m_linePositionFrom = lineFrom->GetLinePosition(lineShape);
- m_linePositionTo = lineTo->GetLinePosition(lineShape);
- }
-
- m_shapeOnCanvas->Select(FALSE);
- ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
-
- m_shapeOnCanvas->Unlink();
-
- m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
-
- m_savedState = m_shapeOnCanvas;
-
- if (m_savedState->IsKindOf(CLASSINFO(wxLineShape)))
- {
- // Restore the from/to info for future reference
- wxLineShape* lineShape = (wxLineShape*) m_savedState;
- lineShape->SetFrom(lineFrom);
- lineShape->SetTo(lineTo);
- lineShape->SetAttachments(attachmentFrom, attachmentTo);
-
- wxClientDC dc(canvas);
- canvas->PrepareDC(dc);
-
- lineFrom->MoveLinks(dc);
- lineTo->MoveLinks(dc);
- }
-
- m_doc->Modify(TRUE);
- m_doc->UpdateAllViews();
- break;
- }
- case ID_CS_ADD_SHAPE:
- case ID_CS_ADD_SHAPE_SELECT:
- {
- // The app has given the command state a new m_savedState
- // shape, which is the new shape to add to the canvas (but
- // not actually added until this point).
- // The new 'saved state' is therefore 'nothing' since there
- // was nothing there before.
-
- wxASSERT( (m_shapeOnCanvas == NULL) );
- wxASSERT( (m_savedState != NULL) );
- wxASSERT( (m_doc != NULL) );
-
- m_shapeOnCanvas = m_savedState;
- m_savedState = NULL;
-
- m_doc->GetDiagram()->AddShape(m_shapeOnCanvas);
- m_shapeOnCanvas->Show(TRUE);
-
- wxClientDC dc(m_shapeOnCanvas->GetCanvas());
- m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
-
- csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
- m_shapeOnCanvas->FormatText(dc, handler->m_label);
-
- m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
-
- if (m_cmd == ID_CS_ADD_SHAPE_SELECT)
- {
- m_shapeOnCanvas->Select(TRUE, &dc);
- ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
- }
-
- m_doc->Modify(TRUE);
- m_doc->UpdateAllViews();
- break;
- }
- case ID_CS_ADD_LINE:
- case ID_CS_ADD_LINE_SELECT:
- {
- wxASSERT( (m_shapeOnCanvas == NULL) );
- wxASSERT( (m_savedState != NULL) );
- wxASSERT( (m_doc != NULL) );
-
- wxLineShape *lineShape = (wxLineShape *)m_savedState;
- wxASSERT( (lineShape->GetFrom() != NULL) );
- wxASSERT( (lineShape->GetTo() != NULL) );
-
- m_shapeOnCanvas = m_savedState;
- m_savedState = NULL;
-
- m_doc->GetDiagram()->AddShape(lineShape);
-
- lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
- lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo());
-
- lineShape->Show(TRUE);
-
- wxClientDC dc(lineShape->GetCanvas());
- lineShape->GetCanvas()->PrepareDC(dc);
-
- // It won't get drawn properly unless you move both
- // connected images
- lineShape->GetFrom()->Move(dc, lineShape->GetFrom()->GetX(), lineShape->GetFrom()->GetY());
- lineShape->GetTo()->Move(dc, lineShape->GetTo()->GetX(), lineShape->GetTo()->GetY());
-
- if (m_cmd == ID_CS_ADD_LINE_SELECT)
- {
- lineShape->Select(TRUE, &dc);
- ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, TRUE);
- }
-
- m_doc->Modify(TRUE);
- m_doc->UpdateAllViews();
- break;
- }
- case ID_CS_CHANGE_BACKGROUND_COLOUR:
- case ID_CS_MOVE:
- case ID_CS_SIZE:
- case ID_CS_EDIT_PROPERTIES:
- case ID_CS_FONT_CHANGE:
- case ID_CS_ARROW_CHANGE:
- case ID_CS_ROTATE_CLOCKWISE:
- case ID_CS_ROTATE_ANTICLOCKWISE:
- case ID_CS_CHANGE_LINE_ORDERING:
- case ID_CS_CHANGE_LINE_ATTACHMENT:
- case ID_CS_ALIGN:
- case ID_CS_NEW_POINT:
- case ID_CS_CUT_POINT:
- case ID_CS_MOVE_LINE_POINT:
- case ID_CS_STRAIGHTEN:
- case ID_CS_MOVE_LABEL:
- {
- // At this point we have been given a new shape
- // just like the old one but with a changed colour.
- // It's now time to apply that change to the
- // shape on the canvas, saving the old state.
- // NOTE: this is general enough to work with MOST attribute
- // changes!
-
- wxASSERT( (m_shapeOnCanvas != NULL) );
- wxASSERT( (m_savedState != NULL) ); // This is the new shape with changed colour
- wxASSERT( (m_doc != NULL) );
-
- wxClientDC dc(m_shapeOnCanvas->GetCanvas());
- m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
-
- bool isSelected = m_shapeOnCanvas->Selected();
- if (isSelected)
- m_shapeOnCanvas->Select(FALSE, & dc);
-
- if (m_cmd == ID_CS_SIZE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
- m_cmd == ID_CS_CHANGE_LINE_ORDERING || m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
- {
- m_shapeOnCanvas->Erase(dc);
- }
-
- // TODO: make sure the ID is the same. Or, when applying the new state,
- // don't change the original ID.
- wxShape* tempShape = m_shapeOnCanvas->CreateNewCopy();
-
- // Apply the saved state to the shape on the canvas, by copying.
- m_savedState->CopyWithHandler(*m_shapeOnCanvas);
-
- // Delete this state now it's been used (m_shapeOnCanvas currently holds this state)
- delete m_savedState;
-
- // Remember the previous state
- m_savedState = tempShape;
-
- // Redraw the shape
-
- if (m_cmd == ID_CS_MOVE || m_cmd == ID_CS_ROTATE_CLOCKWISE || m_cmd == ID_CS_ROTATE_ANTICLOCKWISE ||
- m_cmd == ID_CS_ALIGN)
- {
- m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
-
- csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
- m_shapeOnCanvas->FormatText(dc, handler->m_label);
- m_shapeOnCanvas->Draw(dc);
- }
- else if (m_cmd == ID_CS_CHANGE_LINE_ORDERING)
- {
- m_shapeOnCanvas->MoveLinks(dc);
- }
- else if (m_cmd == ID_CS_CHANGE_LINE_ATTACHMENT)
- {
- wxLineShape *lineShape = (wxLineShape *)m_shapeOnCanvas;
-
- // Have to move both sets of links since we don't know which links
- // have been affected (unless we compared before and after states).
- lineShape->GetFrom()->MoveLinks(dc);
- lineShape->GetTo()->MoveLinks(dc);
- }
- else if (m_cmd == ID_CS_SIZE)
- {
- double width, height;
- m_shapeOnCanvas->GetBoundingBoxMax(&width, &height);
-
- m_shapeOnCanvas->SetSize(width, height);
- m_shapeOnCanvas->Move(dc, m_shapeOnCanvas->GetX(), m_shapeOnCanvas->GetY());
-
- m_shapeOnCanvas->Show(TRUE);
-
- // Recursively redraw links if we have a composite.
- if (m_shapeOnCanvas->GetChildren().Number() > 0)
- m_shapeOnCanvas->DrawLinks(dc, -1, TRUE);
-
- m_shapeOnCanvas->GetEventHandler()->OnEndSize(width, height);
- }
- else if (m_cmd == ID_CS_EDIT_PROPERTIES || m_cmd == ID_CS_FONT_CHANGE)
- {
- csEvtHandler *handler = (csEvtHandler *)m_shapeOnCanvas->GetEventHandler();
- m_shapeOnCanvas->FormatText(dc, handler->m_label);
- m_shapeOnCanvas->Draw(dc);
- }
- else
- {
- m_shapeOnCanvas->Draw(dc);
- }
-
- if (isSelected)
- m_shapeOnCanvas->Select(TRUE, & dc);
-
- m_doc->Modify(TRUE);
- m_doc->UpdateAllViews();
-
- break;
- }
- }
- return TRUE;
-}
-
-bool csCommandState::Undo()
-{
- switch (m_cmd)
- {
- case ID_CS_CUT:
- {
- wxASSERT( (m_savedState != NULL) );
- wxASSERT( (m_doc != NULL) );
-
- m_doc->GetDiagram()->AddShape(m_savedState);
- m_shapeOnCanvas = m_savedState;
- m_savedState = NULL;
-
- if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
- {
- wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
- lineShape->GetFrom()->AddLine(lineShape, lineShape->GetTo(),
- lineShape->GetAttachmentFrom(), lineShape->GetAttachmentTo(),
- m_linePositionFrom, m_linePositionTo);
-
- wxShapeCanvas* canvas = lineShape->GetFrom()->GetCanvas();
-
- wxClientDC dc(canvas);
- canvas->PrepareDC(dc);
-
- lineShape->GetFrom()->MoveLinks(dc);
- lineShape->GetTo()->MoveLinks(dc);
-
- }
- m_shapeOnCanvas->Show(TRUE);
-
- m_doc->Modify(TRUE);
- m_doc->UpdateAllViews();
- break;
- }
- case ID_CS_ADD_SHAPE:
- case ID_CS_ADD_LINE:
- case ID_CS_ADD_SHAPE_SELECT:
- case ID_CS_ADD_LINE_SELECT:
- {
- wxASSERT( (m_shapeOnCanvas != NULL) );
- wxASSERT( (m_savedState == NULL) );
- wxASSERT( (m_doc != NULL) );
-
- // In case this is a line
- wxShape* lineFrom = NULL;
- wxShape* lineTo = NULL;
- int attachmentFrom = 0, attachmentTo = 0;
-
- if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
- {
- // Store the from/to info to save in the line shape
- wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
- lineFrom = lineShape->GetFrom();
- lineTo = lineShape->GetTo();
- attachmentFrom = lineShape->GetAttachmentFrom();
- attachmentTo = lineShape->GetAttachmentTo();
- }
-
- wxClientDC dc(m_shapeOnCanvas->GetCanvas());
- m_shapeOnCanvas->GetCanvas()->PrepareDC(dc);
-
- m_shapeOnCanvas->Select(FALSE, &dc);
- ((csDiagramView*) m_doc->GetFirstView())->SelectShape(m_shapeOnCanvas, FALSE);
- m_doc->GetDiagram()->RemoveShape(m_shapeOnCanvas);
- m_shapeOnCanvas->Unlink(); // Unlinks the line, if it is a line
-
- if (m_shapeOnCanvas->IsKindOf(CLASSINFO(wxLineShape)))
- {
- // Restore the from/to info for future reference
- wxLineShape* lineShape = (wxLineShape*) m_shapeOnCanvas;
- lineShape->SetFrom(lineFrom);
- lineShape->SetTo(lineTo);
- lineShape->SetAttachments(attachmentFrom, attachmentTo);
- }
-
- m_savedState = m_shapeOnCanvas;
- m_shapeOnCanvas = NULL;
-
- m_doc->Modify(TRUE);
- m_doc->UpdateAllViews();
- break;
- }
- case ID_CS_CHANGE_BACKGROUND_COLOUR:
- case ID_CS_MOVE:
- case ID_CS_SIZE:
- case ID_CS_EDIT_PROPERTIES:
- case ID_CS_FONT_CHANGE:
- case ID_CS_ARROW_CHANGE:
- case ID_CS_ROTATE_CLOCKWISE:
- case ID_CS_ROTATE_ANTICLOCKWISE:
- case ID_CS_CHANGE_LINE_ORDERING:
- case ID_CS_CHANGE_LINE_ATTACHMENT:
- case ID_CS_ALIGN:
- case ID_CS_NEW_POINT:
- case ID_CS_CUT_POINT:
- case ID_CS_MOVE_LINE_POINT:
- case ID_CS_STRAIGHTEN:
- case ID_CS_MOVE_LABEL:
- {
- // Exactly like the Do case; we're just swapping states.
- Do();
- break;
- }
- }
-
- return TRUE;
-}
-