Skip to content

Commit

Permalink
feat: support copy/paste for DCrumbEdit
Browse files Browse the repository at this point in the history
Change-Id: Ib4886d4757792968a3608f996e44d03aa3a481c8
  • Loading branch information
zccrs committed Dec 20, 2017
1 parent 04e2173 commit 90a7388
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 13 deletions.
194 changes: 183 additions & 11 deletions src/widgets/dcrumbedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
#include <QTextBlock>
#include <QStyleOptionFrame>
#include <QMouseEvent>
#include <QMimeData>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>

DWIDGET_BEGIN_NAMESPACE
Expand Down Expand Up @@ -190,6 +194,57 @@ class DCrumbEditPrivate : public DCORE_NAMESPACE::DObjectPrivate
return true;
}

QByteArray crumbMapToData(const QList<DCrumbTextFormat> &list) const
{
QJsonArray array;

for (const DCrumbTextFormat &f : list) {
if (!f.isValid() || f.isEmpty())
continue;

QJsonObject object;
object["text"] = f.text();

if (f.tagColor().isValid())
object["tag color"] = f.tagColor().name();

array.append(QJsonValue(object));
}

QJsonDocument document;
document.setArray(array);

return document.toJson(QJsonDocument::Compact);
}

QList<DCrumbTextFormat> crumbListFromData(const QByteArray &format) const
{
const QJsonDocument &document = QJsonDocument::fromJson(format);
const QJsonArray &array = document.array();

QList<DCrumbTextFormat> list;

D_QC(DCrumbEdit);

for (const QJsonValue &v : array) {
const QJsonObject &object = v.toObject();

if (object.isEmpty())
continue;

DCrumbTextFormat format = q->makeTextFormat();

format.setText(object["text"].toString());

if (object.contains("tag color"))
format.setTagColor(QColor(object["tag color"].toString()));

list << format;
}

return list;
}

