File indexing completed on 2025-02-02 05:43:11

0001 /*
0002     This file is part of the Kasten Framework, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2007-2008, 2011 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "copyascontroller.hpp"
0010 
0011 // lib
0012 #include "copyasdialog.hpp"
0013 // Kasten gui
0014 #include <Kasten/ModelCodecViewManager>
0015 #include <Kasten/DataSelectable>
0016 #include <Kasten/AbstractModelStreamEncoderConfigEditor>
0017 // Kasten core
0018 #include <Kasten/ModelStreamEncodeThread>
0019 #include <Kasten/ModelCodecManager>
0020 #include <Kasten/AbstractModelStreamEncoder>
0021 #include <Kasten/AbstractModelSelection>
0022 #include <Kasten/AbstractModel>
0023 // KF
0024 #include <KXMLGUIClient>
0025 #include <KXMLGUIFactory>
0026 #include <KActionCollection>
0027 #include <KLocalizedString>
0028 #include <KSelectAction>
0029 // Qt
0030 #include <QBuffer>
0031 #include <QMimeData>
0032 #include <QClipboard>
0033 #include <QApplication>
0034 
0035 namespace Kasten {
0036 
0037 CopyAsController::CopyAsController(ModelCodecViewManager* modelCodecViewManager,
0038                                    ModelCodecManager* modelCodecManager,
0039                                    KXMLGUIClient* guiClient)
0040     : mModelCodecViewManager(modelCodecViewManager)
0041     , mModelCodecManager(modelCodecManager)
0042 {
0043     mCopyAsSelectAction = new KSelectAction(QIcon::fromTheme(QStringLiteral("edit-copy")),
0044                                             i18nc("@title:menu", "Copy As"),
0045                                             this);
0046     mCopyAsSelectAction->setToolBarMode(KSelectAction::MenuMode);
0047     connect(mCopyAsSelectAction, qOverload<QAction*>(&KSelectAction::triggered),
0048             this, &CopyAsController::onActionTriggered);
0049 
0050     guiClient->actionCollection()->addAction(QStringLiteral("copy_as"), mCopyAsSelectAction);
0051 
0052     setTargetModel(nullptr);
0053 }
0054 
0055 void CopyAsController::setTargetModel(AbstractModel* model)
0056 {
0057     if (mModel) {
0058         mModel->disconnect(this);
0059     }
0060 
0061     mModel = model ? model->findBaseModelWithInterface<If::DataSelectable*>() : nullptr;
0062     mSelectionControl = mModel ? qobject_cast<If::DataSelectable*>(mModel) : nullptr;
0063 
0064     if (mSelectionControl) {
0065         // TODO: only fill the list on menu call...
0066         connect(mModel, SIGNAL(hasSelectedDataChanged(bool)), SLOT(updateActions()));
0067     }
0068 
0069     updateActions();
0070 }
0071 
0072 void CopyAsController::updateActions()
0073 {
0074     mCopyAsSelectAction->removeAllActions();
0075 
0076     const AbstractModelSelection* selection = mSelectionControl ? mSelectionControl->modelSelection() : nullptr;
0077 
0078     const QVector<AbstractModelStreamEncoder*> encoderList =
0079         mModelCodecManager->encoderList(mModel, selection);
0080     const bool hasEncoders = (!encoderList.isEmpty());
0081 
0082     if (hasEncoders) {
0083         for (auto* encoder : encoderList) {
0084             const QString title = encoder->remoteTypeName();
0085             auto* action = new QAction(title, mCopyAsSelectAction);
0086 
0087             action->setData(QVariant::fromValue(encoder));
0088             mCopyAsSelectAction->addAction(action);
0089         }
0090     } else {
0091         auto* noneAction = new QAction(i18nc("@item There are no encoders.", "Not available."), mCopyAsSelectAction);
0092         noneAction->setEnabled(false);
0093         mCopyAsSelectAction->addAction(noneAction);
0094     }
0095 
0096     // TODO: need a call AbstractModelSelection::isEmpty
0097     mCopyAsSelectAction->setEnabled(mSelectionControl && mSelectionControl->hasSelectedData());
0098 }
0099 
0100 void CopyAsController::onActionTriggered(QAction* action)
0101 {
0102     auto* encoder = action->data().value<AbstractModelStreamEncoder*>();
0103 
0104     const AbstractModelSelection* selection = mSelectionControl->modelSelection();
0105 
0106     AbstractModelStreamEncoderConfigEditor* configEditor =
0107         mModelCodecViewManager->createConfigEditor(encoder);
0108 
0109     if (configEditor) {
0110         auto* dialog = new CopyAsDialog(encoder->remoteTypeName(), configEditor, encoder,
0111                                         QApplication::activeWindow());
0112         dialog->setData(mModel, selection);
0113         connect(dialog, &CopyAsDialog::copyAccepted, this, &CopyAsController::triggerExecution);
0114         dialog->open();
0115         return;
0116     }
0117 
0118     triggerExecution(encoder, selection);
0119 }
0120 
0121 void CopyAsController::triggerExecution(AbstractModelStreamEncoder* encoder,
0122                                         const AbstractModelSelection* selection)
0123 {
0124     QApplication::setOverrideCursor(Qt::WaitCursor);
0125 
0126     QByteArray exportData;
0127     QBuffer exportDataBuffer(&exportData);
0128     exportDataBuffer.open(QIODevice::WriteOnly);
0129 
0130     auto* encodeThread = new ModelStreamEncodeThread(this, &exportDataBuffer, mModel, selection, encoder);
0131     encodeThread->start();
0132     while (!encodeThread->wait(100)) {
0133         QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
0134     }
0135 
0136     delete encodeThread;
0137 
0138     exportDataBuffer.close();
0139 
0140     auto* mimeData = new QMimeData;
0141     mimeData->setData(encoder->remoteClipboardMimeType(), exportData);
0142     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
0143 
0144     QApplication::restoreOverrideCursor();
0145 }
0146 
0147 }
0148 
0149 #include "moc_copyascontroller.cpp"