///////////////////////////////////////////////////////////////////////////// // 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 #endif #include #include #include #ifdef __WXMSW__ #include #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(); wxObjectList::compatibility_iterator node = shapeList->GetFirst(); while (node) { wxShape* shape = (wxShape*) node->GetData(); 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->GetNext(); } node = shapeList->GetFirst(); while (node) { wxShape* shape = (wxShape*) node->GetData(); 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), _T("Could not find 'from' shape")); wxASSERT_MSG( (toShape != NULL), _T("Could not find 'to' shape")); fromShape->AddLine(newShape, toShape, newShape->GetAttachmentFrom(), newShape->GetAttachmentTo()); OnAddShape(diagramTo, newShape, dc); } } node = node->GetNext(); } // Now make sure line ordering is correct node = shapeList->GetFirst(); while (node) { wxShape* shape = (wxShape*) node->GetData(); 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; wxObjectList::compatibility_iterator lineNode = shape->GetLines().GetFirst(); while (lineNode) { wxLineShape* lineShape = (wxLineShape*) lineNode->GetData(); if ((diagramFrom == this) || (lineShape->GetTo()->Selected() && lineShape->GetFrom()->Selected())) { wxLineShape* newLineShape = (wxLineShape*) mapping.Get((long) lineShape); wxASSERT_MSG( (newLineShape != NULL), _T("Could not find new line shape")); newLines.Append(newLineShape); } lineNode = lineNode->GetNext(); } if (newLines.GetCount() > 0) newShape->ApplyAttachmentOrdering(newLines); } node = node->GetNext(); } 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) { #if wxUSE_METAFILE // 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; wxChar buf[200]; wxSprintf(buf, _T("Sorry, could not allocate clipboard bitmap (%dx%d)"), (maxX+10), (maxY+10)); wxMessageBox(buf, _T("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; #else wxMessageBox("wxUSE_METAFILE in build required to use Clipboard", _T("Clipboard copy problem")); return false; #endif } #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(_T("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().GetCount() == 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* WXUNUSED(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; }