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