|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2006 by Sébastien Laoût *
|
|
|
|
* 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. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <tqstring.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqvaluelist.h>
|
|
|
|
#include <tqmap.h>
|
|
|
|
#include <tqdir.h>
|
|
|
|
#include <ktar.h>
|
|
|
|
#include <tqdom.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <tqpixmap.h>
|
|
|
|
#include <tqpainter.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kprogress.h>
|
|
|
|
#include <kmainwindow.h>
|
|
|
|
|
|
|
|
#include "archive.h"
|
|
|
|
#include "global.h"
|
|
|
|
#include "bnpview.h"
|
|
|
|
#include "basket.h"
|
|
|
|
#include "basketlistview.h"
|
|
|
|
#include "basketfactory.h"
|
|
|
|
#include "tag.h"
|
|
|
|
#include "xmlwork.h"
|
|
|
|
#include "tools.h"
|
|
|
|
#include "backgroundmanager.h"
|
|
|
|
#include "formatimporter.h"
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
void Archive::save(Basket *basket, bool withSubBaskets, const TQString &destination)
|
|
|
|
{
|
|
|
|
TQDir dir;
|
|
|
|
|
|
|
|
KProgressDialog dialog(0, 0, i18n("Save as Basket Archive"), i18n("Saving as basket archive. Please wait..."), /*Not modal, for password dialogs!*/false);
|
|
|
|
dialog.showCancelButton(false);
|
|
|
|
dialog.setAutoClose(true);
|
|
|
|
dialog.show();
|
|
|
|
KProgress *progress = dialog.progressBar();
|
|
|
|
progress->setTotalSteps(/*Preparation:*/1 + /*Finishing:*/1 + /*Basket:*/1 + /*SubBaskets:*/(withSubBaskets ? Global::bnpView->basketCount(Global::bnpView->listViewItemForBasket(basket)) : 0));
|
|
|
|
progress->setValue(0);
|
|
|
|
|
|
|
|
// Create the temporar folder:
|
|
|
|
TQString tempFolder = Global::savesFolder() + "temp-archive/";
|
|
|
|
dir.mkdir(tempFolder);
|
|
|
|
|
|
|
|
// Create the temporar archive file:
|
|
|
|
TQString tempDestination = tempFolder + "temp-archive.tar.gz";
|
|
|
|
KTar tar(tempDestination, "application/x-gzip");
|
|
|
|
tar.open(IO_WriteOnly);
|
|
|
|
tar.writeDir("baskets", "", "");
|
|
|
|
|
|
|
|
progress->advance(1); // Preparation finished
|
|
|
|
std::cout << "Preparation finished out of " << progress->totalSteps() << std::endl;
|
|
|
|
|
|
|
|
// Copy the baskets data into the archive:
|
|
|
|
TQStringList backgrounds;
|
|
|
|
saveBasketToArchive(basket, withSubBaskets, &tar, backgrounds, tempFolder, progress);
|
|
|
|
|
|
|
|
// Create a Small baskets.xml Document:
|
|
|
|
TQDomDocument document("basketTree");
|
|
|
|
TQDomElement root = document.createElement("basketTree");
|
|
|
|
document.appendChild(root);
|
|
|
|
Global::bnpView->saveSubHierarchy(Global::bnpView->listViewItemForBasket(basket), document, root, withSubBaskets);
|
|
|
|
Basket::safelySaveToFile(tempFolder + "baskets.xml", "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + document.toString());
|
|
|
|
tar.addLocalFile(tempFolder + "baskets.xml", "baskets/baskets.xml");
|
|
|
|
dir.remove(tempFolder + "baskets.xml");
|
|
|
|
|
|
|
|
// Save a Small tags.xml Document:
|
|
|
|
TQValueList<Tag*> tags;
|
|
|
|
listUsedTags(basket, withSubBaskets, tags);
|
|
|
|
Tag::saveTagsTo(tags, tempFolder + "tags.xml");
|
|
|
|
tar.addLocalFile(tempFolder + "tags.xml", "tags.xml");
|
|
|
|
dir.remove(tempFolder + "tags.xml");
|
|
|
|
|
|
|
|
// Save Tag Emblems (in case they are loaded on a computer that do not have those icons):
|
|
|
|
TQString tempIconFile = tempFolder + "icon.png";
|
|
|
|
for (Tag::List::iterator it = tags.begin(); it != tags.end(); ++it) {
|
|
|
|
State::List states = (*it)->states();
|
|
|
|
for (State::List::iterator it2 = states.begin(); it2 != states.end(); ++it2) {
|
|
|
|
State *state = (*it2);
|
|
|
|
TQPixmap icon = kapp->iconLoader()->loadIcon(state->emblem(), KIcon::Small, 16, KIcon::DefaultState, /*path_store=*/0L, /*canReturnNull=*/true);
|
|
|
|
if (!icon.isNull()) {
|
|
|
|
icon.save(tempIconFile, "PNG");
|
|
|
|
TQString iconFileName = state->emblem().replace('/', '_');
|
|
|
|
tar.addLocalFile(tempIconFile, "tag-emblems/" + iconFileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dir.remove(tempIconFile);
|
|
|
|
|
|
|
|
// Finish Tar.Gz Exportation:
|
|
|
|
tar.close();
|
|
|
|
|
|
|
|
// Computing the File Preview:
|
|
|
|
Basket *previewBasket = basket; // FIXME: Use the first non-empty basket!
|
|
|
|
TQPixmap previewPixmap(previewBasket->visibleWidth(), previewBasket->visibleHeight());
|
|
|
|
TQPainter painter(&previewPixmap);
|
|
|
|
// Save old state, and make the look clean ("smile, you are filmed!"):
|
|
|
|
NoteSelection *selection = previewBasket->selectedNotes();
|
|
|
|
previewBasket->unselectAll();
|
|
|
|
Note *focusedNote = previewBasket->focusedNote();
|
|
|
|
previewBasket->setFocusedNote(0);
|
|
|
|
previewBasket->doHoverEffects(0, Note::None);
|
|
|
|
// Take the screenshot:
|
|
|
|
previewBasket->drawContents(&painter, 0, 0, previewPixmap.width(), previewPixmap.height());
|
|
|
|
// Go back to the old look:
|
|
|
|
previewBasket->selectSelection(selection);
|
|
|
|
previewBasket->setFocusedNote(focusedNote);
|
|
|
|
previewBasket->doHoverEffects();
|
|
|
|
// End and save our splandid painting:
|
|
|
|
painter.end();
|
|
|
|
TQImage previewImage = previewPixmap.convertToImage();
|
|
|
|
const int PREVIEW_SIZE = 256;
|
|
|
|
previewImage = previewImage.scale(PREVIEW_SIZE, PREVIEW_SIZE, TQ_ScaleMin);
|
|
|
|
previewImage.save(tempFolder + "preview.png", "PNG");
|
|
|
|
|
|
|
|
// Finaly Save to the Real Destination file:
|
|
|
|
TQFile file(destination);
|
|
|
|
if (file.open(IO_WriteOnly)) {
|
|
|
|
ulong previewSize = TQFile(tempFolder + "preview.png").size();
|
|
|
|
ulong archiveSize = TQFile(tempDestination).size();
|
|
|
|
TQTextStream stream(&file);
|
|
|
|
stream.setEncoding(TQTextStream::Latin1);
|
|
|
|
stream << "BasKetNP:archive\n"
|
|
|
|
<< "version:0.6.1\n"
|
|
|
|
// << "read-compatible:0.6.1\n"
|
|
|
|
// << "write-compatible:0.6.1\n"
|
|
|
|
<< "preview*:" << previewSize << "\n";
|
|
|
|
// Copy the Preview File:
|
|
|
|
const TQ_ULONG BUFFER_SIZE = 1024;
|
|
|
|
char *buffer = new char[BUFFER_SIZE];
|
|
|
|
TQ_LONG sizeRead;
|
|
|
|
TQFile previewFile(tempFolder + "preview.png");
|
|
|
|
if (previewFile.open(IO_ReadOnly)) {
|
|
|
|
while ((sizeRead = previewFile.readBlock(buffer, BUFFER_SIZE)) > 0)
|
|
|
|
file.writeBlock(buffer, sizeRead);
|
|
|
|
}
|
|
|
|
stream << "archive*:" << archiveSize << "\n";
|
|
|
|
// Copy the Archive File:
|
|
|
|
TQFile archiveFile(tempDestination);
|
|
|
|
if (archiveFile.open(IO_ReadOnly)) {
|
|
|
|
while ((sizeRead = archiveFile.readBlock(buffer, BUFFER_SIZE)) > 0)
|
|
|
|
file.writeBlock(buffer, sizeRead);
|
|
|
|
}
|
|
|
|
// Clean Up:
|
|
|
|
delete buffer;
|
|
|
|
buffer = 0;
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
progress->advance(1); // Finishing finished
|
|
|
|
std::cout << "Finishing finished" << std::endl;
|
|
|
|
|
|
|
|
// Clean Up Everything:
|
|
|
|
dir.remove(tempFolder + "preview.png");
|
|
|
|
dir.remove(tempDestination);
|
|
|
|
dir.rmdir(tempFolder);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::saveBasketToArchive(Basket *basket, bool recursive, KTar *tar, TQStringList &backgrounds, const TQString &tempFolder, KProgress *progress)
|
|
|
|
{
|
|
|
|
// Basket need to be loaded for tags exportation.
|
|
|
|
// We load it NOW so that the progress bar really reflect the state of the exportation:
|
|
|
|
if (!basket->isLoaded()) {
|
|
|
|
basket->load();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDir dir;
|
|
|
|
// Save basket data:
|
|
|
|
tar->addLocalDirectory(basket->fullPath(), "baskets/" + basket->folderName());
|
|
|
|
tar->addLocalFile(basket->fullPath() + ".basket", "baskets/" + basket->folderName() + ".basket"); // The hidden files were not added
|
|
|
|
// Save basket icon:
|
|
|
|
TQString tempIconFile = tempFolder + "icon.png";
|
|
|
|
if (!basket->icon().isEmpty() && basket->icon() != "basket") {
|
|
|
|
TQPixmap icon = kapp->iconLoader()->loadIcon(basket->icon(), KIcon::Small, 16, KIcon::DefaultState, /*path_store=*/0L, /*canReturnNull=*/true);
|
|
|
|
if (!icon.isNull()) {
|
|
|
|
icon.save(tempIconFile, "PNG");
|
|
|
|
TQString iconFileName = basket->icon().replace('/', '_');
|
|
|
|
tar->addLocalFile(tempIconFile, "basket-icons/" + iconFileName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Save basket backgorund image:
|
|
|
|
TQString imageName = basket->backgroundImageName();
|
|
|
|
if (!basket->backgroundImageName().isEmpty() && !backgrounds.contains(imageName)) {
|
|
|
|
TQString backgroundPath = Global::backgroundManager->pathForImageName(imageName);
|
|
|
|
if (!backgroundPath.isEmpty()) {
|
|
|
|
// Save the background image:
|
|
|
|
tar->addLocalFile(backgroundPath, "backgrounds/" + imageName);
|
|
|
|
// Save the preview image:
|
|
|
|
TQString previewPath = Global::backgroundManager->previewPathForImageName(imageName);
|
|
|
|
if (!previewPath.isEmpty())
|
|
|
|
tar->addLocalFile(previewPath, "backgrounds/previews/" + imageName);
|
|
|
|
// Save the configuration file:
|
|
|
|
TQString configPath = backgroundPath + ".config";
|
|
|
|
if (dir.exists(configPath))
|
|
|
|
tar->addLocalFile(configPath, "backgrounds/" + imageName + ".config");
|
|
|
|
}
|
|
|
|
backgrounds.append(imageName);
|
|
|
|
}
|
|
|
|
|
|
|
|
progress->advance(1); // Basket exportation finished
|
|
|
|
std::cout << basket->basketName() << " finished" << std::endl;
|
|
|
|
|
|
|
|
// Recursively save child baskets:
|
|
|
|
BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
|
|
|
|
if (recursive && item->firstChild()) {
|
|
|
|
for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
|
|
|
|
saveBasketToArchive(child->basket(), recursive, tar, backgrounds, tempFolder, progress);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::listUsedTags(Basket *basket, bool recursive, TQValueList<Tag*> &list)
|
|
|
|
{
|
|
|
|
basket->listUsedTags(list);
|
|
|
|
BasketListViewItem *item = Global::bnpView->listViewItemForBasket(basket);
|
|
|
|
if (recursive && item->firstChild()) {
|
|
|
|
for (BasketListViewItem *child = (BasketListViewItem*) item->firstChild(); child; child = (BasketListViewItem*) child->nextSibling()) {
|
|
|
|
listUsedTags(child->basket(), recursive, list);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::open(const TQString &path)
|
|
|
|
{
|
|
|
|
// Create the temporar folder:
|
|
|
|
TQString tempFolder = Global::savesFolder() + "temp-archive/";
|
|
|
|
TQDir dir;
|
|
|
|
dir.mkdir(tempFolder);
|
|
|
|
const TQ_ULONG BUFFER_SIZE = 1024;
|
|
|
|
|
|
|
|
TQFile file(path);
|
|
|
|
if (file.open(IO_ReadOnly)) {
|
|
|
|
TQTextStream stream(&file);
|
|
|
|
stream.setEncoding(TQTextStream::Latin1);
|
|
|
|
TQString line = stream.readLine();
|
|
|
|
if (line != "BasKetNP:archive") {
|
|
|
|
KMessageBox::error(0, i18n("This file is not a basket archive."), i18n("Basket Archive Error"));
|
|
|
|
file.close();
|
|
|
|
Tools::deleteRecursively(tempFolder);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
TQString version;
|
|
|
|
TQStringList readCompatibleVersions;
|
|
|
|
TQStringList writeCompatibleVersions;
|
|
|
|
while (!stream.atEnd()) {
|
|
|
|
// Get Key/Value Pair From the Line to Read:
|
|
|
|
line = stream.readLine();
|
|
|
|
int index = line.find(':');
|
|
|
|
TQString key;
|
|
|
|
TQString value;
|
|
|
|
if (index >= 0) {
|
|
|
|
key = line.left(index);
|
|
|
|
value = line.right(line.length() - index - 1);
|
|
|
|
} else {
|
|
|
|
key = line;
|
|
|
|
value = "";
|
|
|
|
}
|
|
|
|
if (key == "version") {
|
|
|
|
version = value;
|
|
|
|
} else if (key == "read-compatible") {
|
|
|
|
readCompatibleVersions = TQStringList::split(value, ";");
|
|
|
|
} else if (key == "write-compatible") {
|
|
|
|
writeCompatibleVersions = TQStringList::split(value, ";");
|
|
|
|
} else if (key == "preview*") {
|
|
|
|
bool ok;
|
|
|
|
ulong size = value.toULong(&ok);
|
|
|
|
if (!ok) {
|
|
|
|
KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
|
|
|
|
file.close();
|
|
|
|
Tools::deleteRecursively(tempFolder);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Get the preview file:
|
|
|
|
//FIXME: We do not need the preview for now
|
|
|
|
// TQFile previewFile(tempFolder + "preview.png");
|
|
|
|
// if (previewFile.open(IO_WriteOnly)) {
|
|
|
|
char *buffer = new char[BUFFER_SIZE];
|
|
|
|
TQ_LONG sizeRead;
|
|
|
|
while ((sizeRead = file.readBlock(buffer, TQMIN(BUFFER_SIZE, size))) > 0) {
|
|
|
|
// previewFile.writeBlock(buffer, sizeRead);
|
|
|
|
size -= sizeRead;
|
|
|
|
}
|
|
|
|
// previewFile.close();
|
|
|
|
delete buffer;
|
|
|
|
// }
|
|
|
|
} else if (key == "archive*") {
|
|
|
|
if (version != "0.6.1" && readCompatibleVersions.contains("0.6.1") && !writeCompatibleVersions.contains("0.6.1")) {
|
|
|
|
KMessageBox::information(
|
|
|
|
0,
|
|
|
|
i18n("This file was created with a recent version of %1. "
|
|
|
|
"It can be opened but not every information will be available to you. "
|
|
|
|
"For instance, some notes may be missing because they are of a type only available in new versions. "
|
|
|
|
"When saving the file back, consider to save it to another file, to preserve the original one.")
|
|
|
|
.tqarg(kapp->aboutData()->programName()),
|
|
|
|
i18n("Basket Archive Error")
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (version != "0.6.1" && !readCompatibleVersions.contains("0.6.1") && !writeCompatibleVersions.contains("0.6.1")) {
|
|
|
|
KMessageBox::error(
|
|
|
|
0,
|
|
|
|
i18n("This file was created with a recent version of %1. Please upgrade to a newer version to be able to open that file.")
|
|
|
|
.tqarg(kapp->aboutData()->programName()),
|
|
|
|
i18n("Basket Archive Error")
|
|
|
|
);
|
|
|
|
file.close();
|
|
|
|
Tools::deleteRecursively(tempFolder);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok;
|
|
|
|
ulong size = value.toULong(&ok);
|
|
|
|
if (!ok) {
|
|
|
|
KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
|
|
|
|
file.close();
|
|
|
|
Tools::deleteRecursively(tempFolder);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Global::mainWindow()->raise();
|
|
|
|
|
|
|
|
// Get the archive file:
|
|
|
|
TQString tempArchive = tempFolder + "temp-archive.tar.gz";
|
|
|
|
TQFile archiveFile(tempArchive);
|
|
|
|
if (archiveFile.open(IO_WriteOnly)) {
|
|
|
|
char *buffer = new char[BUFFER_SIZE];
|
|
|
|
TQ_LONG sizeRead;
|
|
|
|
while ((sizeRead = file.readBlock(buffer, TQMIN(BUFFER_SIZE, size))) > 0) {
|
|
|
|
archiveFile.writeBlock(buffer, sizeRead);
|
|
|
|
size -= sizeRead;
|
|
|
|
}
|
|
|
|
archiveFile.close();
|
|
|
|
delete buffer;
|
|
|
|
|
|
|
|
// Extract the Archive:
|
|
|
|
TQString extractionFolder = tempFolder + "extraction/";
|
|
|
|
TQDir dir;
|
|
|
|
dir.mkdir(extractionFolder);
|
|
|
|
KTar tar(tempArchive, "application/x-gzip");
|
|
|
|
tar.open(IO_ReadOnly);
|
|
|
|
tar.directory()->copyTo(extractionFolder);
|
|
|
|
tar.close();
|
|
|
|
|
|
|
|
// Import the Tags:
|
|
|
|
importTagEmblems(extractionFolder); // Import and rename tag emblems BEFORE loading them!
|
|
|
|
TQMap<TQString, TQString> mergedStates = Tag::loadTags(extractionFolder + "tags.xml");
|
|
|
|
TQMap<TQString, TQString>::Iterator it;
|
|
|
|
if (mergedStates.count() > 0) {
|
|
|
|
Tag::saveTags();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Import the Background Images:
|
|
|
|
importArchivedBackgroundImages(extractionFolder);
|
|
|
|
|
|
|
|
// Import the Baskets:
|
|
|
|
renameBasketFolders(extractionFolder, mergedStates);
|
|
|
|
|
|
|
|
}
|
|
|
|
} else if (key.endsWith("*")) {
|
|
|
|
// We do not know what it is, but we should read the embedded-file in order to discard it:
|
|
|
|
bool ok;
|
|
|
|
ulong size = value.toULong(&ok);
|
|
|
|
if (!ok) {
|
|
|
|
KMessageBox::error(0, i18n("This file is corrupted. It can not be opened."), i18n("Basket Archive Error"));
|
|
|
|
file.close();
|
|
|
|
Tools::deleteRecursively(tempFolder);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Get the archive file:
|
|
|
|
char *buffer = new char[BUFFER_SIZE];
|
|
|
|
TQ_LONG sizeRead;
|
|
|
|
while ((sizeRead = file.readBlock(buffer, TQMIN(BUFFER_SIZE, size))) > 0) {
|
|
|
|
size -= sizeRead;
|
|
|
|
}
|
|
|
|
delete buffer;
|
|
|
|
} else {
|
|
|
|
// We do not know what it is, and we do not care.
|
|
|
|
}
|
|
|
|
// Analyse the Value, if Understood:
|
|
|
|
}
|
|
|
|
file.close();
|
|
|
|
}
|
|
|
|
Tools::deleteRecursively(tempFolder);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When opening a basket archive that come from another computer,
|
|
|
|
* it can contains tags that use icons (emblems) that are not present on that computer.
|
|
|
|
* Fortunately, basket archives contains a copy of every used icons.
|
|
|
|
* This method check for every emblems and import the missing ones.
|
|
|
|
* It also modify the tags.xml copy for the emblems to point to the absolute path of the impported icons.
|
|
|
|
*/
|
|
|
|
void Archive::importTagEmblems(const TQString &extractionFolder)
|
|
|
|
{
|
|
|
|
TQDomDocument *document = XMLWork::openFile("basketTags", extractionFolder + "tags.xml");
|
|
|
|
if (document == 0)
|
|
|
|
return;
|
|
|
|
TQDomElement docElem = document->documentElement();
|
|
|
|
|
|
|
|
TQDir dir;
|
|
|
|
dir.mkdir(Global::savesFolder() + "tag-emblems/");
|
|
|
|
FormatImporter copier; // Only used to copy files synchronously
|
|
|
|
|
|
|
|
TQDomNode node = docElem.firstChild();
|
|
|
|
while (!node.isNull()) {
|
|
|
|
TQDomElement element = node.toElement();
|
|
|
|
if ( (!element.isNull()) && element.tagName() == "tag" ) {
|
|
|
|
TQDomNode subNode = element.firstChild();
|
|
|
|
while (!subNode.isNull()) {
|
|
|
|
TQDomElement subElement = subNode.toElement();
|
|
|
|
if ( (!subElement.isNull()) && subElement.tagName() == "state" ) {
|
|
|
|
TQString emblemName = XMLWork::getElementText(subElement, "emblem");
|
|
|
|
if (!emblemName.isEmpty()) {
|
|
|
|
TQPixmap emblem = kapp->iconLoader()->loadIcon(emblemName, KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
|
|
|
|
// The icon does not exists on that computer, import it:
|
|
|
|
if (emblem.isNull()) {
|
|
|
|
// Of the emblem path was eg. "/home/seb/emblem.png", it was exported as "tag-emblems/_home_seb_emblem.png".
|
|
|
|
// So we need to copy that image to "~/.kde/share/apps/basket/tag-emblems/emblem.png":
|
|
|
|
int slashIndex = emblemName.findRev("/");
|
|
|
|
TQString emblemFileName = (slashIndex < 0 ? emblemName : emblemName.right(slashIndex - 2));
|
|
|
|
TQString source = extractionFolder + "tag-emblems/" + emblemName.replace('/', '_');
|
|
|
|
TQString destination = Global::savesFolder() + "tag-emblems/" + emblemFileName;
|
|
|
|
if (!dir.exists(destination))
|
|
|
|
copier.copyFolder(source, destination);
|
|
|
|
// Replace the emblem path in the tags.xml copy:
|
|
|
|
TQDomElement emblemElement = XMLWork::getElement(subElement, "emblem");
|
|
|
|
subElement.removeChild(emblemElement);
|
|
|
|
XMLWork::addElement(*document, subElement, "emblem", destination);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
subNode = subNode.nextSibling();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
node = node.nextSibling();
|
|
|
|
}
|
|
|
|
Basket::safelySaveToFile(extractionFolder + "tags.xml", document->toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::importArchivedBackgroundImages(const TQString &extractionFolder)
|
|
|
|
{
|
|
|
|
FormatImporter copier; // Only used to copy files synchronously
|
|
|
|
TQString destFolder = KGlobal::dirs()->saveLocation("data", "basket/backgrounds/");
|
|
|
|
|
|
|
|
TQDir dir(extractionFolder + "backgrounds/", /*nameFilder=*/"*.png", /*sortSpec=*/TQDir::Name | TQDir::IgnoreCase, /*filterSpec=*/TQDir::Files | TQDir::NoSymLinks);
|
|
|
|
TQStringList files = dir.entryList();
|
|
|
|
for (TQStringList::Iterator it = files.begin(); it != files.end(); ++it) {
|
|
|
|
TQString image = *it;
|
|
|
|
if (!Global::backgroundManager->exists(image)) {
|
|
|
|
// Copy images:
|
|
|
|
TQString imageSource = extractionFolder + "backgrounds/" + image;
|
|
|
|
TQString imageDest = destFolder + image;
|
|
|
|
copier.copyFolder(imageSource, imageDest);
|
|
|
|
// Copy configuration file:
|
|
|
|
TQString configSource = extractionFolder + "backgrounds/" + image + ".config";
|
|
|
|
TQString configDest = destFolder + image;
|
|
|
|
if (dir.exists(configSource))
|
|
|
|
copier.copyFolder(configSource, configDest);
|
|
|
|
// Copy preview:
|
|
|
|
TQString previewSource = extractionFolder + "backgrounds/previews/" + image;
|
|
|
|
TQString previewDest = destFolder + "previews/" + image;
|
|
|
|
if (dir.exists(previewSource)) {
|
|
|
|
dir.mkdir(destFolder + "previews/"); // Make sure the folder exists!
|
|
|
|
copier.copyFolder(previewSource, previewDest);
|
|
|
|
}
|
|
|
|
// Append image to database:
|
|
|
|
Global::backgroundManager->addImage(imageDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::renameBasketFolders(const TQString &extractionFolder, TQMap<TQString, TQString> &mergedStates)
|
|
|
|
{
|
|
|
|
TQDomDocument *doc = XMLWork::openFile("basketTree", extractionFolder + "baskets/baskets.xml");
|
|
|
|
if (doc != 0) {
|
|
|
|
TQMap<TQString, TQString> folderMap;
|
|
|
|
TQDomElement docElem = doc->documentElement();
|
|
|
|
TQDomNode node = docElem.firstChild();
|
|
|
|
renameBasketFolder(extractionFolder, node, folderMap, mergedStates);
|
|
|
|
loadExtractedBaskets(extractionFolder, node, folderMap, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::renameBasketFolder(const TQString &extractionFolder, TQDomNode &basketNode, TQMap<TQString, TQString> &folderMap, TQMap<TQString, TQString> &mergedStates)
|
|
|
|
{
|
|
|
|
TQDomNode n = basketNode;
|
|
|
|
while ( ! n.isNull() ) {
|
|
|
|
TQDomElement element = n.toElement();
|
|
|
|
if ( (!element.isNull()) && element.tagName() == "basket" ) {
|
|
|
|
TQString folderName = element.attribute("folderName");
|
|
|
|
if (!folderName.isEmpty()) {
|
|
|
|
// Find a folder name:
|
|
|
|
TQString newFolderName = BasketFactory::newFolderName();
|
|
|
|
folderMap[folderName] = newFolderName;
|
|
|
|
// Reserve the folder name:
|
|
|
|
TQDir dir;
|
|
|
|
dir.mkdir(Global::basketsFolder() + newFolderName);
|
|
|
|
// Rename the merged tag ids:
|
|
|
|
// if (mergedStates.count() > 0) {
|
|
|
|
renameMergedStatesAndBasketIcon(extractionFolder + "baskets/" + folderName + ".basket", mergedStates, extractionFolder);
|
|
|
|
// }
|
|
|
|
// Child baskets:
|
|
|
|
TQDomNode node = element.firstChild();
|
|
|
|
renameBasketFolder(extractionFolder, node, folderMap, mergedStates);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n = n.nextSibling();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::renameMergedStatesAndBasketIcon(const TQString &fullPath, TQMap<TQString, TQString> &mergedStates, const TQString &extractionFolder)
|
|
|
|
{
|
|
|
|
TQDomDocument *doc = XMLWork::openFile("basket", fullPath);
|
|
|
|
if (doc == 0)
|
|
|
|
return;
|
|
|
|
TQDomElement docElem = doc->documentElement();
|
|
|
|
TQDomElement properties = XMLWork::getElement(docElem, "properties");
|
|
|
|
importBasketIcon(properties, extractionFolder);
|
|
|
|
TQDomElement notes = XMLWork::getElement(docElem, "notes");
|
|
|
|
if (mergedStates.count() > 0)
|
|
|
|
renameMergedStates(notes, mergedStates);
|
|
|
|
Basket::safelySaveToFile(fullPath, /*"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + */doc->toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::importBasketIcon(TQDomElement properties, const TQString &extractionFolder)
|
|
|
|
{
|
|
|
|
TQString iconName = XMLWork::getElementText(properties, "icon");
|
|
|
|
if (!iconName.isEmpty() && iconName != "basket") {
|
|
|
|
TQPixmap icon = kapp->iconLoader()->loadIcon(iconName, KIcon::NoGroup, 16, KIcon::DefaultState, 0L, /*canReturnNull=*/true);
|
|
|
|
// The icon does not exists on that computer, import it:
|
|
|
|
if (icon.isNull()) {
|
|
|
|
TQDir dir;
|
|
|
|
dir.mkdir(Global::savesFolder() + "basket-icons/");
|
|
|
|
FormatImporter copier; // Only used to copy files synchronously
|
|
|
|
// Of the icon path was eg. "/home/seb/icon.png", it was exported as "basket-icons/_home_seb_icon.png".
|
|
|
|
// So we need to copy that image to "~/.kde/share/apps/basket/basket-icons/icon.png":
|
|
|
|
int slashIndex = iconName.findRev("/");
|
|
|
|
TQString iconFileName = (slashIndex < 0 ? iconName : iconName.right(slashIndex - 2));
|
|
|
|
TQString source = extractionFolder + "basket-icons/" + iconName.replace('/', '_');
|
|
|
|
TQString destination = Global::savesFolder() + "basket-icons/" + iconFileName;
|
|
|
|
if (!dir.exists(destination))
|
|
|
|
copier.copyFolder(source, destination);
|
|
|
|
// Replace the emblem path in the tags.xml copy:
|
|
|
|
TQDomElement iconElement = XMLWork::getElement(properties, "icon");
|
|
|
|
properties.removeChild(iconElement);
|
|
|
|
TQDomDocument document = properties.ownerDocument();
|
|
|
|
XMLWork::addElement(document, properties, "icon", destination);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::renameMergedStates(TQDomNode notes, TQMap<TQString, TQString> &mergedStates)
|
|
|
|
{
|
|
|
|
TQDomNode n = notes.firstChild();
|
|
|
|
while ( ! n.isNull() ) {
|
|
|
|
TQDomElement element = n.toElement();
|
|
|
|
if (!element.isNull()) {
|
|
|
|
if (element.tagName() == "group" ) {
|
|
|
|
renameMergedStates(n, mergedStates);
|
|
|
|
} else if (element.tagName() == "note") {
|
|
|
|
TQString tags = XMLWork::getElementText(element, "tags");
|
|
|
|
if (!tags.isEmpty()) {
|
|
|
|
TQStringList tagNames = TQStringList::split(";", tags);
|
|
|
|
for (TQStringList::Iterator it = tagNames.begin(); it != tagNames.end(); ++it) {
|
|
|
|
TQString &tag = *it;
|
|
|
|
if (mergedStates.contains(tag)) {
|
|
|
|
tag = mergedStates[tag];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TQString newTags = tagNames.join(";");
|
|
|
|
TQDomElement tagsElement = XMLWork::getElement(element, "tags");
|
|
|
|
element.removeChild(tagsElement);
|
|
|
|
TQDomDocument document = element.ownerDocument();
|
|
|
|
XMLWork::addElement(document, element, "tags", newTags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n = n.nextSibling();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Archive::loadExtractedBaskets(const TQString &extractionFolder, TQDomNode &basketNode, TQMap<TQString, TQString> &folderMap, Basket *parent)
|
|
|
|
{
|
|
|
|
bool basketSetAsCurrent = (parent != 0);
|
|
|
|
TQDomNode n = basketNode;
|
|
|
|
while ( ! n.isNull() ) {
|
|
|
|
TQDomElement element = n.toElement();
|
|
|
|
if ( (!element.isNull()) && element.tagName() == "basket" ) {
|
|
|
|
TQString folderName = element.attribute("folderName");
|
|
|
|
if (!folderName.isEmpty()) {
|
|
|
|
// Move the basket folder to its destination, while renaming it uniquely:
|
|
|
|
TQString newFolderName = folderMap[folderName];
|
|
|
|
FormatImporter copier;
|
|
|
|
// The folder has been "reserved" by creating it. Avoid asking the user to override:
|
|
|
|
TQDir dir;
|
|
|
|
dir.rmdir(Global::basketsFolder() + newFolderName);
|
|
|
|
copier.moveFolder(extractionFolder + "baskets/" + folderName, Global::basketsFolder() + newFolderName);
|
|
|
|
// Append and load the basket in the tree:
|
|
|
|
Basket *basket = Global::bnpView->loadBasket(newFolderName);
|
|
|
|
BasketListViewItem *basketItem = Global::bnpView->appendBasket(basket, (basket && parent ? Global::bnpView->listViewItemForBasket(parent) : 0));
|
|
|
|
basketItem->setOpen(!XMLWork::trueOrFalse(element.attribute("folded", "false"), false));
|
|
|
|
TQDomElement properties = XMLWork::getElement(element, "properties");
|
|
|
|
importBasketIcon(properties, extractionFolder); // Rename the icon fileName if necessary
|
|
|
|
basket->loadProperties(properties);
|
|
|
|
// Open the first basket of the archive:
|
|
|
|
if (!basketSetAsCurrent) {
|
|
|
|
Global::bnpView->setCurrentBasket(basket);
|
|
|
|
basketSetAsCurrent = true;
|
|
|
|
}
|
|
|
|
TQDomNode node = element.firstChild();
|
|
|
|
loadExtractedBaskets(extractionFolder, node, folderMap, basket);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n = n.nextSibling();
|
|
|
|
}
|
|
|
|
}
|