1 /*
2 This file is part of the Kasten Framework, made within the KDE community.
3
4 SPDX-FileCopyrightText: 2006-2008 Friedrich W. H. Kossebau <kossebau@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8
9 #include "clipboardcontroller.hpp"
10
11 // Kasten gui
12 #include <Kasten/DataSelectable>
13 #include <Kasten/SelectedDataWriteable>
14 // Kasten core
15 #include <Kasten/AbstractModel>
16 // KF
17 #include <KXMLGUIClient>
18 #include <KLocalizedString>
19 #include <KActionCollection>
20 #include <KStandardAction>
21 // Qt
22 #include <QClipboard>
23 #include <QApplication>
24 #include <QMimeData>
25 #include <QAction>
26
27 namespace Kasten {
28
ClipboardController(KXMLGUIClient * guiClient)29 ClipboardController::ClipboardController(KXMLGUIClient* guiClient)
30 {
31 mCutAction = KStandardAction::cut( this, &ClipboardController::cut, this);
32 mCopyAction = KStandardAction::copy( this, &ClipboardController::copy, this);
33 mPasteAction = KStandardAction::paste(this, &ClipboardController::paste, this);
34
35 guiClient->actionCollection()->addActions({
36 mCutAction,
37 mCopyAction,
38 mPasteAction,
39 });
40
41 connect(QApplication::clipboard(), &QClipboard::dataChanged,
42 this, &ClipboardController::onClipboardDataChanged);
43
44 setTargetModel(nullptr);
45 }
46
setTargetModel(AbstractModel * model)47 void ClipboardController::setTargetModel(AbstractModel* model)
48 {
49 if (mModel) {
50 mModel->disconnect(this);
51 }
52
53 mModel = model ? model->findBaseModelWithInterface<If::DataSelectable*>() : nullptr;
54 mSelectionControl = mModel ? qobject_cast<If::DataSelectable*>(mModel) : nullptr;
55
56 if (mSelectionControl) {
57 connect(mModel, SIGNAL(hasSelectedDataChanged(bool)), SLOT(onHasSelectedDataChanged(bool)));
58
59 mMimeDataControl = qobject_cast<If::SelectedDataWriteable*>(mModel);
60 if (mMimeDataControl) {
61 connect(mModel, &AbstractModel::readOnlyChanged,
62 this, &ClipboardController::onReadOnlyChanged);
63 }
64
65 mCutControl = nullptr;
66 const auto children = mModel->findChildren<QObject*>(QString(), Qt::FindDirectChildrenOnly);
67 for (auto* child : children) {
68 mCutControl = qobject_cast<If::SelectedDataCutable*>(child);
69 if (mCutControl) {
70 connect(child, SIGNAL(canCutSelectedDataChanged(bool)),
71 this, SLOT(onCanCutSelectedDataChanged(bool)));
72 break;
73 }
74 }
75 } else {
76 mMimeDataControl = nullptr;
77 mCutControl = nullptr;
78 }
79
80 const QMimeData* mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
81
82 const bool hasSelectedData = mSelectionControl ? mSelectionControl->hasSelectedData() : false;
83 const bool isWriteable = (mMimeDataControl && !mModel->isReadOnly());
84 const bool isCutable = (hasSelectedData && isWriteable && (!mCutControl || mCutControl->canCutSelectedData()));
85 const bool isPastable = isWriteable && !mimeData->formats().isEmpty() && mMimeDataControl->canReadData(mimeData);
86
87 mCopyAction->setEnabled(hasSelectedData);
88 mCutAction->setEnabled(isCutable);
89 mPasteAction->setEnabled(isPastable);
90 }
91
cut()92 void ClipboardController::cut()
93 {
94 QMimeData* data = mMimeDataControl->cutSelectedData();
95 if (!data) {
96 return;
97 }
98
99 QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard);
100 }
101
copy()102 void ClipboardController::copy()
103 {
104 QMimeData* data = mSelectionControl->copySelectedData();
105 if (!data) {
106 return;
107 }
108
109 QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard);
110 }
111
paste()112 void ClipboardController::paste()
113 {
114 const QMimeData* data = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
115
116 mMimeDataControl->insertData(data);
117 }
118
onReadOnlyChanged(bool isReadOnly)119 void ClipboardController::onReadOnlyChanged(bool isReadOnly)
120 {
121 const QMimeData* mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
122
123 const bool hasSelectedData = mSelectionControl ? mSelectionControl->hasSelectedData() : false;
124 const bool isWriteable = !isReadOnly;
125 // backward compatibility: assume true by default
126 const bool canCutSelectedData = mCutControl ? mCutControl->canCutSelectedData() : true;
127 const bool isCutable = (hasSelectedData && isWriteable && canCutSelectedData);
128 const bool isPastable = isWriteable && !mimeData->formats().isEmpty() && mMimeDataControl->canReadData(mimeData);
129
130 mCutAction->setEnabled(isCutable);
131 mPasteAction->setEnabled(isPastable);
132 }
133
onHasSelectedDataChanged(bool hasSelectedData)134 void ClipboardController::onHasSelectedDataChanged(bool hasSelectedData)
135 {
136 const bool isWriteable = (mMimeDataControl && !mModel->isReadOnly());
137 // backward compatibility: assume true by default
138 const bool canCutSelectedData = mCutControl ? mCutControl->canCutSelectedData() : true;
139 const bool isCutable = (hasSelectedData && isWriteable && canCutSelectedData);
140
141 mCopyAction->setEnabled(hasSelectedData);
142 mCutAction->setEnabled(isCutable);
143 }
144
onCanCutSelectedDataChanged(bool canCutSelectedData)145 void ClipboardController::onCanCutSelectedDataChanged(bool canCutSelectedData)
146 {
147 const bool hasSelectedData = mSelectionControl ? mSelectionControl->hasSelectedData() : false;
148 const bool isWriteable = (mMimeDataControl && !mModel->isReadOnly());
149 const bool isCutable = (hasSelectedData && isWriteable && canCutSelectedData);
150
151 mCutAction->setEnabled(isCutable);
152 }
153
onClipboardDataChanged()154 void ClipboardController::onClipboardDataChanged()
155 {
156 const QMimeData* mimeData = QApplication::clipboard()->mimeData(QClipboard::Clipboard);
157
158 const bool isWriteable = (mMimeDataControl && !mModel->isReadOnly());
159 const bool isPastable = isWriteable && !mimeData->formats().isEmpty() && mMimeDataControl->canReadData(mimeData);
160
161 mPasteAction->setEnabled(isPastable);
162 }
163
164 }
165