|
|
|
|
/***************************************************************************
|
|
|
|
|
* Copyright (C) 2003 by S<EFBFBD>astien Laot *
|
|
|
|
|
* slaout@linux62.org *
|
|
|
|
|
* *
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
|
* (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
|
* *
|
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <tqdragobject.h>
|
|
|
|
|
#include <tqdir.h>
|
|
|
|
|
#include <tqpainter.h>
|
|
|
|
|
#include <tqtextcodec.h>
|
|
|
|
|
#include <tqbuffer.h>
|
|
|
|
|
#include <kurldrag.h>
|
|
|
|
|
#include <tdeversion.h>
|
|
|
|
|
#include <tdeapplication.h>
|
|
|
|
|
#include <tqdesktopwidget.h>
|
|
|
|
|
|
|
|
|
|
#include "basket.h"
|
|
|
|
|
#include "notedrag.h"
|
|
|
|
|
#include "notefactory.h"
|
|
|
|
|
#include "tools.h"
|
|
|
|
|
#include "global.h"
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
/** NoteDrag */
|
|
|
|
|
|
|
|
|
|
const char * NoteDrag::NOTE_MIME_STRING = "application/x-basket-note";
|
|
|
|
|
|
|
|
|
|
void NoteDrag::createAndEmptyCuttingTmpFolder()
|
|
|
|
|
{
|
|
|
|
|
Tools::deleteRecursively(Global::tempCutFolder());
|
|
|
|
|
TQDir dir;
|
|
|
|
|
dir.mkdir(Global::tempCutFolder());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQDragObject* NoteDrag::dragObject(NoteSelection *noteList, bool cutting, TQWidget *source)
|
|
|
|
|
{
|
|
|
|
|
if (noteList->count() <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
// The MimeSource:
|
|
|
|
|
KMultipleDrag *multipleDrag = new KMultipleDrag(source);
|
|
|
|
|
|
|
|
|
|
// Make sure the temporary folder exists and is empty (we delete previously moved file(s) (if exists)
|
|
|
|
|
// since we override the content of the clipboard and previous file willn't be accessable anymore):
|
|
|
|
|
createAndEmptyCuttingTmpFolder();
|
|
|
|
|
|
|
|
|
|
// The "Native Format" Serialization:
|
|
|
|
|
TQBuffer buffer;
|
|
|
|
|
if (buffer.open(IO_WriteOnly)) {
|
|
|
|
|
TQDataStream stream(&buffer);
|
|
|
|
|
// First append a pointer to the basket:
|
|
|
|
|
stream << (TQ_UINT64)(noteList->firstStacked()->note->basket());
|
|
|
|
|
// Then a list of pointers to all notes, and parent groups:
|
|
|
|
|
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked())
|
|
|
|
|
stream << (TQ_UINT64)(node->note);
|
|
|
|
|
TQValueList<Note*> groups = noteList->parentGroups();
|
|
|
|
|
for (TQValueList<Note*>::iterator it = groups.begin(); it != groups.end(); ++it)
|
|
|
|
|
stream << (TQ_UINT64)(*it);
|
|
|
|
|
stream << (TQ_UINT64)0;
|
|
|
|
|
// And finally the notes themselves:
|
|
|
|
|
serializeNotes(noteList, stream, cutting);
|
|
|
|
|
// Append the object:
|
|
|
|
|
buffer.close();
|
|
|
|
|
TQStoredDrag *dragObject = new TQStoredDrag(NOTE_MIME_STRING, source);
|
|
|
|
|
dragObject->setEncodedData(buffer.buffer());
|
|
|
|
|
multipleDrag->addDragObject(dragObject);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The "Other Flavours" Serialization:
|
|
|
|
|
serializeText( noteList, multipleDrag );
|
|
|
|
|
serializeHtml( noteList, multipleDrag );
|
|
|
|
|
serializeImage( noteList, multipleDrag );
|
|
|
|
|
serializeLinks( noteList, multipleDrag, cutting );
|
|
|
|
|
|
|
|
|
|
// The Alternate Flavours:
|
|
|
|
|
if (noteList->count() == 1)
|
|
|
|
|
noteList->firstStacked()->note->content()->addAlternateDragObjects(multipleDrag);
|
|
|
|
|
|
|
|
|
|
// If it is a drag, and not a copy/cut, add the feedback pixmap:
|
|
|
|
|
if (source)
|
|
|
|
|
setFeedbackPixmap(noteList, multipleDrag);
|
|
|
|
|
|
|
|
|
|
return multipleDrag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteDrag::serializeNotes(NoteSelection *noteList, TQDataStream &stream, bool cutting)
|
|
|
|
|
{
|
|
|
|
|
for (NoteSelection *node = noteList; node; node = node->next) {
|
|
|
|
|
stream << (TQ_UINT64)(node->note);
|
|
|
|
|
if (node->firstChild) {
|
|
|
|
|
stream << (TQ_UINT64)(NoteType::Group) << (TQ_UINT64)(node->note->groupWidth()) << (TQ_UINT64)(node->note->isFolded());
|
|
|
|
|
serializeNotes(node->firstChild, stream, cutting);
|
|
|
|
|
} else {
|
|
|
|
|
NoteContent *content = node->note->content();
|
|
|
|
|
stream << (TQ_UINT64)(content->type()) << (TQ_UINT64)(node->note->groupWidth());
|
|
|
|
|
// Serialize file name, and move the file to a temporary place if the note is to be cuttted.
|
|
|
|
|
// If note does not have file name, we append empty string to be able to easily decode the notes later:
|
|
|
|
|
stream << content->fileName();
|
|
|
|
|
if (content->shouldSerializeFile()) {
|
|
|
|
|
if (cutting) {
|
|
|
|
|
// Move file in a temporary place:
|
|
|
|
|
TQString fullPath = Global::tempCutFolder() + Tools::fileNameForNewFile(content->fileName(), Global::tempCutFolder());
|
|
|
|
|
TDEIO::move(KURL(content->fullPath()), KURL(fullPath), /*showProgressInfo=*/false);
|
|
|
|
|
node->fullPath = fullPath;
|
|
|
|
|
stream << fullPath;
|
|
|
|
|
} else
|
|
|
|
|
stream << content->fullPath();
|
|
|
|
|
} else
|
|
|
|
|
stream << TQString("");
|
|
|
|
|
stream << content->note()->addedDate() << content->note()->lastModificationDate();
|
|
|
|
|
content->serialize(stream);
|
|
|
|
|
State::List states = node->note->states();
|
|
|
|
|
for (State::List::Iterator it = states.begin(); it != states.end(); ++it)
|
|
|
|
|
stream << (TQ_UINT64)(*it);
|
|
|
|
|
stream << (TQ_UINT64)0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
stream << (TQ_UINT64)0; // Mark the end of the notes in this group/hierarchy.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteDrag::serializeText(NoteSelection *noteList, KMultipleDrag *multipleDrag)
|
|
|
|
|
{
|
|
|
|
|
TQString textEquivalent;
|
|
|
|
|
TQString text;
|
|
|
|
|
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
|
|
|
|
|
text = node->note->toText(node->fullPath); // note->toText() and not note->content()->toText() because the first one will also export the tags as text.
|
|
|
|
|
if (!text.isEmpty())
|
|
|
|
|
textEquivalent += (!textEquivalent.isEmpty() ? "\n" : "") + text;
|
|
|
|
|
}
|
|
|
|
|
if (!textEquivalent.isEmpty())
|
|
|
|
|
multipleDrag->addDragObject( new TQTextDrag(textEquivalent) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteDrag::serializeHtml(NoteSelection *noteList, KMultipleDrag *multipleDrag)
|
|
|
|
|
{
|
|
|
|
|
TQString htmlEquivalent;
|
|
|
|
|
TQString html;
|
|
|
|
|
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
|
|
|
|
|
html = node->note->content()->toHtml("", node->fullPath);
|
|
|
|
|
if (!html.isEmpty())
|
|
|
|
|
htmlEquivalent += (!htmlEquivalent.isEmpty() ? "<br>\n" : "") + html;
|
|
|
|
|
}
|
|
|
|
|
if (!htmlEquivalent.isEmpty()) {
|
|
|
|
|
// Add HTML flavour:
|
|
|
|
|
TQTextDrag *htmlDrag = new TQTextDrag(htmlEquivalent);
|
|
|
|
|
htmlDrag->setSubtype("html");
|
|
|
|
|
multipleDrag->addDragObject(htmlDrag);
|
|
|
|
|
// But also TQTextEdit flavour, to be able to paste several notes to a text edit:
|
|
|
|
|
TQByteArray byteArray = ("<!--StartFragment--><p>" + htmlEquivalent).local8Bit();
|
|
|
|
|
TQStoredDrag *richTextDrag = new TQStoredDrag("application/x-qrichtext");
|
|
|
|
|
richTextDrag->setEncodedData(byteArray);
|
|
|
|
|
multipleDrag->addDragObject(richTextDrag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteDrag::serializeImage(NoteSelection *noteList, KMultipleDrag *multipleDrag)
|
|
|
|
|
{
|
|
|
|
|
TQValueList<TQPixmap> pixmaps;
|
|
|
|
|
TQPixmap pixmap;
|
|
|
|
|
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
|
|
|
|
|
pixmap = node->note->content()->toPixmap();
|
|
|
|
|
if (!pixmap.isNull())
|
|
|
|
|
pixmaps.append(pixmap);
|
|
|
|
|
}
|
|
|
|
|
if (!pixmaps.isEmpty()) {
|
|
|
|
|
TQPixmap pixmapEquivalent;
|
|
|
|
|
if (pixmaps.count() == 1)
|
|
|
|
|
pixmapEquivalent = pixmaps[0];
|
|
|
|
|
else {
|
|
|
|
|
// Search the total size:
|
|
|
|
|
int height = 0;
|
|
|
|
|
int width = 0;
|
|
|
|
|
for (TQValueList<TQPixmap>::iterator it = pixmaps.begin(); it != pixmaps.end(); ++it) {
|
|
|
|
|
height += (*it).height();
|
|
|
|
|
if ((*it).width() > width)
|
|
|
|
|
width = (*it).width();
|
|
|
|
|
}
|
|
|
|
|
// Create the image by painting all image into one big image:
|
|
|
|
|
pixmapEquivalent.resize(width, height);
|
|
|
|
|
pixmapEquivalent.fill(TQt::white);
|
|
|
|
|
TQPainter painter(&pixmapEquivalent);
|
|
|
|
|
height = 0;
|
|
|
|
|
for (TQValueList<TQPixmap>::iterator it = pixmaps.begin(); it != pixmaps.end(); ++it) {
|
|
|
|
|
painter.drawPixmap(0, height, *it);
|
|
|
|
|
height += (*it).height();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TQImageDrag *imageDrag = new TQImageDrag(pixmapEquivalent.convertToImage());
|
|
|
|
|
multipleDrag->addDragObject(imageDrag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteDrag::serializeLinks(NoteSelection *noteList, KMultipleDrag *multipleDrag, bool cutting)
|
|
|
|
|
{
|
|
|
|
|
KURL::List urls;
|
|
|
|
|
TQStringList titles;
|
|
|
|
|
KURL url;
|
|
|
|
|
TQString title;
|
|
|
|
|
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked()) {
|
|
|
|
|
node->note->content()->toLink(&url, &title, node->fullPath);
|
|
|
|
|
if (!url.isEmpty()) {
|
|
|
|
|
urls.append(url);
|
|
|
|
|
titles.append(title);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!urls.isEmpty()) {
|
|
|
|
|
// First, the standard text/uri-list MIME format:
|
|
|
|
|
#if KDE_IS_VERSION( 3, 3, 90 )
|
|
|
|
|
KURLDrag *urlsDrag = new KURLDrag(urls);
|
|
|
|
|
// ONLY export as text/uri-list, and not as text/plain* as we wil do that better ourself
|
|
|
|
|
urlsDrag->setExportAsText(false);
|
|
|
|
|
multipleDrag->addDragObject(urlsDrag);
|
|
|
|
|
#else
|
|
|
|
|
KURLDrag2 *urlsDrag = new KURLDrag2(urls);
|
|
|
|
|
TQByteArray byteArray = urlsDrag->encodedData2("text/uri-list");
|
|
|
|
|
TQStoredDrag *uriListDrag = new TQStoredDrag("text/uri-list");
|
|
|
|
|
uriListDrag->setEncodedData(byteArray);
|
|
|
|
|
multipleDrag->addDragObject(uriListDrag);
|
|
|
|
|
delete urlsDrag;
|
|
|
|
|
#endif
|
|
|
|
|
// Then, also provide it in the Mozilla proprietary format (that also allow to add titles to URLs):
|
|
|
|
|
// A version for Mozilla applications (convert to "theUrl\ntheTitle", into UTF-16):
|
|
|
|
|
// FIXME: Does Mozilla support the drag of several URLs at once?
|
|
|
|
|
// FIXME: If no, only provide that if theire is only ONE URL.
|
|
|
|
|
TQString xMozUrl;
|
|
|
|
|
for (uint i = 0; i < urls.count(); ++i)
|
|
|
|
|
xMozUrl += (xMozUrl.isEmpty() ? "" : "\n") + urls[i].prettyURL() + "\n" + titles[i];
|
|
|
|
|
/* Code for only one: ===============
|
|
|
|
|
xMozUrl = note->title() + "\n" + note->url().prettyURL();*/
|
|
|
|
|
TQByteArray baMozUrl;
|
|
|
|
|
TQTextStream stream(baMozUrl, IO_WriteOnly);
|
|
|
|
|
stream.setEncoding(TQTextStream::RawUnicode); // It's UTF16 (aka UCS2), but with the first two order bytes
|
|
|
|
|
stream << xMozUrl;
|
|
|
|
|
TQStoredDrag *xMozUrlDrag = new TQStoredDrag("text/x-moz-url");
|
|
|
|
|
xMozUrlDrag->setEncodedData(baMozUrl);
|
|
|
|
|
multipleDrag->addDragObject(xMozUrlDrag);
|
|
|
|
|
|
|
|
|
|
if (cutting) {
|
|
|
|
|
TQByteArray arrayCut(2);
|
|
|
|
|
TQStoredDrag *storedDragCut = new TQStoredDrag("application/x-tde-cutselection");
|
|
|
|
|
arrayCut[0] = '1';
|
|
|
|
|
arrayCut[1] = 0;
|
|
|
|
|
storedDragCut->setEncodedData(arrayCut);
|
|
|
|
|
multipleDrag->addDragObject(storedDragCut);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void NoteDrag::setFeedbackPixmap(NoteSelection *noteList, KMultipleDrag *multipleDrag)
|
|
|
|
|
{
|
|
|
|
|
TQPixmap pixmap = feedbackPixmap(noteList);
|
|
|
|
|
if (!pixmap.isNull())
|
|
|
|
|
multipleDrag->setPixmap(pixmap, TQPoint(-8, -8));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQPixmap NoteDrag::feedbackPixmap(NoteSelection *noteList)
|
|
|
|
|
{
|
|
|
|
|
if (noteList == 0)
|
|
|
|
|
return TQPixmap();
|
|
|
|
|
|
|
|
|
|
static const int MARGIN = 2;
|
|
|
|
|
static const int SPACING = 1;
|
|
|
|
|
|
|
|
|
|
TQColor textColor = noteList->firstStacked()->note->basket()->textColor();
|
|
|
|
|
TQColor backgroundColor = noteList->firstStacked()->note->basket()->backgroundColor().dark(NoteContent::FEEDBACK_DARKING);
|
|
|
|
|
|
|
|
|
|
TQValueList<TQPixmap> pixmaps;
|
|
|
|
|
TQValueList<TQColor> backgrounds;
|
|
|
|
|
TQValueList<bool> spaces;
|
|
|
|
|
TQPixmap pixmap;
|
|
|
|
|
int height = 0;
|
|
|
|
|
int width = 0;
|
|
|
|
|
int i = 0;
|
|
|
|
|
bool elipsisImage = false;
|
|
|
|
|
TQColor bgColor;
|
|
|
|
|
bool needSpace;
|
|
|
|
|
for (NoteSelection *node = noteList->firstStacked(); node; node = node->nextStacked(), ++i) {
|
|
|
|
|
if (elipsisImage) {
|
|
|
|
|
pixmap = TQPixmap(7, 2);
|
|
|
|
|
pixmap.fill(backgroundColor);
|
|
|
|
|
TQPainter painter(&pixmap);
|
|
|
|
|
painter.setPen(textColor);
|
|
|
|
|
painter.drawPoint(1, 1);
|
|
|
|
|
painter.drawPoint(3, 1);
|
|
|
|
|
painter.drawPoint(5, 1);
|
|
|
|
|
painter.end();
|
|
|
|
|
bgColor = node->note->basket()->backgroundColor();
|
|
|
|
|
needSpace = false;
|
|
|
|
|
} else {
|
|
|
|
|
pixmap = node->note->content()->feedbackPixmap(/*maxWidth=*/kapp->desktop()->width() / 2, /*maxHeight=*/96);
|
|
|
|
|
bgColor = node->note->backgroundColor();
|
|
|
|
|
needSpace = node->note->content()->needSpaceForFeedbackPixmap();
|
|
|
|
|
}
|
|
|
|
|
if (!pixmap.isNull()) {
|
|
|
|
|
if (pixmap.width() > width)
|
|
|
|
|
width = pixmap.width();
|
|
|
|
|
pixmaps.append(pixmap);
|
|
|
|
|
backgrounds.append(bgColor);
|
|
|
|
|
spaces.append(needSpace);
|
|
|
|
|
height += (i > 0 && needSpace ? 1 : 0) + pixmap.height() + SPACING + (needSpace ? 1 : 0);
|
|
|
|
|
if (elipsisImage)
|
|
|
|
|
break;
|
|
|
|
|
if (height > kapp->desktop()->height() / 2)
|
|
|
|
|
elipsisImage = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!pixmaps.isEmpty()) {
|
|
|
|
|
TQPixmap result(MARGIN + width + MARGIN, MARGIN + height - SPACING + MARGIN - (spaces.last() ? 1 : 0));
|
|
|
|
|
TQPainter painter(&result);
|
|
|
|
|
// Draw all the images:
|
|
|
|
|
height = MARGIN;
|
|
|
|
|
TQValueList<TQPixmap>::iterator it;
|
|
|
|
|
TQValueList<TQColor>::iterator it2;
|
|
|
|
|
TQValueList<bool>::iterator it3;
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (it = pixmaps.begin(), it2 = backgrounds.begin(), it3 = spaces.begin(); it != pixmaps.end(); ++it, ++it2, ++it3, ++i) {
|
|
|
|
|
if (i != 0 && (*it3)) {
|
|
|
|
|
painter.fillRect(MARGIN, height, result.width() - 2 * MARGIN, SPACING, (*it2).dark(NoteContent::FEEDBACK_DARKING));
|
|
|
|
|
++height;
|
|
|
|
|
}
|
|
|
|
|
painter.drawPixmap(MARGIN, height, *it);
|
|
|
|
|
if ((*it).width() < width)
|
|
|
|
|
painter.fillRect(MARGIN + (*it).width(), height, width - (*it).width(), (*it).height(), (*it2).dark(NoteContent::FEEDBACK_DARKING));
|
|
|
|
|
if (*it3) {
|
|
|
|
|
painter.fillRect(MARGIN, height + (*it).height(), result.width() - 2 * MARGIN, SPACING, (*it2).dark(NoteContent::FEEDBACK_DARKING));
|
|
|
|
|
++height;
|
|
|
|
|
}
|
|
|
|
|
painter.fillRect(MARGIN, height + (*it).height(), result.width() - 2 * MARGIN, SPACING, Tools::mixColor(textColor, backgroundColor));
|
|
|
|
|
height += (*it).height() + SPACING;
|
|
|
|
|
}
|
|
|
|
|
// Draw the border:
|
|
|
|
|
painter.setPen(textColor);
|
|
|
|
|
painter.drawLine(0, 0, result.width() - 1, 0);
|
|
|
|
|
painter.drawLine(0, 0, 0, result.height() - 1);
|
|
|
|
|
painter.drawLine(0, result.height() - 1, result.width() - 1, result.height() - 1);
|
|
|
|
|
painter.drawLine(result.width() - 1, 0, result.width() - 1, result.height() - 1);
|
|
|
|
|
// Draw the "lightly rounded" border:
|
|
|
|
|
painter.setPen(Tools::mixColor(textColor, backgroundColor));
|
|
|
|
|
painter.drawPoint(0, 0);
|
|
|
|
|
painter.drawPoint(0, result.height() - 1);
|
|
|
|
|
painter.drawPoint(result.width() - 1, result.height() - 1);
|
|
|
|
|
painter.drawPoint(result.width() - 1, 0);
|
|
|
|
|
// Draw the background in the margin (the inside will be painted above, anyway):
|
|
|
|
|
painter.setPen(backgroundColor);
|
|
|
|
|
painter.drawLine(1, 1, result.width() - 2, 1);
|
|
|
|
|
painter.drawLine(1, 1, 1, result.height() - 2);
|
|
|
|
|
painter.drawLine(1, result.height() - 2, result.width() - 2, result.height() - 2);
|
|
|
|
|
painter.drawLine(result.width() - 2, 1, result.width() - 2, result.height() - 2);
|
|
|
|
|
// And assign the feedback pixmap to the drag object:
|
|
|
|
|
//multipleDrag->setPixmap(result, TQPoint(-8, -8));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return TQPixmap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NoteDrag::canDecode(TQMimeSource *source)
|
|
|
|
|
{
|
|
|
|
|
return source->provides(NOTE_MIME_STRING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Basket* NoteDrag::basketOf(TQMimeSource *source)
|
|
|
|
|
{
|
|
|
|
|
TQBuffer buffer(source->encodedData(NOTE_MIME_STRING));
|
|
|
|
|
if (buffer.open(IO_ReadOnly)) {
|
|
|
|
|
TQDataStream stream(&buffer);
|
|
|
|
|
// Get the parent basket:
|
|
|
|
|
TQ_UINT64 basketPointer;
|
|
|
|
|
stream >> (TQ_UINT64&)basketPointer;
|
|
|
|
|
return (Basket*)basketPointer;
|
|
|
|
|
} else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQValueList<Note*> NoteDrag::notesOf(TQMimeSource *source)
|
|
|
|
|
{
|
|
|
|
|
TQBuffer buffer(source->encodedData(NOTE_MIME_STRING));
|
|
|
|
|
if (buffer.open(IO_ReadOnly)) {
|
|
|
|
|
TQDataStream stream(&buffer);
|
|
|
|
|
// Get the parent basket:
|
|
|
|
|
TQ_UINT64 basketPointer;
|
|
|
|
|
stream >> (TQ_UINT64&)basketPointer;
|
|
|
|
|
// Get the note list:
|
|
|
|
|
TQ_UINT64 notePointer;
|
|
|
|
|
TQValueList<Note*> notes;
|
|
|
|
|
do {
|
|
|
|
|
stream >> notePointer;
|
|
|
|
|
if (notePointer != 0)
|
|
|
|
|
notes.append((Note*)notePointer);
|
|
|
|
|
} while (notePointer);
|
|
|
|
|
// Done:
|
|
|
|
|
return notes;
|
|
|
|
|
} else
|
|
|
|
|
return TQValueList<Note*>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Note* NoteDrag::decode(TQMimeSource *source, Basket *parent, bool moveFiles, bool moveNotes)
|
|
|
|
|
{
|
|
|
|
|
TQBuffer buffer(source->encodedData(NOTE_MIME_STRING));
|
|
|
|
|
if (buffer.open(IO_ReadOnly)) {
|
|
|
|
|
TQDataStream stream(&buffer);
|
|
|
|
|
// Get the parent basket:
|
|
|
|
|
TQ_UINT64 basketPointer;
|
|
|
|
|
stream >> (TQ_UINT64&)basketPointer;
|
|
|
|
|
Basket *basket = (Basket*)basketPointer;
|
|
|
|
|
// Get the note list:
|
|
|
|
|
TQ_UINT64 notePointer;
|
|
|
|
|
TQValueList<Note*> notes;
|
|
|
|
|
do {
|
|
|
|
|
stream >> notePointer;
|
|
|
|
|
if (notePointer != 0)
|
|
|
|
|
notes.append((Note*)notePointer);
|
|
|
|
|
} while (notePointer);
|
|
|
|
|
// Decode the note hierarchy:
|
|
|
|
|
Note *hierarchy = decodeHierarchy(stream, parent, moveFiles, moveNotes, basket);
|
|
|
|
|
// In case we moved notes from one basket to another, save the source basket where notes were removed:
|
|
|
|
|
basket->filterAgainDelayed(); // Delayed, because if a note is moved to the same basket, the note is not at its
|
|
|
|
|
basket->save(); // new position yet, and the call to ensureNoteVisible would make the interface flicker!!
|
|
|
|
|
return hierarchy;
|
|
|
|
|
} else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Note* NoteDrag::decodeHierarchy(TQDataStream &stream, Basket *parent, bool moveFiles, bool moveNotes, Basket *originalBasket)
|
|
|
|
|
{
|
|
|
|
|
TQ_UINT64 notePointer;
|
|
|
|
|
TQ_UINT64 type;
|
|
|
|
|
TQString fileName;
|
|
|
|
|
TQString fullPath;
|
|
|
|
|
TQDateTime addedDate;
|
|
|
|
|
TQDateTime lastModificationDate;
|
|
|
|
|
|
|
|
|
|
Note *firstNote = 0; // TODO: class NoteTreeChunk
|
|
|
|
|
Note *lastInserted = 0;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
stream >> notePointer;
|
|
|
|
|
if (notePointer == 0)
|
|
|
|
|
return firstNote;
|
|
|
|
|
Note *oldNote = (Note*)notePointer;
|
|
|
|
|
|
|
|
|
|
Note *note = 0;
|
|
|
|
|
TQ_UINT64 groupWidth;
|
|
|
|
|
stream >> type >> groupWidth;
|
|
|
|
|
if (type == NoteType::Group) {
|
|
|
|
|
note = new Note(parent);
|
|
|
|
|
note->setGroupWidth(groupWidth);
|
|
|
|
|
TQ_UINT64 isFolded;
|
|
|
|
|
stream >> isFolded;
|
|
|
|
|
if (isFolded)
|
|
|
|
|
note->toggleFolded(/*animate=*/false);
|
|
|
|
|
if (moveNotes) {
|
|
|
|
|
note->setX(oldNote->x()); // We don't move groups but re-create them (every childs can to not be selected)
|
|
|
|
|
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.
|
|
|
|
|
note->setHeight(oldNote->height()); // Idem: the only use of Note::setHeight()
|
|
|
|
|
}
|
|
|
|
|
Note* childs = decodeHierarchy(stream, parent, moveFiles, moveNotes, originalBasket);
|
|
|
|
|
if (childs) {
|
|
|
|
|
for (Note *n = childs; n; n = n->next())
|
|
|
|
|
n->setParentNote(note);
|
|
|
|
|
note->setFirstChild(childs);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
stream >> fileName >> fullPath >> addedDate >> lastModificationDate;
|
|
|
|
|
if (moveNotes) {
|
|
|
|
|
originalBasket->unplugNote(oldNote);
|
|
|
|
|
note = oldNote;
|
|
|
|
|
if (note->basket() != parent) {
|
|
|
|
|
TQString newFileName = NoteFactory::createFileForNewNote(parent, "", fileName);
|
|
|
|
|
note->content()->setFileName(newFileName);
|
|
|
|
|
TDEIO::FileCopyJob *copyJob = TDEIO::file_move(KURL(fullPath), KURL(parent->fullPath() + newFileName),
|
|
|
|
|
/*perms=*/-1, /*override=*/true, /*resume=*/false, /*showProgressInfo=*/false);
|
|
|
|
|
parent->connect( copyJob, TQT_SIGNAL(result(TDEIO::Job *)),
|
|
|
|
|
parent, TQT_SLOT(slotCopyingDone2(TDEIO::Job *)) );
|
|
|
|
|
}
|
|
|
|
|
note->setGroupWidth(groupWidth);
|
|
|
|
|
note->setParentNote(0);
|
|
|
|
|
note->setPrev(0);
|
|
|
|
|
note->setNext(0);
|
|
|
|
|
note->setParentBasket(parent);
|
|
|
|
|
NoteFactory::consumeContent(stream, (NoteType::Id)type);
|
|
|
|
|
} else if ( (note = NoteFactory::decodeContent(stream, (NoteType::Id)type, parent)) ) {
|
|
|
|
|
note->setGroupWidth(groupWidth);
|
|
|
|
|
note->setAddedDate(addedDate);
|
|
|
|
|
note->setLastModificationDate(lastModificationDate);
|
|
|
|
|
} else if (!fileName.isEmpty()) {
|
|
|
|
|
// Here we are CREATING a new EMPTY file, so the name is RESERVED
|
|
|
|
|
// (while dropping several files at once a filename cannot be used by two of them).
|
|
|
|
|
// Later on, file_copy/file_move will copy/move the file to the new location.
|
|
|
|
|
TQString newFileName = NoteFactory::createFileForNewNote(parent, "", fileName);
|
|
|
|
|
note = NoteFactory::loadFile(newFileName, (NoteType::Id)type, parent);
|
|
|
|
|
TDEIO::FileCopyJob *copyJob;
|
|
|
|
|
if (moveFiles)
|
|
|
|
|
copyJob = TDEIO::file_move(KURL(fullPath), KURL(parent->fullPath() + newFileName),
|
|
|
|
|
/*perms=*/-1, /*override=*/true, /*resume=*/false, /*showProgressInfo=*/false);
|
|
|
|
|
else
|
|
|
|
|
copyJob = TDEIO::file_copy(KURL(fullPath), KURL(parent->fullPath() + newFileName),
|
|
|
|
|
/*perms=*/-1, /*override=*/true, /*resume=*/false, /*showProgressInfo=*/false);
|
|
|
|
|
parent->connect( copyJob, TQT_SIGNAL(result(TDEIO::Job *)),
|
|
|
|
|
parent, TQT_SLOT(slotCopyingDone2(TDEIO::Job *)) );
|
|
|
|
|
note->setGroupWidth(groupWidth);
|
|
|
|
|
note->setAddedDate(addedDate);
|
|
|
|
|
note->setLastModificationDate(lastModificationDate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Retreive the states (tags) and assign them to the note:
|
|
|
|
|
if (note && note->content()) {
|
|
|
|
|
TQ_UINT64 statePointer;
|
|
|
|
|
do {
|
|
|
|
|
stream >> statePointer;
|
|
|
|
|
if (statePointer)
|
|
|
|
|
note->addState((State*)statePointer);
|
|
|
|
|
} while (statePointer);
|
|
|
|
|
}
|
|
|
|
|
// Now that we have created the note, insert it:
|
|
|
|
|
if (note) {
|
|
|
|
|
if (!firstNote)
|
|
|
|
|
firstNote = note;
|
|
|
|
|
else {
|
|
|
|
|
lastInserted->setNext(note);
|
|
|
|
|
note->setPrev(lastInserted);
|
|
|
|
|
}
|
|
|
|
|
lastInserted = note;
|
|
|
|
|
}
|
|
|
|
|
} while (true);
|
|
|
|
|
|
|
|
|
|
// We've done: return!
|
|
|
|
|
return firstNote;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ExtendedTextDrag */
|
|
|
|
|
|
|
|
|
|
bool ExtendedTextDrag::decode(const TQMimeSource *e, TQString &str)
|
|
|
|
|
{
|
|
|
|
|
TQCString subtype("plain");
|
|
|
|
|
return decode(e, str, subtype);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ExtendedTextDrag::decode(const TQMimeSource *e, TQString &str, TQCString &subtype)
|
|
|
|
|
{
|
|
|
|
|
// Get the string:
|
|
|
|
|
bool ok = TQTextDrag::decode(e, str, subtype);
|
|
|
|
|
|
|
|
|
|
// Test if it was a UTF-16 string (from eg. Mozilla):
|
|
|
|
|
if (str.length() >= 2) {
|
|
|
|
|
if ((str[0] == 0xFF && str[1] == 0xFE) || (str[0] == 0xFE && str[1] == 0xFF)) {
|
|
|
|
|
TQByteArray utf16 = e->encodedData(TQString("text/" + subtype).local8Bit());
|
|
|
|
|
str = TQTextCodec::codecForName("utf16")->toUnicode(utf16);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test if it was empty (sometimes, from GNOME or Mozilla)
|
|
|
|
|
if (str.length() == 0 && subtype == "plain") {
|
|
|
|
|
if (e->provides("UTF8_STRING")) {
|
|
|
|
|
TQByteArray utf8 = e->encodedData("UTF8_STRING");
|
|
|
|
|
str = TQTextCodec::codecForName("utf8")->toUnicode(utf8);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (e->provides("text/unicode")) { // FIXME: It's UTF-16 without order bytes!!!
|
|
|
|
|
TQByteArray utf16 = e->encodedData("text/unicode");
|
|
|
|
|
str = TQTextCodec::codecForName("utf16")->toUnicode(utf16);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (e->provides("TEXT")) { // local encoding
|
|
|
|
|
TQByteArray text = e->encodedData("TEXT");
|
|
|
|
|
str = TQString(text);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (e->provides("COMPOUND_TEXT")) { // local encoding
|
|
|
|
|
TQByteArray text = e->encodedData("COMPOUND_TEXT");
|
|
|
|
|
str = TQString(text);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include "notedrag.moc"
|