Ran qt3to4
[basket4.git] / src / archive.cpp
blob0b2fbe3e53452798fbbd0221d53a577bdb292a47
1 /***************************************************************************
2 * Copyright (C) 2006 by Sébastien Laoût *
3 * slaout@linux62.org *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
21 #include <qstring.h>
22 #include <qstringlist.h>
23 #include <q3valuelist.h>
24 #include <qmap.h>
25 #include <qdir.h>
26 //Added by qt3to4:
27 #include <Q3TextStream>
28 #include <ktar.h>
29 #include <qdom.h>
30 #include <kmessagebox.h>
31 #include <qpixmap.h>
32 #include <qpainter.h>
33 #include <kstandarddirs.h>
34 #include <kapplication.h>
35 #include <kiconloader.h>
36 #include <kprogress.h>
37 #include <kmainwindow.h>
39 #include "archive.h"
40 #include "global.h"
41 #include "bnpview.h"
42 #include "basket.h"
43 #include "basketlistview.h"
44 #include "basketfactory.h"
45 #include "tag.h"
46 #include "xmlwork.h"
47 #include "tools.h"
48 #include "backgroundmanager.h"
49 #include "formatimporter.h"
51 #include <iostream>
53 void Archive::save(Basket *basket, bool withSubBaskets, const QString &destination)
55 QDir dir;
57 KProgressDialog dialog(0, 0, i18n("Save as Basket Archive"), i18n("Saving as basket archive. Please wait..."), /*Not modal, for password dialogs!*/false);
58 dialog.showCancelButton(false);
59 dialog.setAutoClose(true);
60 dialog.show();
61 KProgress *progress = dialog.progressBar();
62 progress->setTotalSteps(/*Preparation:*/1 + /*Finishing:*/1 + /*Basket:*/1 + /*SubBaskets:*/(withSubBaskets ? Global::bnpView->basketCount(Global::bnpView->listViewItemForBasket(basket)) : 0));
63 progress->setValue(0);
65 // Create the temporar folder:
66 QString tempFolder = Global::savesFolder() + "temp-archive/";
67 dir.mkdir(tempFolder);
69 // Create the temporar archive file:
70 QString tempDestination = tempFolder + "temp-archive.tar.gz";
71 KTar tar(tempDestination, "application/x-gzip");
72 tar.open(QIODevice::WriteOnly);
73 tar.writeDir("baskets", "", "");
75 progress->advance(1); // Preparation finished
76 std::cout << "Preparation finished out of " << progress->totalSteps() << std::endl;
78 // Copy the baskets data into the archive:
79 QStringList backgrounds;
80 saveBasketToArchive(basket, withSubBaskets, &tar, backgrounds, tempFolder, progress);
82 // Create a Small baskets.xml Document:
83 QDomDocument document("basketTree");
84 QDomElement root = document.createElement("basketTree");
85 document.appendChild(root);
86 Global::bnpView->saveSubHierarchy(Global::bnpView->listViewItemForBasket(basket), document, root, withSubBaskets);
87 Basket::safelySaveToFile(tempFolder + "baskets.xml", "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + document.toString());
88 tar.addLocalFile(tempFolder + "baskets.xml", "baskets/baskets.xml");
89 dir.remove(tempFolder + "baskets.xml");
91 // Save a Small tags.xml Document:
92 Q3ValueList<Tag*> tags;
93 listUsedTags(basket, withSubBaskets, tags);
94 Tag::saveTagsTo(tags, tempFolder + "tags.xml");
95 tar.addLocalFile(tempFolder + "tags.xml", "tags.xml");
96 dir.remove(tempFolder + "tags.xml");
98 // Save Tag Emblems (in case they are loaded on a computer that do not have those icons):
99 QString tempIconFile = tempFolder + "icon.png";
100 for (Tag::List::iterator it = tags.begin(); it != tags.end(); ++it) {
101 State::List states = (*it)->states();
102 for (State::List::iterator it2 = states.begin(); it2 != states.end(); ++it2) {
103 State *state = (*it2);
104 QPixmap icon = kapp->iconLoader()->loadIcon(state->emblem(), KIcon::Small, 16, KIcon::DefaultState, /*path_store=*/0L, /*canReturnNull=*/true);
105 if (!icon.isNull()) {
106 icon.save(tempIconFile, "PNG");
107 QString iconFileName = state->emblem().replace('/', '_');
108 tar.addLocalFile(tempIconFile, "tag-emblems/" + iconFileName);
112 dir.remove(tempIconFile);
114 // Finish Tar.Gz Exportation:
115 tar.close();
117 // Computing the File Preview:
118 Basket *previewBasket = basket; // FIXME: Use the first non-empty basket!
119 QPixmap previewPixmap(previewBasket->visibleWidth(), previewBasket->visibleHeight());
120 QPainter painter(&previewPixmap);
121 // Save old state, and make the look clean ("smile, you are filmed!"):
122 NoteSelection *selection = previewBasket->selectedNotes();
123 previewBasket->unselectAll();
124 Note *focusedNote = previewBasket->focusedNote();
125 previewBasket->setFocusedNote(0);
126 previewBasket->doHoverEffects(0, Note::None);
127 // Take the screenshot:
128 previewBasket->drawContents(&painter, 0, 0, previewPixmap.width(), previewPixmap.height());
129 // Go back to the old look:
130 previewBasket->selectSelection(selection);
131 previewBasket->setFocusedNote(focusedNote);
132 previewBasket->doHoverEffects();
133 // End and save our splandid painting:
134 painter.end();
135 QImage previewImage = previewPixmap.convertToImage();
136 const int PREVIEW_SIZE = 256;
137 previewImage = previewImage.scale(PREVIEW_SIZE, PREVIEW_SIZE, QImage::ScaleMin);
138 previewImage.save(tempFolder + "preview.png", "PNG");
140 // Finaly Save to the Real Destination file:
141 QFile file(destination);
142 if (file.open(QIODevice::WriteOnly)) {
143 ulong previewSize = QFile(tempFolder + "preview.png").size();
144 ulong archiveSize = QFile(tempDestination).size();
145 Q3TextStream stream(&file);
146 stream.setEncoding(Q3TextStream::Latin1);
147 stream << "BasKetNP:archive\n"
148 << "version:0.6.1\n"
149 // << "read-compatible:0.6.1\n"
150 // << "write-compatible:0.6.1\n"
151 << "preview*:" << previewSize << "\n";
152 // Copy the Preview File:
153 const Q_ULONG BUFFER_SIZE = 1024;
154 char *buffer = new char[BUFFER_SIZE];
155 Q_LONG sizeRead;
156 QFile previewFile(tempFolder + "preview.png");
157 if (previewFile.open(QIODevice::ReadOnly)) {
158 while ((sizeRead = previewFile.readBlock(buffer, BUFFER_SIZE)) > 0)
159 file.writeBlock(buffer, sizeRead);
161 stream << "archive*:" << archiveSize << "\n";
162 // Copy the Archive File:
163 QFile archiveFile(tempDestination);
164 if (archiveFile.open(QIODevice::ReadOnly)) {
165 while ((sizeRead = archiveFile.readBlock(buffer, BUFFER_SIZE)) > 0)
166 file.writeBlock(buffer, sizeRead);
168 // Clean Up:
169 delete buffer;
170 buffer = 0;
171 file.close();
174 progress->advance(1); // Finishing finished
175 std::cout << "Finishing finished" << std::endl;
177 // Clean Up Everything:
178 dir.remove(tempFolder + "preview.png");
179 dir.remove(tempDestination);
180 dir.rmdir(tempFolder);
183 void Archive::saveBasketToArchive(Basket *basket, bool recursive, KTar *tar, QStringList &backgrounds, const QString &tempFolder, KProgress *progress)
185 // Basket need to be loaded for tags exportation.
186 // We load it NOW so that the progress bar really reflect the state of the exportation:
187 if (!basket->isLoaded()) {
188 basket->load();
191 QDir dir;
192 // Save basket data:
193 tar->addLocalDirectory(basket->fullPath(), "baskets/" + basket->folderName());
194 tar->addLocalFile(basket->fullPath() + ".basket", "baskets/" + basket->folderName() + ".basket"); // The hidden files were not added
195 // Save basket icon:
196 QString tempIconFile = tempFolder + "icon.png";
197 if (!basket->icon().isEmpty() && basket->icon() != "basket") {
198 QPixmap icon = kapp->iconLoader()->loadIcon(basket->icon(), KIcon::Small, 16, KIcon::DefaultState, /*path_store=*/0L, /*canReturnNull=*/true);
199 if (!icon.isNull()) {
200 icon.save(tempIconFile, "PNG");
201 QString iconFileName = basket->icon().replace('/', '_');
202 tar->addLocalFile(tempIconFile, "basket-icons/" + iconFileName);
205 // Save basket backgorund image:
206 QString imageName = basket->backgroundImageName();
207 if (!basket->backgroundImageName().isEmpty() && !backgrounds.contains(imageName)) {
208 QString backgroundPath = Global::backgroundManager->pathForImageName(imageName);
209 if (!backgroundPath.isEmpty()) {
210 // Save the background image:
211 tar->addLocalFile(backgroundPath, "backgrounds/" + imageName);
212 // Save the preview image:
213 QString previewPath = Global::backgroundManager->previewPathForImageName(imageName);
214 if (!previewPath.isEmpty())
215 tar->addLocalFile(previewPath, "backgrounds/previews/" + imageName);
216 // Save the configuration file:
217 QString configPath = backgroundPath + ".config";
218 if (dir.exists(configPath))
219 tar->addLocalFile(configPath, "backgrounds/" + imageName + ".config");
221 backgrounds.append(imageName);
224 progress->advance(1); // Basket exportation finished
225 std::cout << basket->basketName() << " finished" << std::endl;
227 // Recursively save child baskets:
228 BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
229 if (recursive && item->firstChild()) {
230 for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
231 saveBasketToArchive(child->basket(), recursive, tar, backgrounds, tempFolder, progress);
236 void Archive::listUsedTags(Basket *basket, bool recursive, Q3ValueList<Tag*> &list)
238 basket->listUsedTags(list);
239 BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
240 if (recursive && item->firstChild()) {
241 for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
242 listUsedTags(child->basket(), recursive, list);
247 void Archive::open(const QString &path)
249 // Create the temporar folder:
250 QString tempFolder = Global::savesFolder() + "temp-archive/";
251 QDir dir;
252 dir.mkdir(tempFolder);
253 const Q_ULONG BUFFER_SIZE = 1024;
255 QFile file(path);
256 if (file.open(QIODevice::ReadOnly)) {
257 Q3TextStream stream(&file);
258 stream.setEncoding(Q3TextStream::Latin1);
259 QString line = stream.readLine();
260 if (line != "BasKetNP:archive") {
261 KMessageBox::error(0, i18n("This file is not a basket archive."), i18n("Basket Archive Error"));
262 file.close();
263 Tools::deleteRecursively(tempFolder);
264 return;
266 QString version;
267 QStringList readCompatibleVersions;
268 QStringList writeCompatibleVersions;
269 while (!stream.atEnd()) {
270 // Get Key/Value Pair From the Line to Read:
271 line = stream.readLine();
272 int index = line.find(':');
273 QString key;
274 QString value;
275 if (index >= 0) {
276 key = line.left(index);
277 value = line.right(line.length() - index - 1);
278 } else {
279 key = line;
280 value = "";
282 if (key == "version") {
283 version = value;
284 } else if (key == "read-compatible") {
285 readCompatibleVersions = QStringList::split(value, ";");
286 } else if (key == "write-compatible") {
287 writeCompatibleVersions = QStringList::split(value, ";");
288 } else if (key == "preview*") {
289 bool ok;
290 ulong size = value.toULong(&ok);
291 if (!ok) {
292 KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
293 file.close();
294 Tools::deleteRecursively(tempFolder);
295 return;
297 // Get the preview file:
298 //FIXME: We do not need the preview for now
299 // QFile previewFile(tempFolder + "preview.png");
300 // if (previewFile.open(IO_WriteOnly)) {
301 char *buffer = new char[BUFFER_SIZE];
302 Q_LONG sizeRead;
303 while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
304 // previewFile.writeBlock(buffer, sizeRead);
305 size -= sizeRead;
307 // previewFile.close();
308 delete buffer;
309 // }
310 } else if (key == "archive*") {
311 if (version != "0.6.1" && readCompatibleVersions.contains("0.6.1") && !writeCompatibleVersions.contains("0.6.1")) {
312 KMessageBox::information(
314 i18n("This file was created with a recent version of %1. "
315 "It can be opened but not every information will be available to you. "
316 "For instance, some notes may be missing because they are of a type only available in new versions. "
317 "When saving the file back, consider to save it to another file, to preserve the original one.")
318 .arg(kapp->aboutData()->programName()),
319 i18n("Basket Archive Error")
322 if (version != "0.6.1" && !readCompatibleVersions.contains("0.6.1") && !writeCompatibleVersions.contains("0.6.1")) {
323 KMessageBox::error(
325 i18n("This file was created with a recent version of %1. Please upgrade to a newer version to be able to open that file.")
326 .arg(kapp->aboutData()->programName()),
327 i18n("Basket Archive Error")
329 file.close();
330 Tools::deleteRecursively(tempFolder);
331 return;
334 bool ok;
335 ulong size = value.toULong(&ok);
336 if (!ok) {
337 KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
338 file.close();
339 Tools::deleteRecursively(tempFolder);
340 return;
343 Global::mainWindow()->raise();
345 // Get the archive file:
346 QString tempArchive = tempFolder + "temp-archive.tar.gz";
347 QFile archiveFile(tempArchive);
348 if (archiveFile.open(QIODevice::WriteOnly)) {
349 char *buffer = new char[BUFFER_SIZE];
350 Q_LONG sizeRead;
351 while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
352 archiveFile.writeBlock(buffer, sizeRead);
353 size -= sizeRead;
355 archiveFile.close();
356 delete buffer;
358 // Extract the Archive:
359 QString extractionFolder = tempFolder + "extraction/";
360 QDir dir;
361 dir.mkdir(extractionFolder);
362 KTar tar(tempArchive, "application/x-gzip");
363 tar.open(QIODevice::ReadOnly);
364 tar.directory()->copyTo(extractionFolder);
365 tar.close();
367 // Import the Tags:
368 importTagEmblems(extractionFolder); // Import and rename tag emblems BEFORE loading them!
369 QMap<QString, QString> mergedStates = Tag::loadTags(extractionFolder + "tags.xml");
370 QMap<QString, QString>::Iterator it;
371 if (mergedStates.count() > 0) {
372 Tag::saveTags();
375 // Import the Background Images:
376 importArchivedBackgroundImages(extractionFolder);
378 // Import the Baskets:
379 renameBasketFolders(extractionFolder, mergedStates);
382 } else if (key.endsWith("*")) {
383 // We do not know what it is, but we should read the embedded-file in order to discard it:
384 bool ok;
385 ulong size = value.toULong(&ok);
386 if (!ok) {
387 KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
388 file.close();
389 Tools::deleteRecursively(tempFolder);
390 return;
392 // Get the archive file:
393 char *buffer = new char[BUFFER_SIZE];
394 Q_LONG sizeRead;
395 while ((sizeRead = file.readBlock(buffer, QMIN(BUFFER_SIZE, size))) > 0) {
396 size -= sizeRead;
398 delete buffer;
399 } else {
400 // We do not know what it is, and we do not care.
402 // Analyse the Value, if Understood:
404 file.close();
406 Tools::deleteRecursively(tempFolder);
410 * When opening a basket archive that come from another computer,
411 * it can contains tags that use icons (emblems) that are not present on that computer.
412 * Fortunately, basket archives contains a copy of every used icons.
413 * This method check for every emblems and import the missing ones.
414 * It also modify the tags.xml copy for the emblems to point to the absolute path of the impported icons.
416 void Archive::importTagEmblems(const QString &extractionFolder)
418 QDomDocument *document = XMLWork::openFile("basketTags", extractionFolder + "tags.xml");
419 if (document == 0)
420 return;
421 QDomElement docElem = document->documentElement();
423 QDir dir;
424 dir.mkdir(Global::savesFolder() + "tag-emblems/");
425 FormatImporter copier; // Only used to copy files synchronously
427 QDomNode node = docElem.firstChild();
428 while (!node.isNull()) {
429 QDomElement element = node.toElement();
430 if ( (!element.isNull()) && element.tagName() == "tag" ) {
431 QDomNode subNode = element.firstChild();
432 while (!subNode.isNull()) {
433 QDomElement subElement = subNode.toElement();
434 if ( (!subElement.isNull()) && subElement.tagName() == "state" ) {
435 QString emblemName = XMLWork::getElementText(subElement, "emblem");
436 if (!emblemName.isEmpty()) {
437 QPixmap emblem = kapp->iconLoader()->loadIcon(emblemName, KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
438 // The icon does not exists on that computer, import it:
439 if (emblem.isNull()) {
440 // Of the emblem path was eg. "/home/seb/emblem.png", it was exported as "tag-emblems/_home_seb_emblem.png".
441 // So we need to copy that image to "~/.kde/share/apps/basket/tag-emblems/emblem.png":
442 int slashIndex = emblemName.findRev("/");
443 QString emblemFileName = (slashIndex < 0 ? emblemName : emblemName.right(slashIndex - 2));
444 QString source = extractionFolder + "tag-emblems/" + emblemName.replace('/', '_');
445 QString destination = Global::savesFolder() + "tag-emblems/" + emblemFileName;
446 if (!dir.exists(destination))
447 copier.copyFolder(source, destination);
448 // Replace the emblem path in the tags.xml copy:
449 QDomElement emblemElement = XMLWork::getElement(subElement, "emblem");
450 subElement.removeChild(emblemElement);
451 XMLWork::addElement(*document, subElement, "emblem", destination);
455 subNode = subNode.nextSibling();
458 node = node.nextSibling();
460 Basket::safelySaveToFile(extractionFolder + "tags.xml", document->toString());
463 void Archive::importArchivedBackgroundImages(const QString &extractionFolder)
465 FormatImporter copier; // Only used to copy files synchronously
466 QString destFolder = KGlobal::dirs()->saveLocation("data", "basket/backgrounds/");
468 QDir dir(extractionFolder + "backgrounds/", /*nameFilder=*/"*.png", /*sortSpec=*/QDir::Name | QDir::IgnoreCase, /*filterSpec=*/QDir::Files | QDir::NoSymLinks);
469 QStringList files = dir.entryList();
470 for (QStringList::Iterator it = files.begin(); it != files.end(); ++it) {
471 QString image = *it;
472 if (!Global::backgroundManager->exists(image)) {
473 // Copy images:
474 QString imageSource = extractionFolder + "backgrounds/" + image;
475 QString imageDest = destFolder + image;
476 copier.copyFolder(imageSource, imageDest);
477 // Copy configuration file:
478 QString configSource = extractionFolder + "backgrounds/" + image + ".config";
479 QString configDest = destFolder + image;
480 if (dir.exists(configSource))
481 copier.copyFolder(configSource, configDest);
482 // Copy preview:
483 QString previewSource = extractionFolder + "backgrounds/previews/" + image;
484 QString previewDest = destFolder + "previews/" + image;
485 if (dir.exists(previewSource)) {
486 dir.mkdir(destFolder + "previews/"); // Make sure the folder exists!
487 copier.copyFolder(previewSource, previewDest);
489 // Append image to database:
490 Global::backgroundManager->addImage(imageDest);
495 void Archive::renameBasketFolders(const QString &extractionFolder, QMap<QString, QString> &mergedStates)
497 QDomDocument *doc = XMLWork::openFile("basketTree", extractionFolder + "baskets/baskets.xml");
498 if (doc != 0) {
499 QMap<QString, QString> folderMap;
500 QDomElement docElem = doc->documentElement();
501 QDomNode node = docElem.firstChild();
502 renameBasketFolder(extractionFolder, node, folderMap, mergedStates);
503 loadExtractedBaskets(extractionFolder, node, folderMap, 0);
507 void Archive::renameBasketFolder(const QString &extractionFolder, QDomNode &basketNode, QMap<QString, QString> &folderMap, QMap<QString, QString> &mergedStates)
509 QDomNode n = basketNode;
510 while ( ! n.isNull() ) {
511 QDomElement element = n.toElement();
512 if ( (!element.isNull()) && element.tagName() == "basket" ) {
513 QString folderName = element.attribute("folderName");
514 if (!folderName.isEmpty()) {
515 // Find a folder name:
516 QString newFolderName = BasketFactory::newFolderName();
517 folderMap[folderName] = newFolderName;
518 // Reserve the folder name:
519 QDir dir;
520 dir.mkdir(Global::basketsFolder() + newFolderName);
521 // Rename the merged tag ids:
522 // if (mergedStates.count() > 0) {
523 renameMergedStatesAndBasketIcon(extractionFolder + "baskets/" + folderName + ".basket", mergedStates, extractionFolder);
524 // }
525 // Child baskets:
526 QDomNode node = element.firstChild();
527 renameBasketFolder(extractionFolder, node, folderMap, mergedStates);
530 n = n.nextSibling();
534 void Archive::renameMergedStatesAndBasketIcon(const QString &fullPath, QMap<QString, QString> &mergedStates, const QString &extractionFolder)
536 QDomDocument *doc = XMLWork::openFile("basket", fullPath);
537 if (doc == 0)
538 return;
539 QDomElement docElem = doc->documentElement();
540 QDomElement properties = XMLWork::getElement(docElem, "properties");
541 importBasketIcon(properties, extractionFolder);
542 QDomElement notes = XMLWork::getElement(docElem, "notes");
543 if (mergedStates.count() > 0)
544 renameMergedStates(notes, mergedStates);
545 Basket::safelySaveToFile(fullPath, /*"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + */doc->toString());
548 void Archive::importBasketIcon(QDomElement properties, const QString &extractionFolder)
550 QString iconName = XMLWork::getElementText(properties, "icon");
551 if (!iconName.isEmpty() && iconName != "basket") {
552 QPixmap icon = kapp->iconLoader()->loadIcon(iconName, KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
553 // The icon does not exists on that computer, import it:
554 if (icon.isNull()) {
555 QDir dir;
556 dir.mkdir(Global::savesFolder() + "basket-icons/");
557 FormatImporter copier; // Only used to copy files synchronously
558 // Of the icon path was eg. "/home/seb/icon.png", it was exported as "basket-icons/_home_seb_icon.png".
559 // So we need to copy that image to "~/.kde/share/apps/basket/basket-icons/icon.png":
560 int slashIndex = iconName.findRev("/");
561 QString iconFileName = (slashIndex < 0 ? iconName : iconName.right(slashIndex - 2));
562 QString source = extractionFolder + "basket-icons/" + iconName.replace('/', '_');
563 QString destination = Global::savesFolder() + "basket-icons/" + iconFileName;
564 if (!dir.exists(destination))
565 copier.copyFolder(source, destination);
566 // Replace the emblem path in the tags.xml copy:
567 QDomElement iconElement = XMLWork::getElement(properties, "icon");
568 properties.removeChild(iconElement);
569 QDomDocument document = properties.ownerDocument();
570 XMLWork::addElement(document, properties, "icon", destination);
575 void Archive::renameMergedStates(QDomNode notes, QMap<QString, QString> &mergedStates)
577 QDomNode n = notes.firstChild();
578 while ( ! n.isNull() ) {
579 QDomElement element = n.toElement();
580 if (!element.isNull()) {
581 if (element.tagName() == "group" ) {
582 renameMergedStates(n, mergedStates);
583 } else if (element.tagName() == "note") {
584 QString tags = XMLWork::getElementText(element, "tags");
585 if (!tags.isEmpty()) {
586 QStringList tagNames = QStringList::split(";", tags);
587 for (QStringList::Iterator it = tagNames.begin(); it != tagNames.end(); ++it) {
588 QString &tag = *it;
589 if (mergedStates.contains(tag)) {
590 tag = mergedStates[tag];
593 QString newTags = tagNames.join(";");
594 QDomElement tagsElement = XMLWork::getElement(element, "tags");
595 element.removeChild(tagsElement);
596 QDomDocument document = element.ownerDocument();
597 XMLWork::addElement(document, element, "tags", newTags);
601 n = n.nextSibling();
605 void Archive::loadExtractedBaskets(const QString &extractionFolder, QDomNode &basketNode, QMap<QString, QString> &folderMap, Basket *parent)
607 bool basketSetAsCurrent = (parent != 0);
608 QDomNode n = basketNode;
609 while ( ! n.isNull() ) {
610 QDomElement element = n.toElement();
611 if ( (!element.isNull()) && element.tagName() == "basket" ) {
612 QString folderName = element.attribute("folderName");
613 if (!folderName.isEmpty()) {
614 // Move the basket folder to its destination, while renaming it uniquely:
615 QString newFolderName = folderMap[folderName];
616 FormatImporter copier;
617 // The folder has been "reserved" by creating it. Avoid asking the user to override:
618 QDir dir;
619 dir.rmdir(Global::basketsFolder() + newFolderName);
620 copier.moveFolder(extractionFolder + "baskets/" + folderName, Global::basketsFolder() + newFolderName);
621 // Append and load the basket in the tree:
622 Basket *basket = Global::bnpView->loadBasket(newFolderName);
623 BasketListViewItem *basketItem = Global::bnpView->appendBasket(basket, (basket && parent ? Global::bnpView->listViewItemForBasket(parent) : 0));
624 basketItem->setOpen(!XMLWork::trueOrFalse(element.attribute("folded", "false"), false));
625 QDomElement properties = XMLWork::getElement(element, "properties");
626 importBasketIcon(properties, extractionFolder); // Rename the icon fileName if necessary
627 basket->loadProperties(properties);
628 // Open the first basket of the archive:
629 if (!basketSetAsCurrent) {
630 Global::bnpView->setCurrentBasket(basket);
631 basketSetAsCurrent = true;
633 QDomNode node = element.firstChild();
634 loadExtractedBaskets(extractionFolder, node, folderMap, basket);
637 n = n.nextSibling();