Add cut-copy-paste support for streams

This commit is contained in:
Srivats P 2020-03-06 18:16:23 +05:30
parent fd6f2c2508
commit 43f6959dcc
3 changed files with 148 additions and 7 deletions

View File

@ -22,6 +22,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "portgrouplist.h"
#include "qicon.h"
#include <QMimeData>
const QLatin1String kStreamsMimeType("application/vnd.ostinato.streams");
StreamModel::StreamModel(PortGroupList *p, QObject *parent)
: QAbstractTableModel(parent)
{
@ -223,6 +227,77 @@ QVariant StreamModel::headerData(int section, Qt::Orientation orientation, int r
return QVariant();
}
QStringList StreamModel::mimeTypes() const
{
return QStringList() << kStreamsMimeType;
}
QMimeData* StreamModel::mimeData(const QModelIndexList &indexes) const
{
using ::google::protobuf::uint8;
if (indexes.isEmpty())
return nullptr;
// indexes may include multiple columns for a row - but we are only
// interested in rows 'coz we have a single data for all columns
// XXX: use QMap instead of QSet to keep rows in sorted order
QMap<int, int> rows;
foreach(QModelIndex index, indexes)
rows.insert(index.row(), index.row());
OstProto::StreamConfigList streams;
streams.mutable_port_id()->set_id(mCurrentPort->id());
foreach(int row, rows) {
OstProto::Stream *stream = streams.add_stream();
mCurrentPort->streamByIndex(row)->protoDataCopyInto(*stream);
}
QByteArray data;
data.resize(streams.ByteSize());
streams.SerializeWithCachedSizesToArray((uint8*)data.data());
//qDebug("copy %s", streams.DebugString().c_str());
//TODO: copy DebugString as text/plain?
QMimeData *mimeData = new QMimeData();
mimeData->setData(kStreamsMimeType, data);
return mimeData; // XXX: caller is expected to take ownership and free!
}
bool StreamModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int /*column*/, const QModelIndex &parent)
{
if (!data)
return false;
if (!data->hasFormat(kStreamsMimeType))
return false;
if (action != Qt::CopyAction)
return false;
OstProto::StreamConfigList streamsData;
QByteArray ba(data->data(kStreamsMimeType));
streamsData.ParseFromArray((void*)ba.constData(), ba.size());
//qDebug("paste %s", streamsData.DebugString().c_str());
QList<Stream*> streams;
for (int i = 0; i < streamsData.stream_size(); i++) {
Stream *stream = new Stream;
stream->protoDataCopyFrom(streamsData.stream(i));
streams.append(stream);
}
if ((row < 0) || (row > rowCount(parent)))
row = rowCount(parent);
// Delete rows that we are going to overwrite
if (row < rowCount(parent))
removeRows(row, qMin(rowCount() - row, streams.size()));
return insert(row, streams); // callee will free streams after insert
}
/*!
* Inserts streams before the given row
*

View File

@ -39,12 +39,19 @@ class StreamModel : public QAbstractTableModel
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
QStringList mimeTypes() const;
QMimeData* mimeData(const QModelIndexList &indexes) const;
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent);
bool insert(int row, QList<Stream*> &streams);
bool insertRows (int row, int count,
const QModelIndex & parent = QModelIndex());

View File

@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include <QClipboard>
#include <QKeyEvent>
#include <QMimeData>
#include <QPainter>
class XTableView : public QTableView
@ -46,18 +47,76 @@ protected:
}
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:
void cut()
{
copy();
foreach(QItemSelectionRange range, selectionModel()->selection())
model()->removeRows(range.top(), range.height());
}
void copy()
{
// Copy selection to clipboard (base class copies only current item)
// Selection, by default, is in the order in which items were selected
// - sort them before copying
if (event->matches(QKeySequence::Copy)
&& selectionBehavior() == SelectRows) {
QModelIndexList selected = selectionModel()->selectedIndexes();
std::sort(selected.begin(), selected.end());
qApp->clipboard()->setMimeData(model()->mimeData(selected));
QModelIndexList selected = selectionModel()->selectedIndexes();
if (selected.isEmpty())
return;
std::sort(selected.begin(), selected.end());
QMimeData *mimeData = model()->mimeData(selected);
qApp->clipboard()->setMimeData(mimeData);
qDebug("Copied data in %d format(s) to clipboard",
mimeData->formats().size());
for (int i = 0; i < mimeData->formats().size(); i++) {
qDebug(" %d: %s, %d bytes", i+1,
qPrintable(mimeData->formats().at(i)),
mimeData->data(mimeData->formats().at(i)).size());
}
else
QTableView::keyPressEvent(event);
}
void paste()
{
const QMimeData *mimeData = qApp->clipboard()->mimeData();
if (!mimeData)
return;
if (selectionModel()->hasSelection()
&& selectionModel()->selection().size() > 1) {
qWarning("Cannot paste into multiple(%d) selections",
selectionModel()->selection().size());
return;
}
// If no selection, insert at the end
int row, column;
if (selectionModel()->hasSelection()
&& selectionModel()->selection().size() == 1) {
row = selectionModel()->selection().first().top();
column = selectionModel()->selection().first().left();
} else {
row = model()->rowCount();
column = model()->columnCount();
}
if (model()->canDropMimeData(mimeData, Qt::CopyAction,
row, column, QModelIndex()))
model()->dropMimeData(mimeData, Qt::CopyAction,
row, column, QModelIndex());
}
};