void _q_onDocumentLayoutChanged()
{
D_Q(DCrumbEdit);
Expand Down Expand Up @@ -228,6 +283,7 @@ class DCrumbEditPrivate : public DCORE_NAMESPACE::DObjectPrivate
int last_pos = 0;

cursor.setPosition(0);
formatList.clear();

while (!cursor.atEnd()) {
cursor.setPosition(last_pos + 1);
Expand All @@ -244,6 +300,7 @@ class DCrumbEditPrivate : public DCORE_NAMESPACE::DObjectPrivate

if (!text.isEmpty()) {
crumbList << text;
formatList << text;

if (!formats.contains(text)) {
formats[text] = format;
Expand Down Expand Up @@ -271,6 +328,7 @@ class DCrumbEditPrivate : public DCORE_NAMESPACE::DObjectPrivate
CrumbObjectInterface *object;
int objectType;
bool crumbReadOnly = false;
QStringList formatList;
QMap<QString, DCrumbTextFormat> formats;
};

Expand Down Expand Up @@ -346,31 +404,48 @@ bool DCrumbEdit::insertCrumb(const DCrumbTextFormat &format, int pos)

QTextCursor cursor = textCursor();

if (pos < 0)
cursor.movePosition(QTextCursor::End);
else
if (pos >= 0)
cursor.setPosition(pos);

cursor.insertText(QString(QChar::ObjectReplacementCharacter), format);

return true;
}

void DCrumbEdit::insertCrumb(const QString &text, int pos)
bool DCrumbEdit::appendCrumb(const DCrumbTextFormat &format)
{
if (format.text().isEmpty())
return false;

D_DC(DCrumbEdit);

if (!d->canAddCrumb(format.text()))
return false;

QTextCursor cursor = textCursor();

cursor.movePosition(QTextCursor::End);
cursor.insertText(QString(QChar::ObjectReplacementCharacter), format);

return true;
}

bool DCrumbEdit::insertCrumb(const QString &text, int pos)
{
DCrumbTextFormat format = makeTextFormat();

format.setText(text);
insertCrumb(format, pos);

return insertCrumb(format, pos);
}

void DCrumbEdit::appendCrumb(const QString &text)
bool DCrumbEdit::appendCrumb(const QString &text)
{
QTextCursor crusor = textCursor();
DCrumbTextFormat format = makeTextFormat();

format.setText(text);

crusor.movePosition(QTextCursor::End);
setTextCursor(crusor);
insertCrumb(text);
return appendCrumb(text);
}

bool DCrumbEdit::containCrumb(const QString &text) const
Expand All @@ -384,7 +459,7 @@ QStringList DCrumbEdit::crumbList() const
{
D_DC(DCrumbEdit);

return d->formats.keys();
return d->formatList;
}

DCrumbTextFormat DCrumbEdit::crumbTextFormat(const QString &text) const
Expand Down Expand Up @@ -531,6 +606,103 @@ void DCrumbEdit::focusOutEvent(QFocusEvent *event)
QTextEdit::focusOutEvent(event);
}

QMimeData *DCrumbEdit::createMimeDataFromSelection() const
{
D_DC(DCrumbEdit);

QMimeData *mime = new QMimeData();
const QTextCursor &cursor = textCursor();
QStringList::const_iterator current_format = d->formatList.constBegin();

const QString &plain_text = toPlainText();
const QString &selected_text = cursor.selectedText();
int pos = -1;
QString text;
QList<DCrumbTextFormat> format_list;

for (const QChar &ch : plain_text) {
++pos;

if (pos >= cursor.selectionEnd())
break;

if (ch == QChar::ObjectReplacementCharacter) {
if (pos < cursor.selectionStart()) {
++current_format;
continue;
}

const DCrumbTextFormat &f = d->formats.value(*current_format);

++current_format;

if (f.text().isEmpty())
continue;

if (!text.isEmpty())
text.append(" ").append(f.text());
else
text.append(f.text());

format_list << f;
} else if (pos < cursor.selectionStart()) {
text.append(ch);
}
}

mime->setText(text);
mime->setData("deepin/dtkwidget-DCrumbTextFormat-data", selected_text.toUtf8());
mime->setData("deepin/dtkwidget-DCrumbTextFormat-list", d->crumbMapToData(format_list));

return mime;
}

bool DCrumbEdit::canInsertFromMimeData(const QMimeData *source) const
{
if (source->hasFormat("deepin/dtkwidget-DCrumbTextFormat-data"))
return true;

return QTextEdit::canInsertFromMimeData(source);
}

void DCrumbEdit::insertFromMimeData(const QMimeData *source)
{
if (!source->hasFormat("deepin/dtkwidget-DCrumbTextFormat-data"))
QTextEdit::insertFromMimeData(source);

const QString &plain_text = QString::fromUtf8(source->data("deepin/dtkwidget-DCrumbTextFormat-data"));

if (plain_text.isEmpty())
return;

D_DC(DCrumbEdit);

const QList<DCrumbTextFormat> &list = d->crumbListFromData(source->data("deepin/dtkwidget-DCrumbTextFormat-list"));
QList<DCrumbTextFormat>::const_iterator current_format = list.constBegin();
QString text;

textCursor().beginEditBlock();

for (const QChar &ch : plain_text) {
if (ch == QChar::ObjectReplacementCharacter) {
if (!text.isEmpty()) {
textCursor().insertText(text);
text.clear();
}

insertCrumb(*current_format);
++current_format;
} else {
text.append(ch);
}
}

if (!text.isEmpty())
textCursor().insertText(text);

textCursor().endEditBlock();
}

DWIDGET_END_NAMESPACE

#include "moc_dcrumbedit.cpp"
Expand Down
9 changes: 7 additions & 2 deletions src/widgets/dcrumbedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ class DCrumbEdit : public QTextEdit, public DCORE_NAMESPACE::DObject
explicit DCrumbEdit(QWidget *parent = 0);

bool insertCrumb(const DCrumbTextFormat &format, int pos = -1);
void insertCrumb(const QString &text, int pos = -1);
void appendCrumb(const QString &text);
bool insertCrumb(const QString &text, int pos = -1);
bool appendCrumb(const DCrumbTextFormat &format);
bool appendCrumb(const QString &text);

bool containCrumb(const QString &text) const;
QStringList crumbList() const;
Expand All @@ -107,6 +108,10 @@ public Q_SLOTS:
void mouseDoubleClickEvent(QMouseEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;

QMimeData *createMimeDataFromSelection() const override;
bool canInsertFromMimeData(const QMimeData *source) const override;
void insertFromMimeData(const QMimeData *source) override;

private:
using QTextEdit::setDocument;
using QTextEdit::document;
Expand Down

0 comments on commit 90a7388

Please sign in to comment.