diff --git a/client/clipboardhelper.cpp b/client/clipboardhelper.cpp
index cbaf62f..8b2d46a 100644
--- a/client/clipboardhelper.cpp
+++ b/client/clipboardhelper.cpp
@@ -19,10 +19,19 @@ along with this program. If not, see
#include "clipboardhelper.h"
+#include "xtableview.h"
+
#include
#include
#include
#include
+#include
+
+#if 0 // change 0 to 1 for debug
+#define xDebug(...) qDebug(__VA_ARGS__)
+#else
+#define xDebug(...)
+#endif
ClipboardHelper::ClipboardHelper(QObject *parent)
: QObject(parent)
@@ -43,10 +52,13 @@ ClipboardHelper::ClipboardHelper(QObject *parent)
connect(actionCopy_, SIGNAL(triggered()), SLOT(actionTriggered()));
connect(actionPaste_, SIGNAL(triggered()), SLOT(actionTriggered()));
-#if 0 // FIXME: doesn't work correctly yet
- connect(qGuiApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
- SLOT(updateClipboardActions()));
-#endif
+ connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
+ SLOT(updateCutCopyStatus(QWidget*, QWidget*)));
+
+ connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
+ SLOT(updatePasteStatus()));
+ connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
+ SLOT(updatePasteStatus()));
}
QList ClipboardHelper::actions()
@@ -57,7 +69,7 @@ QList ClipboardHelper::actions()
void ClipboardHelper::actionTriggered()
{
- QWidget *focusWidget = QApplication::focusWidget();
+ QWidget *focusWidget = qApp->focusWidget();
if (!focusWidget)
return;
@@ -66,7 +78,7 @@ void ClipboardHelper::actionTriggered()
QString action = sender()->objectName()
.remove("action").append("()").toLower();
if (focusWidget->metaObject()->indexOfSlot(qPrintable(action)) < 0) {
- qDebug("%s slot not found for object %s:%s ",
+ xDebug("%s slot not found for object %s:%s ",
qPrintable(action),
qPrintable(focusWidget->objectName()),
focusWidget->metaObject()->className());
@@ -78,32 +90,126 @@ void ClipboardHelper::actionTriggered()
Qt::DirectConnection);
}
-void ClipboardHelper::updateActionStatus()
+void ClipboardHelper::updateCutCopyStatus(QWidget *old, QWidget *now)
{
- QWidget *focusWidget = QApplication::focusWidget();
- if (!focusWidget)
- return;
+ xDebug("In %s", __FUNCTION__);
- qDebug("In %s", __FUNCTION__);
-
- const QMetaObject *meta = focusWidget->metaObject();
- // FIXME: we should check if the mimeData's mimeType can be pasted in
- // the focusWidget
- actionPaste_->setEnabled(qGuiApp->clipboard()->mimeData()
- && (meta->indexOfSlot("paste()") >= 0));
-
- bool hasSelection = false;
- if (meta->indexOfProperty("hasSelectedText") >= 0)
- hasSelection |= focusWidget->property("hasSelectedText").toBool();
-
- bool ret = false;
- if (meta->indexOfMethod("hasSelection()") >= 0) {
- if (QMetaObject::invokeMethod(focusWidget, "hasSelection",
- Qt::DirectConnection, Q_RETURN_ARG(bool, ret)))
- hasSelection |= ret;
+ const XTableView *view = dynamic_cast(old);
+ if (view) {
+ disconnect(view->selectionModel(),
+ SIGNAL(selectionChanged(const QItemSelection&,
+ const QItemSelection&)),
+ this,
+ SLOT(focusWidgetSelectionChanged(const QItemSelection&,
+ const QItemSelection&)));
+ disconnect(view->model(), SIGNAL(modelReset()),
+ this, SLOT(focusWidgetModelReset()));
}
- actionCut_->setEnabled(hasSelection && (meta->indexOfSlot("cut") >= 0));
- actionCopy_->setEnabled(hasSelection && (meta->indexOfSlot("copy") >= 0));
+ if (!now) {
+ xDebug("No focus widget to copy from");
+ actionCut_->setEnabled(false);
+ actionCopy_->setEnabled(false);
+ return;
+ }
+
+ const QMetaObject *meta = now->metaObject();
+ if (meta->indexOfSlot("copy()") < 0) {
+ xDebug("Focus Widget (%s) doesn't have a copy slot",
+ qPrintable(now->objectName()));
+ actionCut_->setEnabled(false);
+ actionCopy_->setEnabled(false);
+ return;
+ }
+
+ view = dynamic_cast(now);
+ if (view) {
+ connect(view->selectionModel(),
+ SIGNAL(selectionChanged(const QItemSelection&,
+ const QItemSelection&)),
+ SLOT(focusWidgetSelectionChanged(const QItemSelection&,
+ const QItemSelection&)));
+ connect(view->model(), SIGNAL(modelReset()),
+ this, SLOT(focusWidgetModelReset()));
+ if (!view->hasSelection()) {
+ xDebug("%s doesn't have anything selected to copy",
+ qPrintable(view->objectName()));
+ actionCut_->setEnabled(false);
+ actionCopy_->setEnabled(false);
+ return;
+ }
+ }
+
+ xDebug("%s model can cut: %d", qPrintable(view->objectName()),
+ view->canCut());
+ actionCut_->setEnabled(view->canCut());
+
+ xDebug("%s has a selection and copy slot: copy possible",
+ qPrintable(now->objectName()));
+ actionCopy_->setEnabled(true);
}
+void ClipboardHelper::focusWidgetSelectionChanged(
+ const QItemSelection &selected, const QItemSelection &/*deselected*/)
+{
+ xDebug("In %s", __FUNCTION__);
+
+ // Selection changed in the XTableView that has focus
+ const XTableView *view = dynamic_cast(qApp->focusWidget());
+ xDebug("canCut:%d empty:%d", view->canCut(), selected.indexes().isEmpty());
+ actionCut_->setEnabled(!selected.indexes().isEmpty()
+ && view && view->canCut());
+ actionCopy_->setEnabled(!selected.indexes().isEmpty());
+}
+
+void ClipboardHelper::updatePasteStatus()
+{
+ xDebug("In %s", __FUNCTION__);
+
+ QWidget *focusWidget = qApp->focusWidget();
+ if (!focusWidget) {
+ xDebug("No focus widget to paste into");
+ actionPaste_->setEnabled(false);
+ return;
+ }
+
+ const QMimeData *item = QGuiApplication::clipboard()->mimeData();
+ if (!item || item->formats().isEmpty()) {
+ xDebug("Nothing on clipboard to paste");
+ actionPaste_->setEnabled(false);
+ return;
+ }
+
+ const QMetaObject *meta = focusWidget->metaObject();
+ if (meta->indexOfSlot("paste()") < 0) {
+ xDebug("Focus Widget (%s) doesn't have a paste slot",
+ qPrintable(focusWidget->objectName()));
+ actionPaste_->setEnabled(false);
+ return;
+ }
+
+ const XTableView *view = dynamic_cast(focusWidget);
+ if (view && !view->canPaste(item)) {
+ xDebug("%s cannot accept this item (%s)",
+ qPrintable(view->objectName()),
+ qPrintable(item->formats().join("|")));
+ actionPaste_->setEnabled(false);
+ return;
+ }
+
+ xDebug("%s can accept this item (%s): paste possible",
+ qPrintable(focusWidget->objectName()),
+ qPrintable(item->formats().join("|")));
+ actionPaste_->setEnabled(true);
+}
+
+void ClipboardHelper::focusWidgetModelReset()
+{
+ xDebug("In %s", __FUNCTION__);
+
+ QWidget *focusWidget = qApp->focusWidget();
+ updateCutCopyStatus(focusWidget, focusWidget); // re-eval cut/copy status
+}
+
+#undef xDebug
+
diff --git a/client/clipboardhelper.h b/client/clipboardhelper.h
index e43be4f..0c2c8fe 100644
--- a/client/clipboardhelper.h
+++ b/client/clipboardhelper.h
@@ -24,6 +24,7 @@ along with this program. If not, see
#include
class QAction;
+class QItemSelection;
class ClipboardHelper : public QObject
{
@@ -35,7 +36,11 @@ public:
private slots:
void actionTriggered();
- void updateActionStatus();
+ void updateCutCopyStatus(QWidget *old, QWidget *now);
+ void focusWidgetSelectionChanged(const QItemSelection &selected,
+ const QItemSelection &deselected);
+ void focusWidgetModelReset();
+ void updatePasteStatus();
private:
QAction *actionCut_{nullptr};
diff --git a/client/logsmodel.cpp b/client/logsmodel.cpp
index b23feb5..1aa8600 100644
--- a/client/logsmodel.cpp
+++ b/client/logsmodel.cpp
@@ -109,6 +109,11 @@ QVariant LogsModel::data(const QModelIndex &index, int role) const
return QVariant();
}
+Qt::DropActions LogsModel::supportedDropActions() const
+{
+ return Qt::IgnoreAction; // read-only model, doesn't accept any data
+}
+
QStringList LogsModel::mimeTypes() const
{
return QStringList() << "text/plain";
diff --git a/client/logsmodel.h b/client/logsmodel.h
index dd27e37..8c7c937 100644
--- a/client/logsmodel.h
+++ b/client/logsmodel.h
@@ -43,6 +43,8 @@ public:
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ Qt::DropActions supportedDropActions() const;
QStringList mimeTypes() const;
QMimeData* mimeData(const QModelIndexList &indexes) const;
diff --git a/client/xtableview.h b/client/xtableview.h
index 0f17496..2f87f2b 100644
--- a/client/xtableview.h
+++ b/client/xtableview.h
@@ -22,6 +22,9 @@ along with this program. If not, see
#include
+#include "devicegroupmodel.h"
+#include "streammodel.h"
+
#include
#include
#include
@@ -36,36 +39,33 @@ public:
XTableView(QWidget *parent) : QTableView(parent) {}
virtual ~XTableView() {}
-#if 0
- Q_INVOKABLE bool hasSelection() const
+ void setModel(QAbstractItemModel *model)
+ {
+ // XXX: yes, this is hacky; but there's no way to figure out
+ // if a model allows removeRows() or not
+ if (dynamic_cast(model)
+ || dynamic_cast(model))
+ _modelAllowsRemove = true;
+ else
+ _modelAllowsRemove = false;
+
+ QTableView::setModel(model);
+ }
+
+ bool hasSelection() const
{
return !selectionModel()->selectedIndexes().isEmpty();
}
-#endif
-protected:
- virtual void paintEvent(QPaintEvent *event)
+ bool canCut() const
{
- if (!model()->hasChildren()) {
- QPainter painter(viewport());
- style()->drawItemText(&painter, viewport()->rect(),
- layoutDirection() | Qt::AlignCenter, palette(),
- true, whatsThis(), QPalette::WindowText);
- }
- else
- QTableView::paintEvent(event);
+ return _modelAllowsRemove;
}
- virtual void keyPressEvent(QKeyEvent *event)
+ bool canPaste(const QMimeData *data) const
{
- if (event->matches(QKeySequence::Cut)) {
- cut();
- } else if (event->matches(QKeySequence::Copy)) {
- copy();
- } else if (event->matches(QKeySequence::Paste)) {
- paste();
- } else
- QTableView::keyPressEvent(event);
+ return model()->canDropMimeData(data, Qt::CopyAction,
+ 0, 0, QModelIndex());
}
public slots:
@@ -102,7 +102,7 @@ public slots:
{
const QMimeData *mimeData = qApp->clipboard()->mimeData();
- if (!mimeData)
+ if (!mimeData || mimeData->formats().isEmpty())
return;
if (selectionModel()->hasSelection()
@@ -128,6 +128,34 @@ public slots:
model()->dropMimeData(mimeData, Qt::CopyAction,
row, column, QModelIndex());
}
+
+protected:
+ virtual void paintEvent(QPaintEvent *event)
+ {
+ if (!model()->hasChildren()) {
+ QPainter painter(viewport());
+ style()->drawItemText(&painter, viewport()->rect(),
+ layoutDirection() | Qt::AlignCenter, palette(),
+ true, whatsThis(), QPalette::WindowText);
+ }
+ else
+ QTableView::paintEvent(event);
+ }
+
+ virtual void keyPressEvent(QKeyEvent *event)
+ {
+ if (event->matches(QKeySequence::Cut)) {
+ cut();
+ } else if (event->matches(QKeySequence::Copy)) {
+ copy();
+ } else if (event->matches(QKeySequence::Paste)) {
+ paste();
+ } else
+ QTableView::keyPressEvent(event);
+ }
+
+private:
+ bool _modelAllowsRemove{false};
};
#endif