From 3533a9ec641dee8ad9cc1ad2f9cb5c4a51e96af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20=C3=81ngel=20San=20Mart=C3=ADn?= Date: Thu, 24 May 2012 17:10:28 +0200 Subject: [PATCH] a?adido el codigo del tree model modificada la funci?n de creaci?n de la base de datos (se crea la estructura de directorios, los c?mics y comic_info) falta determinar qu? informaci?n habr? finalmente en la BD y tratar adecuadamente los errores adem?s habr?a que mover el c?digo relacionado con la base de datos a la clase DataBaseManagement. --- YACReaderLibrary/YACReaderLibrary.pro | 15 +- YACReaderLibrary/data_base_management.cpp | 22 - YACReaderLibrary/db/data_base_management.cpp | 52 ++ .../{ => db}/data_base_management.h | 8 +- YACReaderLibrary/db/treeitem.cpp | 118 +++ YACReaderLibrary/db/treeitem.h | 72 ++ YACReaderLibrary/db/treemodel.cpp | 192 +++++ YACReaderLibrary/db/treemodel.h | 77 ++ YACReaderLibrary/library_creator.cpp | 798 +++++++++++------- YACReaderLibrary/library_creator.h | 11 + 10 files changed, 1013 insertions(+), 352 deletions(-) delete mode 100644 YACReaderLibrary/data_base_management.cpp create mode 100644 YACReaderLibrary/db/data_base_management.cpp rename YACReaderLibrary/{ => db}/data_base_management.h (53%) create mode 100644 YACReaderLibrary/db/treeitem.cpp create mode 100644 YACReaderLibrary/db/treeitem.h create mode 100644 YACReaderLibrary/db/treemodel.cpp create mode 100644 YACReaderLibrary/db/treemodel.h diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro index ea3aa965..4b273a5f 100644 --- a/YACReaderLibrary/YACReaderLibrary.pro +++ b/YACReaderLibrary/YACReaderLibrary.pro @@ -7,7 +7,8 @@ TARGET = DEPENDPATH += . INCLUDEPATH += . INCLUDEPATH += ../common \ - ./server + ./server \ + ./db CONFIG += release CONFIG -= flat QT += sql network @@ -27,8 +28,10 @@ HEADERS += comic_flow.h \ import_library_dialog.h \ package_manager.h \ ../common/qnaturalsorting.h \ - data_base_management.h \ - bundle_creator.h + bundle_creator.h \ + ./db/data_base_management.h \ + ./db/treeitem.h \ + ./db/treemodel.h SOURCES += comic_flow.cpp \ create_library_dialog.cpp \ library_creator.cpp \ @@ -44,8 +47,10 @@ SOURCES += comic_flow.cpp \ import_library_dialog.cpp \ package_manager.cpp \ ../common/qnaturalsorting.cpp \ - data_base_management.cpp \ - bundle_creator.cpp + bundle_creator.cpp \ + ./db/data_base_management.cpp \ + ./db/treeitem.cpp \ + ./db/treemodel.cpp include(./server/server.pri) diff --git a/YACReaderLibrary/data_base_management.cpp b/YACReaderLibrary/data_base_management.cpp deleted file mode 100644 index 83632489..00000000 --- a/YACReaderLibrary/data_base_management.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "data_base_management.h" - -#include - -DataBaseManagement::DataBaseManagement() - :QObject(),dataBasesList() -{ - -} - -bool DataBaseManagement::createDataBase(QString name, QString path) -{ - QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); - db.setDatabaseName(QDir::cleanPath(path) + "/" + name + ".ydb"); - if (!db.open()) - qDebug() << db.lastError(); - else { - qDebug() << db.tables(); - db.close(); - } - return true; -} \ No newline at end of file diff --git a/YACReaderLibrary/db/data_base_management.cpp b/YACReaderLibrary/db/data_base_management.cpp new file mode 100644 index 00000000..df3df766 --- /dev/null +++ b/YACReaderLibrary/db/data_base_management.cpp @@ -0,0 +1,52 @@ +#include "data_base_management.h" + +#include + +DataBaseManagement::DataBaseManagement() + :QObject(),dataBasesList() +{ + +} + +TreeModel * DataBaseManagement::newTreeModel(QString path) +{ + //la consulta se ejecuta... + QSqlQuery selectQuery(loadDatabase(path)); + selectQuery.setForwardOnly(true); + selectQuery.exec("select * from folder order by parentId,name"); + return new TreeModel(selectQuery); +} + +QSqlDatabase DataBaseManagement::createDatabase(QString name, QString path) +{ + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName(QDir::cleanPath(path) + "/" + name + ".ydb"); + if (!db.open()) + qDebug() << db.lastError(); + else { + qDebug() << db.tables(); + db.close(); + } + return db; +} + +QSqlDatabase DataBaseManagement::loadDatabase(QString path) +{ + //TODO check path + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); + db.setDatabaseName(path); + if (!db.open()) { + /*QMessageBox::critical( 0, QObject::tr("Cannot open database"), + QObject::tr("Unable to establish a database connection.\n" + "This example needs SQLite support. Please read " + "the Qt SQL driver documentation for information how " + "to build it.\n\n" + "Click Cancel to exit."), QMessageBox::Cancel);*/ + + //se devuelve una base de datos vacía e inválida + return QSqlDatabase(); + } + + //devuelve la base de datos + return db; +} \ No newline at end of file diff --git a/YACReaderLibrary/data_base_management.h b/YACReaderLibrary/db/data_base_management.h similarity index 53% rename from YACReaderLibrary/data_base_management.h rename to YACReaderLibrary/db/data_base_management.h index 52410b2b..eb874ab0 100644 --- a/YACReaderLibrary/data_base_management.h +++ b/YACReaderLibrary/db/data_base_management.h @@ -3,6 +3,9 @@ #include #include +#include + +#include "treemodel.h" class DataBaseManagement : public QObject { @@ -11,8 +14,9 @@ private: QList dataBasesList; public: DataBaseManagement(); - bool createDataBase(QString name, QString path); - + TreeModel * newTreeModel(QString path); + QSqlDatabase createDatabase(QString name, QString path); + QSqlDatabase loadDatabase(QString path); }; #endif \ No newline at end of file diff --git a/YACReaderLibrary/db/treeitem.cpp b/YACReaderLibrary/db/treeitem.cpp new file mode 100644 index 00000000..fa741030 --- /dev/null +++ b/YACReaderLibrary/db/treeitem.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + treeitem.cpp + + A container for items of data supplied by the simple tree model. +*/ + +#include + +#include "treeitem.h" + +//! [0] +TreeItem::TreeItem(const QList &data, TreeItem *parent) +{ + parentItem = parent; + itemData = data; +} +//! [0] + +//! [1] +TreeItem::~TreeItem() +{ + qDeleteAll(childItems); +} +//! [1] + +//! [2] +void TreeItem::appendChild(TreeItem *item) +{ + item->parentItem = this; + //TODO insertar odernado + childItems.append(item); +} +//! [2] + +//! [3] +TreeItem *TreeItem::child(int row) +{ + return childItems.value(row); +} +//! [3] + +//! [4] +int TreeItem::childCount() const +{ + return childItems.count(); +} +//! [4] + +//! [5] +int TreeItem::columnCount() const +{ + return itemData.count(); +} +//! [5] + +//! [6] +QVariant TreeItem::data(int column) const +{ + return itemData.value(column); +} +//! [6] + +//! [7] +TreeItem *TreeItem::parent() +{ + return parentItem; +} +//! [7] + +//! [8] +int TreeItem::row() const +{ + if (parentItem) + return parentItem->childItems.indexOf(const_cast(this)); + + return 0; +} +//! [8] diff --git a/YACReaderLibrary/db/treeitem.h b/YACReaderLibrary/db/treeitem.h new file mode 100644 index 00000000..63678932 --- /dev/null +++ b/YACReaderLibrary/db/treeitem.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TREEITEM_H +#define TREEITEM_H + +#include +#include + +//! [0] +class TreeItem +{ +public: + TreeItem(const QList &data, TreeItem *parent = 0); + ~TreeItem(); + + void appendChild(TreeItem *child); + + TreeItem *child(int row); + int childCount() const; + int columnCount() const; + QVariant data(int column) const; + int row() const; + TreeItem *parent(); + TreeItem *parentItem; + unsigned long long int id; +private: + QList childItems; + QList itemData; + + +}; +//! [0] + +#endif diff --git a/YACReaderLibrary/db/treemodel.cpp b/YACReaderLibrary/db/treemodel.cpp new file mode 100644 index 00000000..ae3d73df --- /dev/null +++ b/YACReaderLibrary/db/treemodel.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* + treemodel.cpp + + Provides a simple tree model to show how to create and use hierarchical + models. +*/ + +#include + + +#include "treeitem.h" +#include "treemodel.h" + +//! [0] +TreeModel::TreeModel( QSqlQuery &sqlquery, QObject *parent) + : QAbstractItemModel(parent) +{ + //lo más probable es que el nodo raíz no necesite tener información + QList rootData; + rootData << "root"; //id 0, padre 0, title "root" (el id, y el id del padre van a ir en la clase TreeItem) + rootItem = new TreeItem(rootData); + rootItem->id = 0; + setupModelData(sqlquery, rootItem); +} +//! [0] + +//! [1] +TreeModel::~TreeModel() +{ + delete rootItem; +} +//! [1] + +//! [2] +int TreeModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return static_cast(parent.internalPointer())->columnCount(); + else + return rootItem->columnCount(); +} +//! [2] + +//! [3] +QVariant TreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role != Qt::DisplayRole) + return QVariant(); + + TreeItem *item = static_cast(index.internalPointer()); + + return item->data(index.column()); +} +//! [3] + +//! [4] +Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} +//! [4] + +//! [5] +QVariant TreeModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return rootItem->data(section); + + return QVariant(); +} +//! [5] + +//! [6] +QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) + const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + TreeItem *parentItem; + + if (!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + TreeItem *childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} +//! [6] + +//! [7] +QModelIndex TreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + TreeItem *childItem = static_cast(index.internalPointer()); + TreeItem *parentItem = childItem->parent(); + + if (parentItem == rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} +//! [7] + +//! [8] +int TreeModel::rowCount(const QModelIndex &parent) const +{ + TreeItem *parentItem; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentItem = rootItem; + else + parentItem = static_cast(parent.internalPointer()); + + return parentItem->childCount(); +} +//! [8] + +void TreeModel::setupModelData(QSqlQuery &sqlquery, TreeItem *parent) +{ + //64 bits para la primary key, es decir la misma precisión que soporta sqlit 2^64 + //el diccionario permitirá encontrar cualquier nodo del árbol rápidamente, de forma que añadir un hijo a un padre sea O(1) + QMap items; + + //se añade el nodo 0 + items.insert(parent->id,parent); + + while (sqlquery.next()) { + QList data; + data << sqlquery.value(2).toString(); + TreeItem * item = new TreeItem(data); + item->id = sqlquery.value(0).toLongLong(); + items.value(sqlquery.value(1).toLongLong())->appendChild(item); + //se añade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones + items.insert(item->id,item); + } +} \ No newline at end of file diff --git a/YACReaderLibrary/db/treemodel.h b/YACReaderLibrary/db/treemodel.h new file mode 100644 index 00000000..b3b38dac --- /dev/null +++ b/YACReaderLibrary/db/treemodel.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TREEMODEL_H +#define TREEMODEL_H + +#include +#include +#include +#include + +class TreeItem; + +//! [0] +class TreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + TreeModel( QSqlQuery &sqlquery, QObject *parent = 0); + ~TreeModel(); + + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +private: + void setupModelData( QSqlQuery &sqlquery, TreeItem *parent); + + TreeItem *rootItem; //el árbol +}; +//! [0] + +#endif diff --git a/YACReaderLibrary/library_creator.cpp b/YACReaderLibrary/library_creator.cpp index 97a33a3d..53f4b560 100644 --- a/YACReaderLibrary/library_creator.cpp +++ b/YACReaderLibrary/library_creator.cpp @@ -1,323 +1,475 @@ -#include "library_creator.h" -#include "custom_widgets.h" - -#include -#include - -//QMutex mutex; - - - -/*int numThreads = 0; -QWaitCondition waitCondition; -QMutex mutex; -*/ -LibraryCreator::LibraryCreator() -{ - _nameFilter << "*.cbr" << "*.cbz" << "*.rar" << "*.zip" << "*.tar"; -} - -void LibraryCreator::createLibrary(const QString &source, const QString &target) -{ - _source = source; - _target = target; - if(!QDir(target).exists()) - _mode = CREATOR; - else - _mode = UPDATER; -} - -void LibraryCreator::updateLibrary(const QString &source, const QString &target) -{ - _source = source; - _target = target; - _mode = UPDATER; -} - -void LibraryCreator::run() -{ - stopRunning = false; - if(_mode == CREATOR) - create(QDir(_source)); - else - update(QDir(_source),QDir(_target)); - emit(finished()); -} - -void LibraryCreator::stop() -{ - stopRunning = true; -} - -void LibraryCreator::create(QDir dir) -{ - dir.setNameFilters(_nameFilter); - dir.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot); - QFileInfoList list = dir.entryInfoList(); - for (int i = 0; i < list.size(); ++i) - { - if(stopRunning) - return; - QFileInfo fileInfo = list.at(i); - if(fileInfo.isDir()) - { - create(QDir(fileInfo.absoluteFilePath())); - } - else - { - dir.mkpath(_target+(QDir::cleanPath(fileInfo.absolutePath()).remove(_source))); - emit(coverExtracted(QDir::cleanPath(fileInfo.absoluteFilePath()).remove(_source))); - - ThumbnailCreator tc(QDir::cleanPath(fileInfo.absoluteFilePath()),_target+(QDir::cleanPath(fileInfo.absoluteFilePath()).remove(_source))+".jpg"); - tc.create(); - } - } -} - -void LibraryCreator::update(QDir dirS,QDir dirD) -{ - dirS.setNameFilters(_nameFilter); - dirS.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot); - dirS.setSorting(QDir::Name|QDir::IgnoreCase|QDir::LocaleAware|QDir::DirsFirst); - QFileInfoList listS = dirS.entryInfoList(); - - dirD.setNameFilters(QStringList()<<"*.jpg"); - dirD.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot); - dirD.setSorting(QDir::Name|QDir::IgnoreCase|QDir::LocaleAware|QDir::DirsFirst); - QFileInfoList listD = dirD.entryInfoList(); - - int lenghtS = listS.size(); - int lenghtD = listD.size(); - int maxLenght = qMax(lenghtS,lenghtD); - - bool updated; - int i,j; - for (i=0,j=0; (i < lenghtS)||(j < lenghtD);) - { - if(stopRunning) - return; - updated = false; - if(i>=lenghtS) //finished source files/dirs - { - //delete listD //from j - for(;j=lenghtD) //finished library files/dirs - { - //create listS //from i - for(;i 0) //delete thumbnail - { - dirD.remove(fileInfoD.absoluteFilePath()); - QString tick = fileInfoD.absoluteFilePath(); - dirD.remove(tick.remove(tick.size()-3,3)); - dirD.remove(tick+"r"); - j++; - } - else //same file - { - if(fileInfoS.isFile() && fileInfoD.isFile()) - { - if(fileInfoS.lastModified()>fileInfoD.lastModified()) - { - dirD.mkpath(_target+(QDir::cleanPath(fileInfoS.absolutePath()).remove(_source))); - emit(coverExtracted(QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source))); - ThumbnailCreator tc(QDir::cleanPath(fileInfoS.absoluteFilePath()),_target+(QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source))+".jpg"); - tc.create(); - } - } - i++;j++; - } - } - } - } - } -} -ThumbnailCreator::ThumbnailCreator(QString fileSource, QString target="") -:_fileSource(fileSource),_target(target),_numPages(0) -{ -} - -void ThumbnailCreator::create() -{ - _7z = new QProcess(); - QStringList attributes; - attributes << "l" << "-ssc-" << "-r" << _fileSource << "*.jpg" << "*.jpeg" << "*.png" << "*.gif" << "*.tiff" << "*.tif" << "*.bmp"; - //connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(loadFirstImage(void))); - connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SIGNAL(openingError(QProcess::ProcessError))); - _7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes); - _7z->waitForFinished(60000); - - QRegExp rx("[0-9]{4}-[0-9]{2}-[0-9]{2}[ ]+[0-9]{2}:[0-9]{2}:[0-9]{2}[ ]+.{5}[ ]+([0-9]+)[ ]+([0-9]+)[ ]+(.+)"); - - QString ba = QString::fromUtf8(_7z->readAllStandardOutput()); - QList lines = ba.split('\n'); - QString line; - _currentName = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; //TODO - QString name; - foreach(line,lines) - { - if(rx.indexIn(line)!=-1) - { - name = rx.cap(3).trimmed(); - if(0 > QString::localeAwareCompare(name,_currentName)) - _currentName = name; - _numPages++; - } - } - delete _7z; - attributes.clear(); - _currentName = QDir::fromNativeSeparators(_currentName).split('/').last(); //separator fixed. -#ifdef Q_WS_WIN - attributes << "e" << "-so" << "-r" << _fileSource << QString(_currentName.toLocal8Bit().constData()); //TODO platform dependency?? OEM 437 -#else - attributes << "e" << "-so" << "-r" << _fileSource << _currentName; //TODO platform dependency?? OEM 437 -#endif - _7z = new QProcess(); - connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SIGNAL(openingError(QProcess::ProcessError))); - //connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(writeThumbnail(void))); - _7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes); - _7z->waitForFinished(60000); - - QByteArray image = _7z->readAllStandardOutput(); - QString error = _7z->readAllStandardError(); - QImage p; - if(_target=="") - { - if(!_cover.loadFromData(image)) - _cover.load(":/images/notCover.png"); - } - else - { - if(p.loadFromData(image)) - { - //TODO calculate aspect ratio - QImage scaled; - if(p.width()>p.height()) //landscape?? - scaled = p.scaledToWidth(640,Qt::SmoothTransformation); - else - scaled = p.scaledToWidth(480,Qt::SmoothTransformation); - scaled.save(_target,0,75); - } - else - { - p.load(":/images/notCover.png"); - p.save(_target); - //TODO save a default image. - } - } - delete _7z; -} - -/*void ThumbnailCreator::openingError(QProcess::ProcessError error) -{ - //TODO : move to the gui thread - switch(error) - { - case QProcess::FailedToStart: - QMessageBox::critical(NULL,tr("7z not found"),tr("7z wasn't found in your PATH.")); - break; - case QProcess::Crashed: - QMessageBox::critical(NULL,tr("7z crashed"),tr("7z crashed.")); - break; - case QProcess::ReadError: - QMessageBox::critical(NULL,tr("7z reading"),tr("problem reading from 7z")); - break; - case QProcess::UnknownError: - QMessageBox::critical(NULL,tr("7z problem"),tr("Unknown error 7z")); - break; - default: - //TODO - break; - } -}*/ +#include "library_creator.h" +#include "custom_widgets.h" + +#include +#include +#include +//QMutex mutex; + + + +/*int numThreads = 0; +QWaitCondition waitCondition; +QMutex mutex; +*/ + +class Folder +{ +public: + bool knownParent; + bool knownId; + unsigned long long int id; + unsigned long long int parentId; + QString name; + QString path; + + Folder():knownParent(false), knownId(false){}; + Folder(unsigned long long int sid, unsigned long long int pid,QString fn, QString fp):id(sid), parentId(pid),name(fn),path(fp),knownParent(true), knownId(true){}; + Folder(QString fn, QString fp):name(fn),path(fp),knownParent(false), knownId(false){}; + void setId(unsigned long long int sid){id = sid;knownId = true;}; + void setFather(unsigned long long int pid){parentId = pid;knownParent = true;}; +}; + +class Comic +{ +public: + unsigned long long int comicInfoId; + unsigned long long int parentId; + QString name; + QString path; + QString hash; + + Comic(){}; + Comic(unsigned long long int cparentId, unsigned long long int ccomicInfoId, QString cname, QString cpath, QString chash) + :parentId(cparentId),comicInfoId(ccomicInfoId),name(cname),path(cpath),hash(chash){}; + //Comic(QString fn, QString fp):name(fn),path(fp),knownParent(false), knownId(false){}; +}; + +LibraryCreator::LibraryCreator() +{ + _nameFilter << "*.cbr" << "*.cbz" << "*.rar" << "*.zip" << "*.tar"; +} + +void LibraryCreator::createLibrary(const QString &source, const QString &target) +{ + _source = source; + _target = target; + if(!QDir(target+"/library.ydb").exists()) + _mode = CREATOR; + else + _mode = UPDATER; +} + +void LibraryCreator::updateLibrary(const QString &source, const QString &target) +{ + _source = source; + _target = target; + _mode = UPDATER; +} + +bool LibraryCreator::createTables() +{ + bool success = true; + + //FOLDER (representa una carpeta en disco) + QSqlQuery queryFolder(_database); + queryFolder.prepare("CREATE TABLE folder (id INTEGER PRIMARY KEY, parentId INTEGER NOT NULL, name TEXT NOT NULL, path TEXT NOT NULL, FOREIGN KEY(parentId) REFERENCES folder(id))"); + success = success && queryFolder.exec(); + + //COMIC INFO (representa la información de un cómic, cada cómic tendrá un idéntificador único formado por un hash sha1'de los primeros 512kb' + su tamaño en bytes) + QSqlQuery queryComicInfo(_database); + queryComicInfo.prepare("CREATE TABLE comic_info (id INTEGER PRIMARY KEY, hash TEXT NOT NULL, name TEXT)"); + success = success && queryComicInfo.exec(); + + //COMIC (representa un cómic en disco, contiene el nombre de fichero) + QSqlQuery queryComic(_database); + queryComic.prepare("CREATE TABLE comic (id INTEGER PRIMARY KEY, parentId INTEGER NOT NULL, comicInfoId INTEGER NOT NULL, fileName TEXT NOT NULL, path TEXT, FOREIGN KEY(parentId) REFERENCES folder(id), FOREIGN KEY(comicInfoId) REFERENCES comic_info(id))"); + success = success && queryComic.exec(); + + return success; +} +// +void LibraryCreator::run() +{ + stopRunning = false; + + if(_mode == CREATOR) + { + QDir dir; + dir.mkpath(_target+"/covers"); + _database = QSqlDatabase::addDatabase("QSQLITE"); + _database.setDatabaseName(_target+"/library.ydb"); + if(!_database.open()) + return; //TODO avisar del problema + _currentPathFolders.clear(); + _currentPathFolders.append(Folder(0,0,"root","/")); + if(!createTables()) + return; + create(QDir(_source)); + _database.commit(); + _database.close(); + } + else + { + _currentPathFolders.clear(); + _currentPathFolders.append(Folder(0,0,"root","/")); + _database = QSqlDatabase::addDatabase("QSQLITE"); + _database.setDatabaseName(_target+"/library.ydb"); + if(!_database.open()) + return; //TODO avisar del problema + update(QDir(_source),QDir(_target)); + } + emit(finished()); +} + +void LibraryCreator::stop() +{ + stopRunning = true; +} + +//retorna el id del ultimo de los folders +unsigned long long int LibraryCreator::insertFolders() +{ + QList::iterator i; + int currentId = 0; + for (i = _currentPathFolders.begin(); i != _currentPathFolders.end(); ++i) + { + if(!(i->knownId)) + { + i->setFather(currentId); + currentId = insertFolder(currentId,*i); + i->setId(currentId); + } + else + { + currentId = i->id; + } + } + return 0; +} + +unsigned long long int LibraryCreator::insertFolder(unsigned long long int parentId,const Folder & folder) +{ + QSqlQuery query(_database); + query.prepare("INSERT INTO folder (parentId, name, path) " + "VALUES (:parentId, :name, :path)"); + query.bindValue(":parentId", parentId); + query.bindValue(":name", folder.name); + query.bindValue(":path", folder.path); + query.exec(); + return query.lastInsertId().toLongLong(); +} + +unsigned long long int LibraryCreator::insertComic(const Comic & comic) +{ + //TODO comprobar si ya hay comic info con ese hash + QSqlQuery comicInfoInsert(_database); + comicInfoInsert.prepare("INSERT INTO comic_info (hash) " + "VALUES (:hash)"); + comicInfoInsert.bindValue(":hash", comic.hash); + comicInfoInsert.exec(); + unsigned long long int comicInfoId =comicInfoInsert.lastInsertId().toLongLong(); + + QSqlQuery query(_database); + query.prepare("INSERT INTO comic (parentId, comicInfoId, fileName, path) " + "VALUES (:parentId,:comicInfoId,:name, :path)"); + query.bindValue(":parentId", comic.parentId); + query.bindValue(":comicInfoId", comicInfoId); + query.bindValue(":name", comic.name); + query.bindValue(":path", comic.path); + query.exec(); + return query.lastInsertId().toLongLong(); +} + +void LibraryCreator::create(QDir dir) +{ + dir.setNameFilters(_nameFilter); + dir.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot); + QFileInfoList list = dir.entryInfoList(); + for (int i = 0; i < list.size(); ++i) + { + if(stopRunning) + return; + QFileInfo fileInfo = list.at(i); + QString fileName = fileInfo.fileName(); + QString relativePath = QDir::cleanPath(fileInfo.absoluteFilePath()).remove(_source); + if(fileInfo.isDir()) + { + //se añade al path actual el folder, aún no se sabe si habrá que añadirlo a la base de datos + _currentPathFolders.append(Folder(fileInfo.fileName(),relativePath)); + create(QDir(fileInfo.absoluteFilePath())); + //una vez importada la información del folder, se retira del path actual ya que no volverá a ser visitado + _currentPathFolders.pop_back(); + } + else + { + //dir.mkpath(_target+(QDir::cleanPath(fileInfo.absolutePath()).remove(_source))); + + //en este punto sabemos que todos los folders que hay en _currentPath, deberían estar añadidos a la base de datos + insertFolders(); + emit(coverExtracted(relativePath)); + + //Se calcula el hash del cómic + + QCryptographicHash crypto(QCryptographicHash::Sha1); + QFile file(fileInfo.absoluteFilePath()); + file.open(QFile::ReadOnly); + crypto.addData(file.read(524288)); + //hash Sha1 del primer 0.5MB + filesize + QString hash = QString(crypto.result().toHex().constData()) + QString::number(fileInfo.size()); + insertComic(Comic(_currentPathFolders.last().id,0,fileName,relativePath,hash)); + ThumbnailCreator tc(QDir::cleanPath(fileInfo.absoluteFilePath()),_target+"/covers/"+hash+".jpg"); + //ThumbnailCreator tc(QDir::cleanPath(fileInfo.absoluteFilePath()),_target+"/covers/"+fileInfo.fileName()+".jpg"); + tc.create(); + + } + } +} + +void LibraryCreator::update(QDir dirS,QDir dirD) +{ + dirS.setNameFilters(_nameFilter); + dirS.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot); + dirS.setSorting(QDir::Name|QDir::IgnoreCase|QDir::LocaleAware|QDir::DirsFirst); + QFileInfoList listS = dirS.entryInfoList(); + + dirD.setNameFilters(QStringList()<<"*.jpg"); + dirD.setFilter(QDir::AllDirs|QDir::Files|QDir::NoDotAndDotDot); + dirD.setSorting(QDir::Name|QDir::IgnoreCase|QDir::LocaleAware|QDir::DirsFirst); + QFileInfoList listD = dirD.entryInfoList(); + + int lenghtS = listS.size(); + int lenghtD = listD.size(); + int maxLenght = qMax(lenghtS,lenghtD); + + bool updated; + int i,j; + for (i=0,j=0; (i < lenghtS)||(j < lenghtD);) + { + if(stopRunning) + return; + updated = false; + if(i>=lenghtS) //finished source files/dirs + { + //delete listD //from j + for(;j=lenghtD) //finished library files/dirs + { + //create listS //from i + for(;i 0) //delete thumbnail + { + dirD.remove(fileInfoD.absoluteFilePath()); + QString tick = fileInfoD.absoluteFilePath(); + dirD.remove(tick.remove(tick.size()-3,3)); + dirD.remove(tick+"r"); + j++; + } + else //same file + { + if(fileInfoS.isFile() && fileInfoD.isFile()) + { + if(fileInfoS.lastModified()>fileInfoD.lastModified()) + { + dirD.mkpath(_target+(QDir::cleanPath(fileInfoS.absolutePath()).remove(_source))); + emit(coverExtracted(QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source))); + ThumbnailCreator tc(QDir::cleanPath(fileInfoS.absoluteFilePath()),_target+(QDir::cleanPath(fileInfoS.absoluteFilePath()).remove(_source))+".jpg"); + tc.create(); + } + } + i++;j++; + } + } + } + } + } +} +ThumbnailCreator::ThumbnailCreator(QString fileSource, QString target="") +:_fileSource(fileSource),_target(target),_numPages(0) +{ +} + +void ThumbnailCreator::create() +{ + _7z = new QProcess(); + QStringList attributes; + attributes << "l" << "-ssc-" << "-r" << _fileSource << "*.jpg" << "*.jpeg" << "*.png" << "*.gif" << "*.tiff" << "*.tif" << "*.bmp"; + //connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(loadFirstImage(void))); + connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SIGNAL(openingError(QProcess::ProcessError))); + _7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes); + _7z->waitForFinished(60000); + + QRegExp rx("[0-9]{4}-[0-9]{2}-[0-9]{2}[ ]+[0-9]{2}:[0-9]{2}:[0-9]{2}[ ]+.{5}[ ]+([0-9]+)[ ]+([0-9]+)[ ]+(.+)"); + + QString ba = QString::fromUtf8(_7z->readAllStandardOutput()); + QList lines = ba.split('\n'); + QString line; + _currentName = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; //TODO + QString name; + foreach(line,lines) + { + if(rx.indexIn(line)!=-1) + { + name = rx.cap(3).trimmed(); + if(0 > QString::localeAwareCompare(name,_currentName)) + _currentName = name; + _numPages++; + } + } + delete _7z; + attributes.clear(); + _currentName = QDir::fromNativeSeparators(_currentName).split('/').last(); //separator fixed. +#ifdef Q_WS_WIN + attributes << "e" << "-so" << "-r" << _fileSource << QString(_currentName.toLocal8Bit().constData()); //TODO platform dependency?? OEM 437 +#else + attributes << "e" << "-so" << "-r" << _fileSource << _currentName; //TODO platform dependency?? OEM 437 +#endif + _7z = new QProcess(); + connect(_7z,SIGNAL(error(QProcess::ProcessError)),this,SIGNAL(openingError(QProcess::ProcessError))); + //connect(_7z,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(writeThumbnail(void))); + _7z->start(QCoreApplication::applicationDirPath()+"/utils/7z",attributes); + _7z->waitForFinished(60000); + + QByteArray image = _7z->readAllStandardOutput(); + QString error = _7z->readAllStandardError(); + QImage p; + if(_target=="") + { + if(!_cover.loadFromData(image)) + _cover.load(":/images/notCover.png"); + } + else + { + if(p.loadFromData(image)) + { + //TODO calculate aspect ratio + QImage scaled; + if(p.width()>p.height()) //landscape?? + scaled = p.scaledToWidth(640,Qt::SmoothTransformation); + else + scaled = p.scaledToWidth(480,Qt::SmoothTransformation); + scaled.save(_target,0,75); + } + else + { + p.load(":/images/notCover.png"); + p.save(_target); + //TODO save a default image. + } + } + delete _7z; +} + +/*void ThumbnailCreator::openingError(QProcess::ProcessError error) +{ + //TODO : move to the gui thread + switch(error) + { + case QProcess::FailedToStart: + QMessageBox::critical(NULL,tr("7z not found"),tr("7z wasn't found in your PATH.")); + break; + case QProcess::Crashed: + QMessageBox::critical(NULL,tr("7z crashed"),tr("7z crashed.")); + break; + case QProcess::ReadError: + QMessageBox::critical(NULL,tr("7z reading"),tr("problem reading from 7z")); + break; + case QProcess::UnknownError: + QMessageBox::critical(NULL,tr("7z problem"),tr("Unknown error 7z")); + break; + default: + //TODO + break; + } +}*/ diff --git a/YACReaderLibrary/library_creator.h b/YACReaderLibrary/library_creator.h index 5a970adb..dba47dfc 100644 --- a/YACReaderLibrary/library_creator.h +++ b/YACReaderLibrary/library_creator.h @@ -12,6 +12,10 @@ #include #include #include +#include + +class Folder; +class Comic; class LibraryCreator : public QThread { @@ -23,14 +27,21 @@ void stop(); private: enum Mode {CREATOR,UPDATER}; + //atributos "globales" durante el proceso de creación y actualización enum Mode _mode; QString _source; QString _target; QStringList _nameFilter; + QSqlDatabase _database; + QList _currentPathFolders; //lista de folders en el orden en el que están siendo explorados, el último es el folder actual //recursive method void create(QDir currentDirectory); void update(QDir currentDirectory,QDir libraryCurrentDirectory); void run(); + bool createTables(); + unsigned long long int insertFolders(); + unsigned long long int insertFolder(unsigned long long int parentId,const Folder & folder); + unsigned long long int insertComic(const Comic & comic); bool stopRunning; signals: void finished();