Skip to content
Permalink
Browse files
Merge pull request #127 from mhugo/copy_paste_styles
[FEATURE] Copy / paste of styles
  • Loading branch information
timlinux committed Apr 17, 2012
2 parents fc373b3 + e1c934a commit 62482954f9a06666a8e79dfac420d841b44a0f0e
Showing with 187 additions and 4 deletions.
  1. +12 −0 src/app/legend/qgslegend.cpp
  2. +73 −1 src/app/qgisapp.cpp
  3. +11 −0 src/app/qgisapp.h
  4. +38 −2 src/app/qgsclipboard.cpp
  5. +31 −0 src/app/qgsclipboard.h
  6. +22 −1 src/ui/qgisapp.ui
@@ -33,6 +33,7 @@
#include "qgsrasterlayer.h"
#include "qgsvectorlayer.h"
#include "qgsgenericprojectionselector.h"
#include "qgsclipboard.h"

#include <QFont>
#include <QDomDocument>
@@ -42,6 +43,7 @@
#include <QMouseEvent>
#include <QPixmap>
#include <QTreeWidgetItem>
#include <QClipboard>

const int AUTOSCROLL_MARGIN = 16;

@@ -697,6 +699,16 @@ void QgsLegend::handleRightClickEvent( QTreeWidgetItem* item, const QPoint& posi
// ends here
}

if ( selectedLayers().length() == 1 )
{
QgisApp* app = QgisApp::instance();
theMenu.addAction( tr( "Copy Style" ), app, SLOT( copyStyle() ) );
if ( app->clipboard()->hasFormat( QGSCLIPBOARD_STYLE_MIME ) )
{
theMenu.addAction( tr( "Paste Style" ), app, SLOT( pasteStyle() ) );
}
}

theMenu.addAction( QgisApp::getThemeIcon( "/folder_new.png" ), tr( "&Add New Group" ), this, SLOT( addGroupToCurrentItem() ) );
theMenu.addAction( QgisApp::getThemeIcon( "/mActionExpandTree.png" ), tr( "&Expand All" ), this, SLOT( expandAll() ) );
theMenu.addAction( QgisApp::getThemeIcon( "/mActionCollapseTree.png" ), tr( "&Collapse All" ), this, SLOT( collapseAll() ) );
@@ -824,6 +824,8 @@ void QgisApp::createActions()
connect( mActionCutFeatures, SIGNAL( triggered() ), this, SLOT( editCut() ) );
connect( mActionCopyFeatures, SIGNAL( triggered() ), this, SLOT( editCopy() ) );
connect( mActionPasteFeatures, SIGNAL( triggered() ), this, SLOT( editPaste() ) );
connect( mActionCopyStyle, SIGNAL( triggered() ), this, SLOT( copyStyle() ) );
connect( mActionPasteStyle, SIGNAL( triggered() ), this, SLOT( pasteStyle() ) );
connect( mActionAddFeature, SIGNAL( triggered() ), this, SLOT( addFeature() ) );
connect( mActionMoveFeature, SIGNAL( triggered() ), this, SLOT( moveFeature() ) );
connect( mActionReshapeFeatures, SIGNAL( triggered() ), this, SLOT( reshapeFeatures() ) );
@@ -4297,7 +4299,6 @@ void QgisApp::editCut( QgsMapLayer * layerContainingSelection )
}
}


void QgisApp::editCopy( QgsMapLayer * layerContainingSelection )
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
@@ -4376,6 +4377,72 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )
}
}

