Skip to content

Commit e60be85

Browse files
committed
Refactor SVG clipboard (paste)
Refactor the paste SVG from clipboard feature. Now works on properly on macOS. Based on work done by @pgilfernandez
1 parent 51c61d4 commit e60be85

File tree

6 files changed

+215
-7
lines changed

6 files changed

+215
-7
lines changed

src/app/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,14 @@ if(${SKIA_STATIC})
401401
endif()
402402
endif()
403403

404+
if(APPLE)
405+
target_link_libraries(
406+
${PROJECT_NAME}
407+
PRIVATE
408+
"-framework AppKit"
409+
)
410+
endif()
411+
404412
if(UNIX AND NOT APPLE)
405413
target_link_libraries(
406414
${PROJECT_NAME}

src/app/GUI/menu.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "memoryhandler.h"
2929
#include "misc/noshortcutaction.h"
3030
#include "dialogs/scenesettingsdialog.h"
31+
#include "system/svgclipboard.h"
3132

3233
#include <QDesktopServices>
3334
#include <QClipboard>
@@ -230,15 +231,10 @@ void MainWindow::setupMenuBar()
230231
mEditMenu->addAction(QIcon::fromTheme("paste"),
231232
tr("Paste from Clipboard"),
232233
[this]() {
233-
const auto clipboard = QGuiApplication::clipboard();
234-
if (clipboard) {
235-
const auto mime = clipboard->mimeData();
236-
qDebug() << mime->formats() << mime->text();
237-
if (mime->hasText() && mime->text().contains("<svg")) {
238-
const QString svg = mime->text();
234+
const QString svg = Ui::SvgClipBoard::getContent();
235+
if (!svg.isEmpty()) {
239236
try { mActions.importClipboard(svg); }
240237
catch (const std::exception& e) { gPrintExceptionCritical(e); }
241-
}
242238
}
243239
}, QKeySequence(tr("Ctrl+Shift+V")));
244240
}

src/ui/CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
cmake_minimum_required(VERSION 3.12)
2121
project(frictionui LANGUAGES CXX)
2222

23+
if(APPLE)
24+
enable_language(OBJCXX)
25+
endif()
26+
2327
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
2428

2529
include(friction-version)
@@ -60,6 +64,7 @@ set(
6064
optimalscrollarena/scrollwidget.cpp
6165
optimalscrollarena/scrollwidgetvisiblepart.cpp
6266
optimalscrollarena/singlewidget.cpp
67+
system/svgclipboard.cpp
6368
widgets/aboutwidget.cpp
6469
widgets/actionbutton.cpp
6570
widgets/alignwidget.cpp
@@ -111,6 +116,10 @@ set(
111116
widgets/wrappernode.cpp
112117
)
113118

119+
if(APPLE)
120+
list(APPEND SOURCES system/svgclipboard.mm)
121+
endif()
122+
114123
set(
115124
HEADERS
116125
ui_global.h
@@ -136,6 +145,7 @@ set(
136145
optimalscrollarena/scrollwidget.h
137146
optimalscrollarena/scrollwidgetvisiblepart.h
138147
optimalscrollarena/singlewidget.h
148+
system/svgclipboard.h
139149
widgets/aboutwidget.h
140150
widgets/actionbutton.h
141151
widgets/alignwidget.h
@@ -217,6 +227,14 @@ target_link_directories(
217227
${SKIA_LIBRARIES_DIRS}
218228
)
219229

230+
if(APPLE)
231+
target_link_libraries(
232+
${PROJECT_NAME}
233+
PRIVATE
234+
"-framework AppKit"
235+
)
236+
endif()
237+
220238
target_link_libraries(
221239
${PROJECT_NAME}
222240
PRIVATE

src/ui/system/svgclipboard.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
#
3+
# Friction - https://friction.graphics
4+
#
5+
# Copyright (c) Ole-André Rodlie and contributors
6+
#
7+
# This program is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, version 3.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
#
19+
# See 'README.md' for more information.
20+
#
21+
*/
22+
23+
#include "svgclipboard.h"
24+
25+
#include <QDomDocument>
26+
#include <QGuiApplication>
27+
#include <QClipboard>
28+
#include <QDebug>
29+
30+
using namespace Friction::Ui;
31+
32+
#ifndef Q_OS_MAC
33+
const QString SvgClipBoard::getContent()
34+
{
35+
return getClipBoard();
36+
}
37+
#endif
38+
39+
const QString SvgClipBoard::getContent(const QMimeData *mime)
40+
{
41+
if (!mime) { return QString(); }
42+
43+
static const QStringList formats{"image/svg+xml",
44+
"public.svg-image",
45+
"com.seriflabs.svg",
46+
"com.adobe.svg",
47+
"com.adobe.illustrator.svg",
48+
"com.adobe.illustrator.svgm",
49+
"text/xml"};
50+
51+
for (const auto &format : formats) {
52+
if (!mime->hasFormat(format)) { continue; }
53+
const QString content = mime->data(format);
54+
if (isSvg(content)) { return content; }
55+
}
56+
57+
if (mime->hasText()) {
58+
const QString text = mime->text();
59+
if (isSvg(text)) { return text; }
60+
}
61+
62+
return QString();
63+
}
64+
65+
bool SvgClipBoard::isSvg(const QString &content)
66+
{
67+
qDebug() << "SVG in clipboard?" << content;
68+
if (content.isEmpty() ||
69+
!content.contains("<svg", Qt::CaseInsensitive)) {
70+
return false;
71+
}
72+
73+
QDomDocument doc;
74+
if (doc.setContent(content)) {
75+
const auto root = doc.documentElement();
76+
return root.tagName().toLower() == "svg" ||
77+
root.localName().toLower() == "svg";
78+
}
79+
return false;
80+
}
81+
82+
const QString SvgClipBoard::getClipBoard()
83+
{
84+
const auto clipboard = QGuiApplication::clipboard();
85+
if (clipboard) { return getContent(clipboard->mimeData()); }
86+
return QString();
87+
}

src/ui/system/svgclipboard.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
#
3+
# Friction - https://friction.graphics
4+
#
5+
# Copyright (c) Ole-André Rodlie and contributors
6+
#
7+
# This program is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, version 3.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
#
19+
# See 'README.md' for more information.
20+
#
21+
*/
22+
23+
#ifndef FRICTION_SVG_CLIPBOARD_H
24+
#define FRICTION_SVG_CLIPBOARD_H
25+
26+
#include "ui_global.h"
27+
28+
#include <QString>
29+
#include <QMimeData>
30+
31+
namespace Friction
32+
{
33+
namespace Ui
34+
{
35+
class UI_EXPORT SvgClipBoard
36+
{
37+
public:
38+
static const QString getContent();
39+
40+
private:
41+
static const QString getContent(const QMimeData *mime);
42+
static bool isSvg(const QString &content);
43+
static const QString getClipBoard();
44+
};
45+
}
46+
}
47+
48+
#endif // FRICTION_SVG_CLIPBOARD_H

src/ui/system/svgclipboard.mm

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
#
3+
# Friction - https://friction.graphics
4+
#
5+
# Copyright (c) Ole-André Rodlie and contributors
6+
#
7+
# This program is free software: you can redistribute it and/or modify
8+
# it under the terms of the GNU General Public License as published by
9+
# the Free Software Foundation, version 3.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
#
19+
# See 'README.md' for more information.
20+
#
21+
*/
22+
23+
#include "svgclipboard.h"
24+
25+
#ifdef Q_OS_MAC
26+
#import <AppKit/AppKit.h>
27+
28+
using namespace Friction::Ui;
29+
30+
const QString SvgClipBoard::getContent()
31+
{
32+
@autoreleasepool{
33+
NSPasteboard* pb = [NSPasteboard generalPasteboard];
34+
if (!pb) { return QString(); }
35+
NSArray<NSString*>* types = @[@"public.svg-image",
36+
@"org.inkscape.svg",
37+
@"com.seriflabs.svg",
38+
@"com.adobe.svg",
39+
@"com.adobe.illustrator.svg",
40+
@"com.adobe.illustrator.svgm",
41+
NSPasteboardTypeString];
42+
for (NSString* type in types) {
43+
NSString* str = [pb stringForType:type];
44+
if (!str) { continue; }
45+
const QString qStr = QString::fromUtf8([str UTF8String]);
46+
if (isSvg(qStr)) { return qStr; }
47+
}
48+
}
49+
return getClipBoard();
50+
}
51+
#endif

0 commit comments

Comments
 (0)