File indexing completed on 2023-09-24 06:04:26
0001 /** 0002 * SPDX-FileCopyrightText: (C) 2003 Sébastien Laoût <slaout@linux62.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "notedrag.h" 0008 0009 #include <QApplication> 0010 #include <QDesktopWidget> //For qApp->desktop() 0011 #include <QtCore/QBuffer> 0012 #include <QtCore/QDir> 0013 #include <QtCore/QList> 0014 #include <QtCore/QMimeData> 0015 #include <QtCore/QTextCodec> 0016 #include <QtCore/QTextStream> 0017 #include <QtGui/QDragEnterEvent> 0018 #include <QtGui/QPainter> 0019 #include <QtGui/QPixmap> 0020 0021 #include <KIO/CopyJob> 0022 0023 #include "basketscene.h" 0024 #include "global.h" 0025 #include "notefactory.h" 0026 #include "noteselection.h" 0027 #include "tools.h" 0028 0029 /** NoteDrag */ 0030 0031 const char *NoteDrag::NOTE_MIME_STRING = "application/x-basket-note"; 0032 QList<Note *> NoteDrag::selectedNotes; 0033 0034 void NoteDrag::createAndEmptyCuttingTmpFolder() 0035 { 0036 Tools::deleteRecursively(Global::tempCutFolder()); 0037 QDir dir; 0038 dir.mkdir(Global::tempCutFolder()); 0039 } 0040 0041 QDrag *NoteDrag::dragObject(NoteSelection *noteList, bool cutting, QWidget *source) 0042 { 0043 if (noteList->count() <= 0) 0044 return nullptr; 0045 0046 QDrag *multipleDrag = new QDrag(source); 0047 0048 // The MimeSource: 0049 QMimeData *mimeData = new QMimeData; 0050 0051 // Make sure the temporary folder exists and is empty (we delete previously moved file(s) (if exists) 0052 // since we override the content of the clipboard and previous file willn't be accessable anymore): 0053 createAndEmptyCuttingTmpFolder(); 0054 0055 // The "Native Format" Serialization: 0056 QBuffer buffer; 0057 if (buffer.open(QIODevice::WriteOnly)) { 0058 QDataStream stream(&buffer); 0059 // First append a pointer to the basket: 0060 stream << (quint64)(noteList->firstStacked()->note->basket()); 0061 0062 // And finally the notes themselves: 0063 serializeNotes(noteList, stream, cutting); 0064 // Append the object: 0065 buffer.close(); 0066 mimeData->setData(NOTE_MIME_STRING, buffer.buffer()); 0067 } 0068 0069 // The "Other Flavors" Serialization: 0070 serializeText(noteList, mimeData); 0071 serializeHtml(noteList, mimeData); 0072 serializeImage(noteList, mimeData); 0073 serializeLinks(noteList, mimeData, cutting); 0074 0075 // The Alternate Flavors: 0076 if (noteList->count() == 1) 0077 noteList->firstStacked()->note->content()->addAlternateDragObjects(mimeData); 0078 0079 multipleDrag->setMimeData(mimeData); 0080 0081 // If it is a drag, and not a copy/cut, add the feedback pixmap: 0082 if (source) 0083 setFeedbackPixmap(noteList, multipleDrag); 0084 0085 return multipleDrag; 0086 } 0087 0088 void NoteDrag::serializeNotes(NoteSelection *noteList, QDataStream &stream, bool cutting) 0089 { 0090 for (NoteSelection *node = noteList; node; node = node->next) { 0091 stream << (quint64)(node->note); 0092 if (node->firstChild) { 0093 stream << (quint64)(NoteType::Group) << (quint64)(node->note->groupWidth()) << (quint64)(node->note->isFolded()); 0094 serializeNotes(node->firstChild, stream, cutting); 0095 } else { 0096 NoteContent *content = node->note->content(); 0097 stream << (quint64)(content->type()) << (quint64)(node->note->groupWidth()); 0098 // Serialize file name, and move the file to a temporary place if the note is to be cut. 0099 // If note does not have file name, we append empty string to be able to easily decode the notes later: 0100 stream << content->fileName(); 0101 if (content->shouldSerializeFile()) { 0102 if (cutting) { 0103 // Move file in a temporary place: 0104 QString fullPath = Global::tempCutFolder() + Tools::fileNameForNewFile(content->fileName(), Global::tempCutFolder()); 0105 KIO::move(QUrl::fromLocalFile(content->fullPath()), QUrl::fromLocalFile(fullPath), KIO::HideProgressInfo); 0106 node->fullPath = fullPath; 0107 stream << fullPath; 0108 } else 0109 stream << content->fullPath(); 0110 } else 0111 stream << QString(QString()); 0112 stream << content->note()->addedDate() << content->note()->lastModificationDate(); 0113 content->serialize(stream); 0114 State::List states = node->note->states(); 0115 for (State::List::Iterator it = states.begin(); it != states.end(); ++it) 0116 stream << (quint64)(*it); 0117 stream << (quint64)0; 0118 } 0119 } 0120 stream << (quint64)0; // Mark the end of the notes in this group/hierarchy. 0121 } 0122 0123 void NoteDrag::serializeText(NoteSelection *noteList, QMimeData* mimeData) 0124 { 0125 QString textEquivalent; 0126 QString text; 0127 for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) { 0128 text = node->note->toText(node->fullPath); // note->toText() and not note->content()->toText() because the first one will also export the tags as text. 0129 if (!text.isEmpty()) 0130 textEquivalent += (!textEquivalent.isEmpty() ? "\n" : QString()) + text; 0131 } 0132 if (!textEquivalent.isEmpty()) { 0133 mimeData->setText(textEquivalent); 0134 } 0135 } 0136 0137 void NoteDrag::serializeHtml(NoteSelection *noteList, QMimeData* mimeData) 0138 { 0139 QString htmlEquivalent; 0140 QString html; 0141 for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) { 0142 html = node->note->content()->toHtml(QString(), node->fullPath); 0143 if (!html.isEmpty()) 0144 htmlEquivalent += (!htmlEquivalent.isEmpty() ? "<br>\n" : QString()) + html; 0145 } 0146 if (!htmlEquivalent.isEmpty()) { 0147 // Add HTML flavour: 0148 mimeData->setHtml(htmlEquivalent); 0149 0150 // But also QTextEdit flavour, to be able to paste several notes to a text edit: 0151 QByteArray byteArray = ("<!--StartFragment--><p>" + htmlEquivalent).toLocal8Bit(); 0152 mimeData->setData("application/x-qrichtext", byteArray); 0153 } 0154 } 0155 0156 void NoteDrag::serializeImage(NoteSelection *noteList, QMimeData* mimeData) 0157 { 0158 QList<QPixmap> pixmaps; 0159 QPixmap pixmap; 0160 for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) { 0161 pixmap = node->note->content()->toPixmap(); 0162 if (!pixmap.isNull()) 0163 pixmaps.append(pixmap); 0164 } 0165 if (!pixmaps.isEmpty()) { 0166 QPixmap pixmapEquivalent; 0167 if (pixmaps.count() == 1) 0168 pixmapEquivalent = pixmaps.first(); 0169 else { 0170 // Search the total size: 0171 int height = 0; 0172 int width = 0; 0173 for (QList<QPixmap>::iterator it = pixmaps.begin(); it != pixmaps.end(); ++it) { 0174 height += (*it).height(); 0175 if ((*it).width() > width) 0176 width = (*it).width(); 0177 } 0178 // Create the image by painting all image into one big image: 0179 pixmapEquivalent = QPixmap(width, height); 0180 pixmapEquivalent.fill(Qt::white); 0181 QPainter painter(&pixmapEquivalent); 0182 height = 0; 0183 for (QList<QPixmap>::iterator it = pixmaps.begin(); it != pixmaps.end(); ++it) { 0184 painter.drawPixmap(0, height, *it); 0185 height += (*it).height(); 0186 } 0187 } 0188 mimeData->setImageData(pixmapEquivalent.toImage()); 0189 } 0190 } 0191 0192 void NoteDrag::serializeLinks(NoteSelection *noteList, QMimeData* mimeData, bool cutting) 0193 { 0194 QList<QUrl> urls; 0195 QStringList titles; 0196 QUrl url; 0197 QString title; 0198 for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) { 0199 node->note->content()->toLink(&url, &title, node->fullPath); 0200 if (!url.isEmpty()) { 0201 urls.append(url); 0202 titles.append(title); 0203 } 0204 } 0205 if (!urls.isEmpty()) { 0206 // First, the standard text/uri-list MIME format: 0207 mimeData->setUrls(urls); 0208 0209 // Then, also provide it in the Mozilla proprietary format (that also allow to add titles to URLs): 0210 // A version for Mozilla applications (convert to "theUrl\ntheTitle", into UTF-16): 0211 // FIXME: Does Mozilla support the drag of several URLs at once? 0212 // FIXME: If no, only provide that if there is only ONE URL. 0213 QString xMozUrl; 0214 for (int i = 0; i < urls.count(); ++i) 0215 xMozUrl += (xMozUrl.isEmpty() ? QString() : "\n") + urls[i].toDisplayString() + '\n' + titles[i]; 0216 /* Code for only one: =============== 0217 xMozUrl = note->title() + "\n" + note->url().toDisplayString();*/ 0218 QByteArray baMozUrl; 0219 QTextStream stream(baMozUrl, QIODevice::WriteOnly); 0220 0221 // It's UTF16 (aka UCS2), but with the first two order bytes 0222 // stream.setEncoding(QTextStream::RawUnicode); // It's UTF16 (aka UCS2), but with the first two order bytes 0223 // FIXME: find out if this is really equivalent, as https://doc.qt.io/archives/3.3/qtextstream.html pretends 0224 stream.setCodec("UTF-16"); 0225 0226 stream << xMozUrl; 0227 0228 mimeData->setData("text/x-moz-url", baMozUrl); 0229 0230 if (cutting) { 0231 QByteArray arrayCut; 0232 arrayCut.resize(2); 0233 arrayCut[0] = '1'; 0234 arrayCut[1] = 0; 0235 mimeData->setData("application/x-kde-cutselection", arrayCut); 0236 } 0237 } 0238 } 0239 0240 void NoteDrag::setFeedbackPixmap(NoteSelection *noteList, QDrag *multipleDrag) 0241 { 0242 QPixmap pixmap = feedbackPixmap(noteList); 0243 if (!pixmap.isNull()) { 0244 multipleDrag->setPixmap(pixmap); 0245 multipleDrag->setHotSpot(QPoint(-8, -8)); 0246 } 0247 } 0248 0249 QPixmap NoteDrag::feedbackPixmap(NoteSelection *noteList) 0250 { 0251 if (noteList == nullptr) 0252 return QPixmap(); 0253 0254 static const int MARGIN = 2; 0255 static const int SPACING = 1; 0256 0257 QColor textColor = noteList->firstStacked()->note->basket()->textColor(); 0258 QColor backgroundColor = noteList->firstStacked()->note->basket()->backgroundColor().darker(NoteContent::FEEDBACK_DARKING); 0259 0260 QList<QPixmap> pixmaps; 0261 QList<QColor> backgrounds; 0262 QList<bool> spaces; 0263 QPixmap pixmap; 0264 int height = 0; 0265 int width = 0; 0266 int i = 0; 0267 bool elipsisImage = false; 0268 QColor bgColor; 0269 bool needSpace; 0270 for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked(), ++i) { 0271 if (elipsisImage) { 0272 pixmap = QPixmap(7, 2); 0273 pixmap.fill(backgroundColor); 0274 QPainter painter(&pixmap); 0275 painter.setPen(textColor); 0276 painter.drawPoint(1, 1); 0277 painter.drawPoint(3, 1); 0278 painter.drawPoint(5, 1); 0279 painter.end(); 0280 bgColor = node->note->basket()->backgroundColor(); 0281 needSpace = false; 0282 } else { 0283 pixmap = node->note->content()->feedbackPixmap(/*maxWidth=*/qApp->desktop()->width() / 2, /*maxHeight=*/96); 0284 bgColor = node->note->backgroundColor(); 0285 needSpace = node->note->content()->needSpaceForFeedbackPixmap(); 0286 } 0287 if (!pixmap.isNull()) { 0288 if (pixmap.width() > width) 0289 width = pixmap.width(); 0290 pixmaps.append(pixmap); 0291 backgrounds.append(bgColor); 0292 spaces.append(needSpace); 0293 height += (i > 0 && needSpace ? 1 : 0) + pixmap.height() + SPACING + (needSpace ? 1 : 0); 0294 if (elipsisImage) 0295 break; 0296 if (height > qApp->desktop()->height() / 2) 0297 elipsisImage = true; 0298 } 0299 } 0300 if (!pixmaps.isEmpty()) { 0301 QPixmap result(MARGIN + width + MARGIN, MARGIN + height - SPACING + MARGIN - (spaces.last() ? 1 : 0)); 0302 QPainter painter(&result); 0303 // Draw all the images: 0304 height = MARGIN; 0305 QList<QPixmap>::iterator it; 0306 QList<QColor>::iterator it2; 0307 QList<bool>::iterator it3; 0308 int i = 0; 0309 for (it = pixmaps.begin(), it2 = backgrounds.begin(), it3 = spaces.begin(); it != pixmaps.end(); ++it, ++it2, ++it3, ++i) { 0310 if (i != 0 && (*it3)) { 0311 painter.fillRect(MARGIN, height, result.width() - 2 * MARGIN, SPACING, (*it2).darker(NoteContent::FEEDBACK_DARKING)); 0312 ++height; 0313 } 0314 painter.drawPixmap(MARGIN, height, *it); 0315 if ((*it).width() < width) 0316 painter.fillRect(MARGIN + (*it).width(), height, width - (*it).width(), (*it).height(), (*it2).darker(NoteContent::FEEDBACK_DARKING)); 0317 if (*it3) { 0318 painter.fillRect(MARGIN, height + (*it).height(), result.width() - 2 * MARGIN, SPACING, (*it2).darker(NoteContent::FEEDBACK_DARKING)); 0319 ++height; 0320 } 0321 painter.fillRect(MARGIN, height + (*it).height(), result.width() - 2 * MARGIN, SPACING, Tools::mixColor(textColor, backgroundColor)); 0322 height += (*it).height() + SPACING; 0323 } 0324 // Draw the border: 0325 painter.setPen(textColor); 0326 painter.drawLine(0, 0, result.width() - 1, 0); 0327 painter.drawLine(0, 0, 0, result.height() - 1); 0328 painter.drawLine(0, result.height() - 1, result.width() - 1, result.height() - 1); 0329 painter.drawLine(result.width() - 1, 0, result.width() - 1, result.height() - 1); 0330 // Draw the "lightly rounded" border: 0331 painter.setPen(Tools::mixColor(textColor, backgroundColor)); 0332 painter.drawPoint(0, 0); 0333 painter.drawPoint(0, result.height() - 1); 0334 painter.drawPoint(result.width() - 1, result.height() - 1); 0335 painter.drawPoint(result.width() - 1, 0); 0336 // Draw the background in the margin (the inside will be painted above, anyway): 0337 painter.setPen(backgroundColor); 0338 painter.drawLine(1, 1, result.width() - 2, 1); 0339 painter.drawLine(1, 1, 1, result.height() - 2); 0340 painter.drawLine(1, result.height() - 2, result.width() - 2, result.height() - 2); 0341 painter.drawLine(result.width() - 2, 1, result.width() - 2, result.height() - 2); 0342 // And assign the feedback pixmap to the drag object: 0343 // multipleDrag->setPixmap(result, QPoint(-8, -8)); 0344 return result; 0345 } 0346 return QPixmap(); 0347 } 0348 0349 bool NoteDrag::canDecode(const QMimeData *source) 0350 { 0351 return source->hasFormat(NOTE_MIME_STRING); 0352 } 0353 0354 BasketScene *NoteDrag::basketOf(const QMimeData *source) 0355 { 0356 QByteArray srcData = source->data(NOTE_MIME_STRING); 0357 QBuffer buffer(&srcData); 0358 if (buffer.open(QIODevice::ReadOnly)) { 0359 QDataStream stream(&buffer); 0360 // Get the parent basket: 0361 quint64 basketPointer; 0362 stream >> (quint64 &)basketPointer; 0363 return (BasketScene *)basketPointer; 0364 } else 0365 return nullptr; 0366 } 0367 0368 QList<Note *> NoteDrag::notesOf(QGraphicsSceneDragDropEvent *source) 0369 { 0370 /* FIXME: this code does not parse the stream properly (see NoteDrag::decode). 0371 Thus m_draggedNotes will contain many invalid pointer values. 0372 As a workaround, we use NoteDrag::selectedNotes now. */ 0373 0374 QByteArray srcData = source->mimeData()->data(NOTE_MIME_STRING); 0375 QBuffer buffer(&srcData); 0376 if (buffer.open(QIODevice::ReadOnly)) { 0377 QDataStream stream(&buffer); 0378 // Get the parent basket: 0379 quint64 basketPointer; 0380 stream >> (quint64 &)basketPointer; 0381 // Get the note list: 0382 quint64 notePointer; 0383 QList<Note *> notes; 0384 do { 0385 stream >> notePointer; 0386 if (notePointer != 0) 0387 notes.append((Note *)notePointer); 0388 } while (notePointer); 0389 // Done: 0390 return notes; 0391 } else 0392 return QList<Note *>(); 0393 } 0394 0395 void NoteDrag::saveNoteSelectionToList(NoteSelection *selection) 0396 { 0397 for (NoteSelection *sel = selection->firstStacked(); sel != nullptr; sel = sel->nextStacked()) { 0398 if (sel->note->isGroup()) 0399 saveNoteSelectionToList(sel); 0400 else 0401 selectedNotes.append(sel->note); 0402 } 0403 } 0404 0405 Note *NoteDrag::decode(const QMimeData *source, BasketScene *parent, bool moveFiles, bool moveNotes) 0406 { 0407 QByteArray srcData = source->data(NOTE_MIME_STRING); 0408 QBuffer buffer(&srcData); 0409 if (buffer.open(QIODevice::ReadOnly)) { 0410 QDataStream stream(&buffer); 0411 // Get the parent basket: 0412 quint64 basketPointer; 0413 stream >> (quint64 &)basketPointer; 0414 BasketScene *basket = (BasketScene *)basketPointer; 0415 // Decode the note hierarchy: 0416 Note *hierarchy = decodeHierarchy(stream, parent, moveFiles, moveNotes, basket); 0417 // In case we moved notes from one basket to another, save the source basket where notes were removed: 0418 basket->filterAgainDelayed(); // Delayed, because if a note is moved to the same basket, the note is not at its 0419 basket->save(); // new position yet, and the call to ensureNoteVisible would make the interface flicker!! 0420 return hierarchy; 0421 } else 0422 return nullptr; 0423 } 0424 0425 Note *NoteDrag::decodeHierarchy(QDataStream &stream, BasketScene *parent, bool moveFiles, bool moveNotes, BasketScene *originalBasket) 0426 { 0427 quint64 notePointer; 0428 quint64 type; 0429 QString fileName; 0430 QString fullPath; 0431 QDateTime addedDate; 0432 QDateTime lastModificationDate; 0433 0434 Note *firstNote = nullptr; // TODO: class NoteTreeChunk 0435 Note *lastInserted = nullptr; 0436 0437 do { 0438 stream >> notePointer; 0439 if (notePointer == 0) 0440 return firstNote; 0441 Note *oldNote = (Note *)notePointer; 0442 0443 Note *note = nullptr; 0444 quint64 groupWidth; 0445 stream >> type >> groupWidth; 0446 if (type == NoteType::Group) { 0447 note = new Note(parent); 0448 note->setZValue(-1); 0449 note->setGroupWidth(groupWidth); 0450 quint64 isFolded; 0451 stream >> isFolded; 0452 if (isFolded) 0453 note->toggleFolded(); 0454 if (moveNotes) { 0455 note->setX(oldNote->x()); // We don't move groups but re-create them (every children can to not be selected) 0456 note->setY(oldNote->y()); // We just set the position of the copied group so the animation seems as if the group is the same as (or a copy of) the old. 0457 note->setHeight(oldNote->height()); // Idem: the only use of Note::setHeight() 0458 parent->removeItem(oldNote); 0459 } 0460 Note *children = decodeHierarchy(stream, parent, moveFiles, moveNotes, originalBasket); 0461 if (children) { 0462 for (Note *n = children; n; n = n->next()) 0463 n->setParentNote(note); 0464 note->setFirstChild(children); 0465 } 0466 } else { 0467 stream >> fileName >> fullPath >> addedDate >> lastModificationDate; 0468 if (moveNotes) { 0469 originalBasket->unplugNote(oldNote); 0470 note = oldNote; 0471 if (note->basket() != parent && (!fileName.isEmpty() && !fullPath.isEmpty())) { 0472 QString newFileName = Tools::fileNameForNewFile(fileName, parent->fullPath()); 0473 note->content()->setFileName(newFileName); 0474 0475 KIO::CopyJob *copyJob = KIO::move(QUrl::fromLocalFile(fullPath), QUrl::fromLocalFile(parent->fullPath() + newFileName), KIO::Overwrite | KIO::Resume | KIO::HideProgressInfo); 0476 parent->connect(copyJob, &KIO::CopyJob::copyingDone, parent, &BasketScene::slotCopyingDone2); 0477 } 0478 note->setGroupWidth(groupWidth); 0479 note->setParentNote(nullptr); 0480 note->setPrev(nullptr); 0481 note->setNext(nullptr); 0482 note->setParentBasket(parent); 0483 NoteFactory::consumeContent(stream, (NoteType::Id)type); 0484 } else if ((note = NoteFactory::decodeContent(stream, (NoteType::Id)type, parent))) { 0485 note->setGroupWidth(groupWidth); 0486 note->setAddedDate(addedDate); 0487 note->setLastModificationDate(lastModificationDate); 0488 } else if (!fileName.isEmpty()) { 0489 // Here we are CREATING a new EMPTY file, so the name is RESERVED 0490 // (while dropping several files at once a filename cannot be used by two of them). 0491 // Later on, file_copy/file_move will copy/move the file to the new location. 0492 QString newFileName = Tools::fileNameForNewFile(fileName, parent->fullPath()); 0493 // NoteFactory::createFileForNewNote(parent, QString(), fileName); 0494 KIO::CopyJob *copyJob; 0495 if (moveFiles) { 0496 copyJob = KIO::move(QUrl::fromLocalFile(fullPath), QUrl::fromLocalFile(parent->fullPath() + newFileName), KIO::Overwrite | KIO::Resume | KIO::HideProgressInfo); 0497 } else { 0498 copyJob = KIO::copy(QUrl::fromLocalFile(fullPath), QUrl::fromLocalFile(parent->fullPath() + newFileName), KIO::Overwrite | KIO::Resume | KIO::HideProgressInfo); 0499 } 0500 parent->connect(copyJob, &KIO::CopyJob::copyingDone, parent, &BasketScene::slotCopyingDone2); 0501 0502 note = NoteFactory::loadFile(newFileName, (NoteType::Id)type, parent); 0503 note->setGroupWidth(groupWidth); 0504 note->setAddedDate(addedDate); 0505 note->setLastModificationDate(lastModificationDate); 0506 } 0507 } 0508 // Retrieve the states (tags) and assign them to the note: 0509 if (note && note->content()) { 0510 quint64 statePointer; 0511 do { 0512 stream >> statePointer; 0513 if (statePointer) 0514 note->addState((State *)statePointer); 0515 } while (statePointer); 0516 } 0517 // Now that we have created the note, insert it: 0518 if (note) { 0519 if (!firstNote) 0520 firstNote = note; 0521 else { 0522 lastInserted->setNext(note); 0523 note->setPrev(lastInserted); 0524 } 0525 lastInserted = note; 0526 } 0527 } while (true); 0528 0529 // We've done: return! 0530 return firstNote; 0531 } 0532 0533 /** ExtendedTextDrag */ 0534 0535 bool ExtendedTextDrag::decode(const QMimeData *e, QString &str) 0536 { 0537 QString subtype("plain"); 0538 return decode(e, str, subtype); 0539 } 0540 0541 bool ExtendedTextDrag::decode(const QMimeData *e, QString &str, QString &subtype) 0542 { 0543 // Get the string: 0544 bool ok; 0545 str = e->text(); 0546 ok = !str.isNull(); 0547 0548 // Test if it was a UTF-16 string (from eg. Mozilla): 0549 if (str.length() >= 2) { 0550 if ((str[0] == 0xFF && str[1] == 0xFE) || (str[0] == 0xFE && str[1] == 0xFF)) { 0551 QByteArray utf16 = e->data(QString("text/" + subtype).toLocal8Bit()); 0552 str = QTextCodec::codecForName("utf16")->toUnicode(utf16); 0553 return true; 0554 } 0555 } 0556 0557 // Test if it was empty (sometimes, from GNOME or Mozilla) 0558 if (str.length() == 0 && subtype == "plain") { 0559 if (e->hasFormat("UTF8_STRING")) { 0560 QByteArray utf8 = e->data("UTF8_STRING"); 0561 str = QTextCodec::codecForName("utf8")->toUnicode(utf8); 0562 return true; 0563 } 0564 if (e->hasFormat("text/unicode")) { // FIXME: It's UTF-16 without order bytes!!! 0565 QByteArray utf16 = e->data("text/unicode"); 0566 str = QTextCodec::codecForName("utf16")->toUnicode(utf16); 0567 return true; 0568 } 0569 if (e->hasFormat("TEXT")) { // local encoding 0570 QByteArray text = e->data("TEXT"); 0571 str = QString(text); 0572 return true; 0573 } 0574 if (e->hasFormat("COMPOUND_TEXT")) { // local encoding 0575 QByteArray text = e->data("COMPOUND_TEXT"); 0576 str = QString(text); 0577 return true; 0578 } 0579 } 0580 return ok; 0581 } 0582 0583 #include "moc_notedrag.cpp"