void QgisApp::copyStyle( QgsMapLayer * sourceLayer )
{
QgsMapLayer *selectionLayer = sourceLayer ? sourceLayer : activeLayer();
if ( selectionLayer )
{
QDomImplementation DomImplementation;
QDomDocumentType documentType =
DomImplementation.createDocumentType(
"qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" );
QDomDocument doc( documentType );
QDomElement rootNode = doc.createElement( "qgis" );
rootNode.setAttribute( "version", QString( "%1" ).arg( QGis::QGIS_VERSION ) );
doc.appendChild( rootNode );
QString errorMsg;
if ( !selectionLayer->writeSymbology( rootNode, doc, errorMsg ) )
{
QMessageBox::warning( this,
tr( "Error" ),
tr( "Cannot copy style: %1" )
.arg( errorMsg ),
QMessageBox::Ok );
return;
}
// Copies data in text form as well, so the XML can be pasted into a text editor
clipboard()->setData( QGSCLIPBOARD_STYLE_MIME, doc.toByteArray(), doc.toString() );
// Enables the paste menu element
mActionPasteStyle->setEnabled( true );
}
}

void QgisApp::pasteStyle( QgsMapLayer * destinationLayer )
{
QgsMapLayer *selectionLayer = destinationLayer ? destinationLayer : activeLayer();
if ( selectionLayer )
{
if ( clipboard()->hasFormat( QGSCLIPBOARD_STYLE_MIME ) )
{
QDomDocument doc( "qgis" );
QString errorMsg;
int errorLine, errorColumn;
if ( !doc.setContent ( clipboard()->data( QGSCLIPBOARD_STYLE_MIME ), false, &errorMsg, &errorLine, &errorColumn ) )
{
QMessageBox::information( this,
tr( "Error" ),
tr( "Cannot parse style: %1:%2:%3" )
.arg( errorMsg )
.arg( errorLine )
.arg( errorColumn ),
QMessageBox::Ok );
return;
}
QDomElement rootNode = doc.firstChildElement( "qgis" );
if ( !selectionLayer->readSymbology( rootNode, errorMsg ) )
{
QMessageBox::information( this,
tr( "Error" ),
tr( "Cannot read style: %1" )
.arg( errorMsg ),
QMessageBox::Ok );
return;
}

mMapLegend->refreshLayerSymbology( selectionLayer->id(), false );
}
}
}

