From 6045b9e6b6134a5defb60a489983334e7770eb4f Mon Sep 17 00:00:00 2001 From: Jim Evins Date: Sun, 24 Apr 2016 16:52:14 -0400 Subject: [PATCH] Added initial clipboard support. --- glabels/LabelModel.cpp | 96 +++++++++++++++++++++++++++++++++++++ glabels/LabelModel.h | 8 ++++ glabels/MainWindow.cpp | 20 +++++--- glabels/MainWindow.h | 2 + glabels/XmlLabelCreator.cpp | 31 ++++++++++-- glabels/XmlLabelCreator.h | 2 + glabels/XmlLabelParser.cpp | 93 +++++++++++++++++++++++++++-------- glabels/XmlLabelParser.h | 14 +++--- 8 files changed, 231 insertions(+), 35 deletions(-) diff --git a/glabels/LabelModel.cpp b/glabels/LabelModel.cpp index 7822847..21fe185 100644 --- a/glabels/LabelModel.cpp +++ b/glabels/LabelModel.cpp @@ -23,10 +23,21 @@ #include #include #include +#include +#include +#include #include #include "LabelModelObject.h" #include "LabelRegion.h" +#include "XmlLabelCreator.h" +#include "XmlLabelParser.h" + + +namespace +{ + const QString MIME_TYPE = "application/x-glabels-objects"; +} /// @@ -1081,6 +1092,91 @@ void LabelModel::setSelectionFillColorNode( ColorNode fillColorNode ) } +/// +/// Copy selection to clipboard +/// +void LabelModel::copySelection() +{ + if ( !isSelectionEmpty() ) + { + QClipboard *clipboard = QApplication::clipboard(); + + QString buffer; + XmlLabelCreator::serializeObjects( getSelection(), buffer ); + + QMimeData *mimeData = new QMimeData; + mimeData->setData( MIME_TYPE, buffer.toUtf8() ); + + clipboard->setMimeData( mimeData ); + } +} + + +/// +/// Cut selection to clipboard +/// +void LabelModel::cutSelection() +{ + copySelection(); + deleteSelection(); +} + + +/// +/// Can we paste? +/// +bool LabelModel::canPaste() +{ + const QClipboard *clipboard = QApplication::clipboard(); + const QMimeData *mimeData = clipboard->mimeData(); + + if ( mimeData->hasFormat( MIME_TYPE ) ) + { + return true; + } + else if ( mimeData->hasImage() ) + { + // TODO: return true + } + else if ( mimeData->hasText() ) + { + // TODO: return true + } + return false; +} + + +/// +/// Paste from clipboard +/// +void LabelModel::paste() +{ + const QClipboard *clipboard = QApplication::clipboard(); + const QMimeData *mimeData = clipboard->mimeData(); + + if ( mimeData->hasFormat( MIME_TYPE ) ) + { + QByteArray buffer = mimeData->data( MIME_TYPE ); + QList objects = XmlLabelParser::deserializeObjects( QString(buffer) ); + + unselectAll(); + foreach ( LabelModelObject* object, objects ) + { + addObject( object ); + selectObject( object ); + } + } + else if ( mimeData->hasImage() ) + { + // TODO: create an image object from image + } + else if ( mimeData->hasText() ) + { + // TODO: create a text object from text + } +} + + /// /// Draw label objects /// diff --git a/glabels/LabelModel.h b/glabels/LabelModel.h index 1a690a8..ac9b068 100644 --- a/glabels/LabelModel.h +++ b/glabels/LabelModel.h @@ -174,6 +174,14 @@ public: void setSelectionFillColorNode( ColorNode fillColorNode ); + ///////////////////////////////// + // Clipboard operations + ///////////////////////////////// + void copySelection(); + void cutSelection(); + bool canPaste(); + void paste(); + ///////////////////////////////// // Drawing operations ///////////////////////////////// diff --git a/glabels/MainWindow.cpp b/glabels/MainWindow.cpp index adb62e1..af6b779 100644 --- a/glabels/MainWindow.cpp +++ b/glabels/MainWindow.cpp @@ -20,6 +20,7 @@ #include "MainWindow.h" +#include #include #include #include @@ -125,6 +126,7 @@ MainWindow::MainWindow() connect( mContents, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(changePage(QListWidgetItem*,QListWidgetItem*))); connect( mLabelEditor, SIGNAL(zoomChanged()), this, SLOT(onZoomChanged()) ); + connect( QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardChanged()) ); #if 0 connect( mLabelEditor, SIGNAL(pointerMoved(double, double)), this, SLOT(onPointerMoved(double, double)) ); @@ -726,9 +728,6 @@ void MainWindow::setDocVerbsEnabled( bool enabled ) fileSaveAsAction->setEnabled( enabled ); editUndoAction->setEnabled( enabled ); editRedoAction->setEnabled( enabled ); - editCutAction->setEnabled( enabled ); - editCopyAction->setEnabled( enabled ); - editPasteAction->setEnabled( enabled ); editDeleteAction->setEnabled( enabled ); editSelectAllAction->setEnabled( enabled ); editUnSelectAllAction->setEnabled( enabled ); @@ -903,6 +902,15 @@ void MainWindow::changePage(QListWidgetItem *current, QListWidgetItem *previous) } +/// +/// Clipboard contents changed +/// +void MainWindow::clipboardChanged() +{ + setPasteVerbsEnabled( mModel->canPaste() ); +} + + /// /// File->New Action /// @@ -989,7 +997,7 @@ void MainWindow::editRedo() /// void MainWindow::editCut() { - qDebug() << "ACTION: edit->Cut"; + mModel->cutSelection(); } @@ -998,7 +1006,7 @@ void MainWindow::editCut() /// void MainWindow::editCopy() { - qDebug() << "ACTION: edit->Copy"; + mModel->copySelection(); } @@ -1007,7 +1015,7 @@ void MainWindow::editCopy() /// void MainWindow::editPaste() { - qDebug() << "ACTION: edit->Paste"; + mModel->paste(); } diff --git a/glabels/MainWindow.h b/glabels/MainWindow.h index b781f0d..b17f6bb 100644 --- a/glabels/MainWindow.h +++ b/glabels/MainWindow.h @@ -84,6 +84,8 @@ protected: private slots: void changePage(QListWidgetItem *current, QListWidgetItem *previous); + void clipboardChanged(); + void fileNew(); void fileOpen(); void fileSave(); diff --git a/glabels/XmlLabelCreator.cpp b/glabels/XmlLabelCreator.cpp index 7a7795b..74f2754 100644 --- a/glabels/XmlLabelCreator.cpp +++ b/glabels/XmlLabelCreator.cpp @@ -65,6 +65,24 @@ XmlLabelCreator::writeBuffer( const LabelModel* label, QString& buffer ) } +void +XmlLabelCreator::serializeObjects( const QList& objects, + QString& buffer ) +{ + QDomDocument doc; + + QDomNode xmlNode( doc.createProcessingInstruction( "xml", "version=\"1.0\"" ) ); + doc.appendChild( xmlNode ); + + QDomElement root = doc.createElement( "Glabels-objects" ); + doc.appendChild( root ); + + addObjectsToNode( root, objects ); + + buffer = doc.toString( 2 ); +} + + void XmlLabelCreator::createDoc( QDomDocument& doc, const LabelModel* label ) { @@ -94,16 +112,23 @@ XmlLabelCreator::createObjectsNode( QDomElement &parent, const LabelModel* label glabels::XmlUtil::setStringAttr( node, "id", "0" ); glabels::XmlUtil::setBoolAttr( node, "rotate", label->rotate() ); - foreach ( LabelModelObject* object, label->objectList() ) + addObjectsToNode( node, label->objectList() ); +} + + +void +XmlLabelCreator::addObjectsToNode( QDomElement &parent, const QList& objects ) +{ + foreach ( LabelModelObject* object, objects ) { if ( LabelModelBoxObject* boxObject = dynamic_cast(object) ) { - createObjectBoxNode( node, boxObject ); + createObjectBoxNode( parent, boxObject ); } // TODO: other object types else { - Q_ASSERT_X( false, "XmlLabelCreator::createObjectsNode", "Invalid object type." ); + Q_ASSERT_X( false, "XmlLabelCreator::addObjectsToNode", "Invalid object type." ); } } } diff --git a/glabels/XmlLabelCreator.h b/glabels/XmlLabelCreator.h index a681c82..1447c96 100644 --- a/glabels/XmlLabelCreator.h +++ b/glabels/XmlLabelCreator.h @@ -46,11 +46,13 @@ class XmlLabelCreator : public QObject public: static void writeFile( const LabelModel* label, const QString& fileName ); static void writeBuffer( const LabelModel* label, QString& buffer ); + static void serializeObjects( const QList& objects, QString& buffer ); private: static void createDoc( QDomDocument& doc, const LabelModel* label ); static void createRootNode( const LabelModel* label ); static void createObjectsNode( QDomElement &parent, const LabelModel* label ); + static void addObjectsToNode( QDomElement &parent, const QList& objects ); static void createObjectBoxNode( QDomElement &parent, const LabelModelBoxObject* object ); static void createObjectEllipseNode( QDomElement &parent, const LabelModelEllipseObject* object ); static void createObjectLineNode( QDomElement &parent, const LabelModelLineObject* object ); diff --git a/glabels/XmlLabelParser.cpp b/glabels/XmlLabelParser.cpp index 40f439c..843f39e 100644 --- a/glabels/XmlLabelParser.cpp +++ b/glabels/XmlLabelParser.cpp @@ -115,6 +115,35 @@ XmlLabelParser::readBuffer( const QString& buffer ) } +QList +XmlLabelParser::deserializeObjects( const QString& buffer ) +{ + QList list; + + QDomDocument doc; + QString errorString; + int errorLine; + int errorColumn; + + if ( !doc.setContent( buffer, false, &errorString, &errorLine, &errorColumn ) ) + { + qWarning() << "Error: Parse error at line " << errorLine + << "column " << errorColumn + << ": " << errorString; + return list; + } + + QDomElement root = doc.documentElement(); + if ( root.tagName() != "Glabels-objects" ) + { + qWarning() << "Error: Not a Glabels-objects stream"; + return list; + } + + return parseObjects( root ); +} + + void XmlLabelParser::gunzip( const QByteArray& data, QByteArray& result ) { @@ -219,52 +248,69 @@ XmlLabelParser::parseRootNode( const QDomElement &node ) } -void -XmlLabelParser::parseObjectsNode( const QDomElement &node, LabelModel* label ) +QList +XmlLabelParser::parseObjects( const QDomElement &node ) { + QList list; + for ( QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling() ) { QString tagName = child.toElement().tagName(); if ( tagName == "Object-box" ) { - parseObjectBoxNode( child.toElement(), label ); + list.append( parseObjectBoxNode( child.toElement() ) ); } +#if 0 else if ( tagName == "Object-ellipse" ) { - parseObjectEllipseNode( child.toElement(), label ); + list.append( parseObjectEllipseNode( child.toElement() ) ); } else if ( tagName == "Object-line" ) { - parseObjectLineNode( child.toElement(), label ); + list.append( parseObjectLineNode( child.toElement() ) ); } else if ( tagName == "Object-image" ) { - parseObjectImageNode( child.toElement(), label ); + list.append( parseObjectImageNode( child.toElement() ) ); } else if ( tagName == "Object-barcode" ) { - parseObjectBarcodeNode( child.toElement(), label ); + list.append( parseObjectBarcodeNode( child.toElement() ) ); } else if ( tagName == "Object-text" ) { - parseObjectTextNode( child.toElement(), label ); + list.append( parseObjectTextNode( child.toElement() ) ); } +#endif else if ( !child.isComment() ) { qWarning() << "Unexpected" << node.tagName() << "child:" << tagName; } } + + return list; } void -XmlLabelParser::parseObjectBoxNode( const QDomElement &node, LabelModel* label ) +XmlLabelParser::parseObjectsNode( const QDomElement &node, LabelModel* label ) +{ + QList list = parseObjects( node ); + + foreach ( LabelModelObject* object, list ) + { + label->addObject( object ); + } +} + + +LabelModelBoxObject* +XmlLabelParser::parseObjectBoxNode( const QDomElement &node ) { using namespace glabels; LabelModelBoxObject* object = new LabelModelBoxObject(); - label->addObject( object ); /* position attrs */ @@ -299,36 +345,43 @@ XmlLabelParser::parseObjectBoxNode( const QDomElement &node, LabelModel* label ) /* shadow attrs */ parseShadowAttrs( node, object ); + + return object; } -void -XmlLabelParser::parseObjectEllipseNode( const QDomElement &node, LabelModel* label ) +LabelModelEllipseObject* +XmlLabelParser::parseObjectEllipseNode( const QDomElement &node ) { + return 0; } -void -XmlLabelParser::parseObjectLineNode( const QDomElement &node, LabelModel* label ) +LabelModelLineObject* +XmlLabelParser::parseObjectLineNode( const QDomElement &node ) { + return 0; } -void -XmlLabelParser::parseObjectImageNode( const QDomElement &node, LabelModel* label ) +LabelModelImageObject* +XmlLabelParser::parseObjectImageNode( const QDomElement &node ) { + return 0; } -void -XmlLabelParser::parseObjectBarcodeNode( const QDomElement &node, LabelModel* label ) +LabelModelBarcodeObject* +XmlLabelParser::parseObjectBarcodeNode( const QDomElement &node ) { + return 0; } -void -XmlLabelParser::parseObjectTextNode( const QDomElement &node, LabelModel* label ) +LabelModelTextObject* +XmlLabelParser::parseObjectTextNode( const QDomElement &node ) { + return 0; } diff --git a/glabels/XmlLabelParser.h b/glabels/XmlLabelParser.h index ad985c0..80c53d9 100644 --- a/glabels/XmlLabelParser.h +++ b/glabels/XmlLabelParser.h @@ -46,17 +46,19 @@ class XmlLabelParser : public QObject public: static LabelModel* readFile( const QString& fileName ); static LabelModel* readBuffer( const QString& buffer ); + static QList deserializeObjects( const QString& buffer ); private: static void gunzip( const QByteArray& gzippedData, QByteArray& data ); static LabelModel* parseRootNode( const QDomElement &node ); + static QList parseObjects( const QDomElement &node ); static void parseObjectsNode( const QDomElement &node, LabelModel* label ); - static void parseObjectBoxNode( const QDomElement &node, LabelModel* label ); - static void parseObjectEllipseNode( const QDomElement &node, LabelModel* label ); - static void parseObjectLineNode( const QDomElement &node, LabelModel* label ); - static void parseObjectImageNode( const QDomElement &node, LabelModel* label ); - static void parseObjectBarcodeNode( const QDomElement &node, LabelModel* label ); - static void parseObjectTextNode( const QDomElement &node, LabelModel* label ); + static LabelModelBoxObject* parseObjectBoxNode( const QDomElement &node ); + static LabelModelEllipseObject* parseObjectEllipseNode( const QDomElement &node ); + static LabelModelLineObject* parseObjectLineNode( const QDomElement &node ); + static LabelModelImageObject* parseObjectImageNode( const QDomElement &node ); + static LabelModelBarcodeObject* parseObjectBarcodeNode( const QDomElement &node ); + static LabelModelTextObject* parseObjectTextNode( const QDomElement &node ); static void parseTopLevelSpanNode( const QDomElement &node, LabelModelTextObject* object ); static void parseAffineAttrs( const QDomElement &node, LabelModelObject* object ); static void parseShadowAttrs( const QDomElement &node, LabelModelObject* object );