321 lines
8.8 KiB
C++
321 lines
8.8 KiB
C++
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Name: csprint.cpp
|
||
|
// Purpose: Printing and clipboard 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 <wx/clipbrd.h>
|
||
|
|
||
|
#ifdef __WXMSW__
|
||
|
#include <wx/metafile.h>
|
||
|
#endif
|
||
|
|
||
|
#include "studio.h"
|
||
|
#include "doc.h"
|
||
|
#include "shapes.h"
|
||
|
#include "view.h"
|
||
|
|
||
|
IMPLEMENT_DYNAMIC_CLASS(wxDiagramClipboard, wxDiagram)
|
||
|
|
||
|
// Copy selection
|
||
|
bool wxDiagramClipboard::Copy(wxDiagram* diagram)
|
||
|
{
|
||
|
DeleteAllShapes();
|
||
|
|
||
|
return DoCopy(diagram, this, FALSE, NULL);
|
||
|
}
|
||
|
|
||
|
// Copy contents to the diagram, with new ids.
|
||
|
|
||
|
bool wxDiagramClipboard::Paste(wxDiagram* diagram, wxDC* dc, int offsetX, int offsetY)
|
||
|
{
|
||
|
return DoCopy(this, diagram, TRUE, dc, offsetX, offsetY);
|
||
|
}
|
||
|
|
||
|
// Universal copy function (to or from clipboard).
|
||
|
// TODO:
|
||
|
// Note that this only works for non-composites so far (nested shapes
|
||
|
// don't have their old-to-new object mappings stored).
|
||
|
// Also, lines don't yet get their attachment points moved to the new offset position
|
||
|
// if they have more than 2 points.
|
||
|
bool wxDiagramClipboard::DoCopy(wxDiagram* diagramFrom, wxDiagram* diagramTo, bool newIds,
|
||
|
wxDC* dc, int offsetX, int offsetY)
|
||
|
{
|
||
|
OnStartCopy(diagramTo);
|
||
|
|
||
|
wxHashTable mapping(wxKEY_INTEGER);
|
||
|
|
||
|
// First copy all node shapes.
|
||
|
wxList* shapeList = diagramFrom->GetShapeList();
|
||
|
wxNode* node = shapeList->First();
|
||
|
while (node)
|
||
|
{
|
||
|
wxShape* shape = (wxShape*) node->Data();
|
||
|
if (((diagramFrom == this) || shape->Selected()) && !shape->IsKindOf(CLASSINFO(wxLineShape)))
|
||
|
{
|
||
|
wxShape* newShape = shape->CreateNewCopy();
|
||
|
newShape->GetLines().Clear();
|
||
|
if (newIds)
|
||
|
{
|
||
|
newShape->AssignNewIds();
|
||
|
}
|
||
|
mapping.Put((long) shape, (wxObject*) newShape);
|
||
|
|
||
|
newShape->SetX(newShape->GetX() + offsetX);
|
||
|
newShape->SetY(newShape->GetY() + offsetY);
|
||
|
|
||
|
OnAddShape(diagramTo, newShape, dc);
|
||
|
|
||
|
}
|
||
|
node = node->Next();
|
||
|
}
|
||
|
|
||
|
node = shapeList->First();
|
||
|
while (node)
|
||
|
{
|
||
|
wxShape* shape = (wxShape*) node->Data();
|
||
|
if (((diagramFrom == this) || shape->Selected()) && shape->IsKindOf(CLASSINFO(wxLineShape)))
|
||
|
{
|
||
|
wxLineShape* lineShape = (wxLineShape*) shape;
|
||
|
// Only copy a line if its ends are selected too.
|
||
|
if ((diagramFrom == this) || (lineShape->GetTo()->Selected() && lineShape->GetFrom()->Selected()))
|
||
|
{
|
||
|
wxLineShape* newShape = (wxLineShape*) shape->CreateNewCopy();
|
||
|
mapping.Put((long) shape, (wxObject*) newShape);
|
||
|
|
||
|
if (newIds)
|
||
|
newShape->AssignNewIds();
|
||
|
|
||
|
wxShape* fromShape = (wxShape*) mapping.Get((long) lineShape->GetFrom());
|
||
|
wxShape* toShape = (wxShape*) mapping.Get((long) lineShape->GetTo());
|
||
|
|
||
|
wxASSERT_MSG( (fromShape != NULL), "Could not find 'from' shape");
|
||
|
wxASSERT_MSG( (toShape != NULL), "Could not find 'to' shape");
|
||
|
|
||
|
fromShape->AddLine(newShape, toShape, newShape->GetAttachmentFrom(),
|
||
|
newShape->GetAttachmentTo());
|
||
|
|
||
|
OnAddShape(diagramTo, newShape, dc);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
node = node->Next();
|
||
|
}
|
||
|
|
||
|
// Now make sure line ordering is correct
|
||
|
node = shapeList->First();
|
||
|
while (node)
|
||
|
{
|
||
|
wxShape* shape = (wxShape*) node->Data();
|
||
|
if (((diagramFrom == this) || shape->Selected()) && !shape->IsKindOf(CLASSINFO(wxLineShape)))
|
||
|
{
|
||
|
wxShape* newShape = (wxShape*) mapping.Get((long) shape);
|
||
|
|
||
|
// Make a list of all the new lines, in the same order as the old lines.
|
||
|
// Then apply the list of new lines to the shape.
|
||
|
wxList newLines;
|
||
|
wxNode* lineNode = shape->GetLines().First();
|
||
|
while (lineNode)
|
||
|
{
|
||
|
wxLineShape* lineShape = (wxLineShape*) lineNode->Data();
|
||
|
if ((diagramFrom == this) || (lineShape->GetTo()->Selected() && lineShape->GetFrom()->Selected()))
|
||
|
{
|
||
|
wxLineShape* newLineShape = (wxLineShape*) mapping.Get((long) lineShape);
|
||
|
|
||
|
wxASSERT_MSG( (newLineShape != NULL), "Could not find new line shape");
|
||
|
|
||
|
newLines.Append(newLineShape);
|
||
|
}
|
||
|
|
||
|
lineNode = lineNode->Next();
|
||
|
}
|
||
|
|
||
|
if (newLines.Number() > 0)
|
||
|
newShape->ApplyAttachmentOrdering(newLines);
|
||
|
}
|
||
|
node = node->Next();
|
||
|
}
|
||
|
|
||
|
OnEndCopy(diagramTo);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
#ifdef __WXMSW__
|
||
|
// Draw contents to a Windows metafile device context and a bitmap, and copy
|
||
|
// these to the Windows clipboard
|
||
|
bool wxDiagramClipboard::CopyToClipboard(double scale)
|
||
|
{
|
||
|
// Make a metafile DC
|
||
|
wxMetaFileDC mfDC;
|
||
|
if (mfDC.Ok())
|
||
|
{
|
||
|
mfDC.SetUserScale(scale, scale);
|
||
|
|
||
|
// Draw on metafile DC
|
||
|
Redraw(mfDC);
|
||
|
|
||
|
int printWidth = mfDC.MaxX() - mfDC.MinX();
|
||
|
int printHeight = mfDC.MaxY() - mfDC.MinY();
|
||
|
int maxX = (int)mfDC.MaxX();
|
||
|
int maxY = (int)mfDC.MaxY();
|
||
|
wxMetaFile *mf = mfDC.Close();
|
||
|
|
||
|
// Set to a bitmap memory DC
|
||
|
wxBitmap *newBitmap = new wxBitmap((int)(maxX + 10), (int)(maxY + 10));
|
||
|
if (!newBitmap->Ok())
|
||
|
{
|
||
|
delete newBitmap;
|
||
|
|
||
|
char buf[200];
|
||
|
sprintf(buf, "Sorry, could not allocate clipboard bitmap (%dx%d)", (maxX+10), (maxY+10));
|
||
|
wxMessageBox(buf, "Clipboard copy problem");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
wxMemoryDC memDC;
|
||
|
memDC.SelectObject(*newBitmap);
|
||
|
memDC.Clear();
|
||
|
|
||
|
// Now draw on memory bitmap DC
|
||
|
Redraw(memDC);
|
||
|
|
||
|
memDC.SelectObject(wxNullBitmap);
|
||
|
|
||
|
// Open clipboard and set the data
|
||
|
if (wxOpenClipboard())
|
||
|
{
|
||
|
wxEmptyClipboard();
|
||
|
|
||
|
// Copy the bitmap to the clipboard
|
||
|
wxSetClipboardData(wxDF_BITMAP, newBitmap, 0, 0);
|
||
|
|
||
|
#if 0 // TODO: replace this code (wxEnhMetaFile doesn't have SetClipboard)
|
||
|
if (mf)
|
||
|
{
|
||
|
// Copy the metafile to the clipboard
|
||
|
// Allow a small margin
|
||
|
bool success = mf->SetClipboard((int)(mfDC.MaxX() + 15), (int)(mfDC.MaxY() + 15));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Close clipboard
|
||
|
wxCloseClipboard();
|
||
|
}
|
||
|
|
||
|
delete newBitmap;
|
||
|
delete mf;
|
||
|
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
// __WXMSW__
|
||
|
|
||
|
// Override this to e.g. have the shape added through a Do/Undo command system.
|
||
|
// By default, we'll just add it directly to the destination diagram.
|
||
|
bool wxDiagramClipboard::OnAddShape(wxDiagram* diagramTo, wxShape* newShape, wxDC* dc)
|
||
|
{
|
||
|
diagramTo->AddShape(newShape);
|
||
|
|
||
|
if (dc && (diagramTo != this))
|
||
|
{
|
||
|
newShape->Select(TRUE, dc);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* csDiagramClipboard
|
||
|
*/
|
||
|
|
||
|
IMPLEMENT_DYNAMIC_CLASS(csDiagramClipboard, wxDiagramClipboard)
|
||
|
|
||
|
// Start/end copying
|
||
|
bool csDiagramClipboard::OnStartCopy(wxDiagram* diagramTo)
|
||
|
{
|
||
|
// Do nothing if copying to the clipboard
|
||
|
if (diagramTo == this)
|
||
|
return TRUE;
|
||
|
|
||
|
// Deselect all objects initially.
|
||
|
|
||
|
csDiagram* diagram = (csDiagram*) diagramTo;
|
||
|
csDiagramDocument* doc = diagram->GetDocument();
|
||
|
((csDiagramView*)doc->GetFirstView())->SelectAll(FALSE);
|
||
|
|
||
|
m_currentCmd = new csDiagramCommand("Paste", doc);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
bool csDiagramClipboard::OnEndCopy(wxDiagram* diagramTo)
|
||
|
{
|
||
|
// Do nothing if copying to the clipboard
|
||
|
if (diagramTo == this)
|
||
|
return TRUE;
|
||
|
|
||
|
csDiagram* diagram = (csDiagram*) diagramTo;
|
||
|
csDiagramDocument* doc = diagram->GetDocument();
|
||
|
|
||
|
if (m_currentCmd)
|
||
|
{
|
||
|
if (m_currentCmd->GetStates().Number() == 0)
|
||
|
{
|
||
|
delete m_currentCmd;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
doc->GetCommandProcessor()->Submit(m_currentCmd);
|
||
|
m_currentCmd = NULL;
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// Use the command framework to add the shapes, if we're copying to a diagram and
|
||
|
// not the clipboard.
|
||
|
bool csDiagramClipboard::OnAddShape(wxDiagram* diagramTo, wxShape* newShape, wxDC* dc)
|
||
|
{
|
||
|
if (diagramTo == this)
|
||
|
{
|
||
|
diagramTo->AddShape(newShape);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
csDiagram* diagram = (csDiagram*) diagramTo;
|
||
|
csDiagramDocument* doc = diagram->GetDocument();
|
||
|
|
||
|
if (newShape->IsKindOf(CLASSINFO(wxLineShape)))
|
||
|
m_currentCmd->AddState(new csCommandState(ID_CS_ADD_LINE_SELECT, newShape, NULL));
|
||
|
else
|
||
|
m_currentCmd->AddState(new csCommandState(ID_CS_ADD_SHAPE_SELECT, newShape, NULL));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|