1 /***************************************************************************
2 * Copyright (C) 2006 by Sébastien Laoût *
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. *
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. *
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 ***************************************************************************/
22 #include <qstringlist.h>
23 #include <q3valuelist.h>
27 #include <Q3TextStream>
30 #include <kmessagebox.h>
33 #include <kstandarddirs.h>
34 #include <kapplication.h>
35 #include <kiconloader.h>
36 #include <kprogress.h>
37 #include <kmainwindow.h>
43 #include "basketlistview.h"
44 #include "basketfactory.h"
48 #include "backgroundmanager.h"
49 #include "formatimporter.h"
53 void Archive::save(Basket
*basket
, bool withSubBaskets
, const QString
&destination
)
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);
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:
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:
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"
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
];
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
);
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()) {
193 tar
->addLocalDirectory(basket
->fullPath(), "baskets/" + basket
->folderName());
194 tar
->addLocalFile(basket
->fullPath() + ".basket", "baskets/" + basket
->folderName() + ".basket"); // The hidden files were not added
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/";
252 dir
.mkdir(tempFolder
);
253 const Q_ULONG BUFFER_SIZE
= 1024;
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"));
263 Tools::deleteRecursively(tempFolder
);
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(':');
276 key
= line
.left(index
);
277 value
= line
.right(line
.length() - index
- 1);
282 if (key
== "version") {
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*") {
290 ulong size
= value
.toULong(&ok
);
292 KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
294 Tools::deleteRecursively(tempFolder
);
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
];
303 while ((sizeRead
= file
.readBlock(buffer
, QMIN(BUFFER_SIZE
, size
))) > 0) {
304 // previewFile.writeBlock(buffer, sizeRead);
307 // previewFile.close();
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")) {
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")
330 Tools::deleteRecursively(tempFolder
);
335 ulong size
= value
.toULong(&ok
);
337 KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
339 Tools::deleteRecursively(tempFolder
);
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
];
351 while ((sizeRead
= file
.readBlock(buffer
, QMIN(BUFFER_SIZE
, size
))) > 0) {
352 archiveFile
.writeBlock(buffer
, sizeRead
);
358 // Extract the Archive:
359 QString extractionFolder
= tempFolder
+ "extraction/";
361 dir
.mkdir(extractionFolder
);
362 KTar
tar(tempArchive
, "application/x-gzip");
363 tar
.open(QIODevice::ReadOnly
);
364 tar
.directory()->copyTo(extractionFolder
);
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) {
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:
385 ulong size
= value
.toULong(&ok
);
387 KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
389 Tools::deleteRecursively(tempFolder
);
392 // Get the archive file:
393 char *buffer
= new char[BUFFER_SIZE
];
395 while ((sizeRead
= file
.readBlock(buffer
, QMIN(BUFFER_SIZE
, size
))) > 0) {
400 // We do not know what it is, and we do not care.
402 // Analyse the Value, if Understood:
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");
421 QDomElement docElem
= document
->documentElement();
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
) {
472 if (!Global::backgroundManager
->exists(image
)) {
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
);
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");
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:
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
);
526 QDomNode node
= element
.firstChild();
527 renameBasketFolder(extractionFolder
, node
, folderMap
, mergedStates
);
534 void Archive::renameMergedStatesAndBasketIcon(const QString
&fullPath
, QMap
<QString
, QString
> &mergedStates
, const QString
&extractionFolder
)
536 QDomDocument
*doc
= XMLWork::openFile("basket", fullPath
);
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:
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
) {
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
);
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:
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
);