void QgisApp::pasteTransformations()
{
@@ -6299,6 +6366,8 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionCutFeatures->setEnabled( false );
mActionCopyFeatures->setEnabled( false );
mActionPasteFeatures->setEnabled( false );
mActionCopyStyle->setEnabled( false );
mActionPasteStyle->setEnabled( false );

mActionUndo->setEnabled( false );
mActionRedo->setEnabled( false );
@@ -6329,6 +6398,9 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
mActionAddToOverview->setEnabled( true );
mActionZoomToLayer->setEnabled( true );

mActionCopyStyle->setEnabled( true );
mActionPasteStyle->setEnabled( clipboard()->hasFormat( QGSCLIPBOARD_STYLE_MIME ) );

/***********Vector layers****************/
if ( layer->type() == QgsMapLayer::VectorLayer )
{
@@ -429,6 +429,17 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
*/
void editPaste( QgsMapLayer * destinationLayer = 0 );

/**
\param sourceLayer The layer where the style will be taken from
(defaults to the active layer on the legend)
*/
void copyStyle( QgsMapLayer * sourceLayer = 0 );
//! copies style on the clipboard to the active layer
/**
\param destinatioLayer The layer that the clipboard will be pasted to
(defaults to the active layer on the legend)
*/
void pasteStyle( QgsMapLayer * destinationLayer = 0 );
void loadOGRSublayers( QString layertype, QString uri, QStringList list );
void loadGDALSublayers( QString uri, QStringList list );

@@ -22,6 +22,7 @@
#include <QStringList>
#include <QClipboard>
#include <QSettings>
#include <QMimeData>

#include "qgsclipboard.h"
#include "qgsfeature.h"
@@ -104,9 +105,9 @@ void QgsClipboard::replaceWithCopyOf( const QgsFieldMap& fields, QgsFeatureList&
// docs). With a Linux X server, ::Clipboard was required.
// The simple solution was to put the text into both clipboards.

// The ::Selection setText() below one may need placing inside so
// #ifdef so that it doesn't get compiled under Windows.
#ifndef Q_OS_WIN
cb->setText( textCopy, QClipboard::Selection );
#endif
cb->setText( textCopy, QClipboard::Clipboard );

QgsDebugMsg( QString( "replaced system clipboard with: %1." ).arg( textCopy ) );
@@ -163,3 +164,38 @@ QgsCoordinateReferenceSystem QgsClipboard::crs()
{
return mCRS;
}

void QgsClipboard::setData( const QString& mimeType, const QByteArray& data, const QString* text )
{
QMimeData *mdata = new QMimeData();
mdata->setData( mimeType, data );
if ( text )
{
mdata->setText( *text );
}
// Transfers ownership to the clipboard object
#ifndef Q_OS_WIN
QApplication::clipboard()->setMimeData( mdata, QClipboard::Selection );
#endif
QApplication::clipboard()->setMimeData( mdata, QClipboard::Clipboard );
}

void QgsClipboard::setData( const QString& mimeType, const QByteArray& data, const QString& text )
{
setData( mimeType, data, &text );
}

void QgsClipboard::setData( const QString& mimeType, const QByteArray& data )
{
setData( mimeType, data, 0 );
}

bool QgsClipboard::hasFormat( const QString& mimeType )
{
return QApplication::clipboard()->mimeData()->hasFormat( mimeType );
}

QByteArray QgsClipboard::data( const QString& mimeType )
{
return QApplication::clipboard()->mimeData()->data( mimeType );
}
@@ -41,6 +41,11 @@
TODO: Make it work
*/

/*
* Constants used to describe copy-paste MIME types
*/
#define QGSCLIPBOARD_STYLE_MIME "application/qgis.style"

class QgsClipboard
{
public:
@@ -98,6 +103,32 @@ class QgsClipboard
*/
QgsCoordinateReferenceSystem crs();

/*
* Stores a MimeData together with a text into the system clipboard
*/
void setData( const QString& mimeType, const QByteArray& data, const QString* text = 0 );
/*
* Stores a MimeData together with a text into the system clipboard
*/
void setData( const QString& mimeType, const QByteArray& data, const QString& text );
/*
* Stores a MimeData into the system clipboard
*/
void setData( const QString& mimeType, const QByteArray& data );
/*
* Stores a text into the system clipboard
*/
void setText( const QString& text );
/*
* Proxy to QMimeData::hasFormat
* Tests whether the system clipboard contains data of a given MIME type
*/
bool hasFormat( const QString& mimeType );
/*
* Retrieve data from the system clipboard.
* No copy is involved, since the return QByteArray is implicitly shared
*/
QByteArray data( const QString& mimeType );
private:

/** QGIS-internal vector feature clipboard.
@@ -17,7 +17,7 @@
<x>0</x>
<y>0</y>
<width>1052</width>
<height>21</height>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="mEditMenu">
@@ -152,6 +152,9 @@
<addaction name="mActionAddLayerSeparator"/>
<addaction name="mActionAddWfsLayer"/>
<addaction name="separator"/>
<addaction name="mActionCopyStyle"/>
<addaction name="mActionPasteStyle"/>
<addaction name="separator"/>
<addaction name="mActionOpenTable"/>
<addaction name="mActionSaveEdits"/>
<addaction name="mActionToggleEditing"/>
@@ -1648,6 +1651,24 @@
<string>Offset Curve</string>
</property>
</action>
<action name="mActionCopyStyle">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionEditCopy.png</normaloff>:/images/themes/default/mActionEditCopy.png</iconset>
</property>
<property name="text">
<string>Copy style</string>
</property>
</action>
<action name="mActionPasteStyle">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/mActionEditPaste.png</normaloff>:/images/themes/default/mActionEditPaste.png</iconset>
</property>
<property name="text">
<string>Paste style</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>

0 comments on commit 6248295

Please sign in to comment.