From 1b2f33d0c68ab3eeefebe41ca1235a887feadfe7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luis=20=C3=81ngel=20San=20Mart=C3=ADn?=
 <luisangelsm@gmail.com>
Date: Wed, 9 Jul 2014 17:38:12 +0200
Subject: [PATCH] added new view for empty folders in YACReaderLibrary that
 shows a list with all the subfolders TODO ?use a special case for the root
 folder?

---
 YACReaderLibrary/YACReaderLibrary.pro    |   6 +-
 YACReaderLibrary/db/tablemodel.cpp       |   4 +-
 YACReaderLibrary/db/tablemodel.h         |   1 +
 YACReaderLibrary/db/treemodel.cpp        |  70 ++++++---
 YACReaderLibrary/db/treemodel.h          |   2 +
 YACReaderLibrary/db_helper.cpp           |  15 +-
 YACReaderLibrary/db_helper.h             |   1 +
 YACReaderLibrary/empty_folder_widget.cpp |  89 +++++++++++
 YACReaderLibrary/empty_folder_widget.h   |  32 ++++
 YACReaderLibrary/images_osx.qrc          |   1 +
 YACReaderLibrary/images_win.qrc          |   1 +
 YACReaderLibrary/library_window.cpp      |  40 ++++-
 YACReaderLibrary/library_window.h        | 182 ++++++++++++-----------
 images/empty_folder.png                  | Bin 0 -> 2515 bytes
 14 files changed, 322 insertions(+), 122 deletions(-)
 create mode 100644 YACReaderLibrary/empty_folder_widget.cpp
 create mode 100644 YACReaderLibrary/empty_folder_widget.h
 create mode 100644 images/empty_folder.png

diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro
index 1d19565d..3523e1ec 100644
--- a/YACReaderLibrary/YACReaderLibrary.pro
+++ b/YACReaderLibrary/YACReaderLibrary.pro
@@ -117,7 +117,8 @@ HEADERS += comic_flow.h \
     yacreader_libraries.h \
         ../common/exit_check.h \
     comics_view.h \
-    classic_comics_view.h
+    classic_comics_view.h \
+    empty_folder_widget.h
 
 		   
 SOURCES += comic_flow.cpp \
@@ -163,7 +164,8 @@ SOURCES += comic_flow.cpp \
     yacreader_libraries.cpp \
 	../common/exit_check.cpp \
     comics_view.cpp \
-    classic_comics_view.cpp
+    classic_comics_view.cpp \
+    empty_folder_widget.cpp
 
 			
 		   
diff --git a/YACReaderLibrary/db/tablemodel.cpp b/YACReaderLibrary/db/tablemodel.cpp
index 1d9e51c2..8987176f 100644
--- a/YACReaderLibrary/db/tablemodel.cpp
+++ b/YACReaderLibrary/db/tablemodel.cpp
@@ -304,7 +304,9 @@ void TableModel::setupModelData(unsigned long long int folderId,const QString &
 	db.close();
 	QSqlDatabase::removeDatabase(_databasePath);
 	endResetModel();
-	//f.close();
+
+    if(_data.length()==0)
+        emit isEmpty();
 }
 
 QString TableModel::getComicPath(QModelIndex mi)
diff --git a/YACReaderLibrary/db/tablemodel.h b/YACReaderLibrary/db/tablemodel.h
index 7bfff95b..9df0126a 100644
--- a/YACReaderLibrary/db/tablemodel.h
+++ b/YACReaderLibrary/db/tablemodel.h
@@ -113,6 +113,7 @@ private:
 signals:
 	void beforeReset();
 	void reset();
+    void isEmpty();
 };
 //! [0]
 
diff --git a/YACReaderLibrary/db/treemodel.cpp b/YACReaderLibrary/db/treemodel.cpp
index fcf0ada8..f04b7bef 100644
--- a/YACReaderLibrary/db/treemodel.cpp
+++ b/YACReaderLibrary/db/treemodel.cpp
@@ -53,6 +53,7 @@
 #include "data_base_management.h"
 #include "folder.h"
 #include "db_helper.h"
+#include "qnaturalsorting.h"
 
 #ifdef Q_OS_MAC
 #include <QFileIconProvider>
@@ -106,7 +107,7 @@ TreeModel::TreeModel(QObject *parent)
 TreeModel::TreeModel( QSqlQuery &sqlquery, QObject *parent)
 	: QAbstractItemModel(parent),rootItem(0),rootBeforeFilter(0),filterEnabled(false),includeComics(false)
 {
-	//lo m�s probable es que el nodo ra�z no necesite tener informaci�n
+	//lo m�s probable es que el nodo ra�z no necesite tener informaci�n
 	QList<QVariant> 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);
@@ -265,7 +266,7 @@ void TreeModel::setupModelData(QString path)
 	filterEnabled = false;
 	rootItem = 0;
 	rootBeforeFilter = 0;
-	//inicializar el nodo ra�z
+	//inicializar el nodo ra�z
 	QList<QVariant> 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);
@@ -291,10 +292,10 @@ void TreeModel::setupModelData(QString path)
 
 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)
+	//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)
 	items.clear();
-	//se a�ade el nodo 0
+	//se a�ade el nodo 0
 	items.insert(parent->id,parent);
 
 	while (sqlquery.next()) {
@@ -308,11 +309,11 @@ void TreeModel::setupModelData(QSqlQuery &sqlquery, TreeItem *parent)
 		TreeItem * item = new TreeItem(data);
 
 		item->id = record.value("id").toULongLong();
-		//la inserci�n de hijos se hace de forma ordenada
+		//la inserci�n de hijos se hace de forma ordenada
 		TreeItem * parent = items.value(record.value("parentId").toULongLong());
 		if(parent !=0) //TODO if parent==0 the parent of item was removed from the DB and delete on cascade didn't work, ERROR.
 			parent->appendChild(item);
-		//se a�ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
+		//se a�ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
 		items.insert(item->id,item);
 	}
 }
@@ -323,12 +324,12 @@ void TreeModel::setupFilteredModelData()
 	
 	//TODO hay que liberar memoria de anteriores filtrados
 
-	//inicializar el nodo ra�z
+	//inicializar el nodo ra�z
 
 	if(rootBeforeFilter == 0)
 		rootBeforeFilter = rootItem;
 	else
-		delete rootItem;//los resultados de la b�squeda anterior deben ser borrados
+		delete rootItem;//los resultados de la b�squeda anterior deben ser borrados
 
 	QList<QVariant> rootData;
 	rootData << "root"; //id 1, padre 1, title "root" (el id, y el id del padre van a ir en la clase TreeItem)
@@ -365,10 +366,10 @@ void TreeModel::setupFilteredModelData()
 
 void TreeModel::setupFilteredModelData(QSqlQuery &sqlquery, TreeItem *parent)
 {
-	//64 bits para la primary key, es decir la misma precisi�n que soporta sqlit 2^64
+	//64 bits para la primary key, es decir la misma precisi�n que soporta sqlit 2^64
 	filteredItems.clear();
 
-	//se a�ade el nodo 0 al modelo que representa el arbol de elementos que cumplen con el filtro
+	//se a�ade el nodo 0 al modelo que representa el arbol de elementos que cumplen con el filtro
 	filteredItems.insert(parent->id,parent);
 
 	while (sqlquery.next()) {  //se procesan todos los folders que cumplen con el filtro
@@ -387,39 +388,39 @@ void TreeModel::setupFilteredModelData(QSqlQuery &sqlquery, TreeItem *parent)
 		//id del padre
 		quint64 parentId = record.value("parentId").toULongLong();
 
-		//se a�ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
+		//se a�ade el item al map, de forma que se pueda encontrar como padre en siguientes iteraciones
 		if(!filteredItems.contains(item->id))
 			filteredItems.insert(item->id,item);
 
-		//es necesario conocer las coordenadas de origen para poder realizar scroll autom�tico en la vista
+		//es necesario conocer las coordenadas de origen para poder realizar scroll autom�tico en la vista
 		item->originalItem = items.value(item->id);
 
-		//si el padre ya existe en el modelo, el item se a�ade como hijo
+		//si el padre ya existe en el modelo, el item se a�ade como hijo
 		if(filteredItems.contains(parentId))
 			filteredItems.value(parentId)->appendChild(item);
-		else//si el padre a�n no se ha a�adido, hay que a�adirlo a �l y todos los padres hasta el nodo ra�z
+		else//si el padre a�n no se ha a�adido, hay que a�adirlo a �l y todos los padres hasta el nodo ra�z
 		{
-			//comprobamos con esta variable si el �ltimo de los padres (antes del nodo ra�z) ya exist�a en el modelo
+			//comprobamos con esta variable si el �ltimo de los padres (antes del nodo ra�z) ya exist�a en el modelo
 			bool parentPreviousInserted = false;
 
-			//mientras no se alcance el nodo ra�z se procesan todos los padres (de abajo a arriba)
+			//mientras no se alcance el nodo ra�z se procesan todos los padres (de abajo a arriba)
 			while(parentId != ROOT )
 			{
-				//el padre no estaba en el modelo filtrado, as� que se rescata del modelo original
+				//el padre no estaba en el modelo filtrado, as� que se rescata del modelo original
 				TreeItem * parentItem = items.value(parentId);
 				//se debe crear un nuevo nodo (para no compartir los hijos con el nodo original)
-				TreeItem * newparentItem = new TreeItem(parentItem->getData()); //padre que se a�adir� a la estructura de directorios filtrados
+				TreeItem * newparentItem = new TreeItem(parentItem->getData()); //padre que se a�adir� a la estructura de directorios filtrados
 				newparentItem->id = parentId;
 
 				newparentItem->originalItem = parentItem;
 
-				//si el modelo contiene al padre, se a�ade el item actual como hijo
+				//si el modelo contiene al padre, se a�ade el item actual como hijo
 				if(filteredItems.contains(parentId))
 				{
 					filteredItems.value(parentId)->appendChild(item);
 					parentPreviousInserted = true;
 				}
-				//sino se registra el nodo para poder encontrarlo con posterioridad y se a�ade el item actual como hijo
+				//sino se registra el nodo para poder encontrarlo con posterioridad y se a�ade el item actual como hijo
 				else
 				{
 					newparentItem->appendChild(item);
@@ -432,7 +433,7 @@ void TreeModel::setupFilteredModelData(QSqlQuery &sqlquery, TreeItem *parent)
 				parentId = parentItem->parentItem->id;
 			}
 
-			//si el nodo es hijo de 1 y no hab�a sido previamente insertado como hijo, se a�ade como tal
+			//si el nodo es hijo de 1 y no hab�a sido previamente insertado como hijo, se a�ade como tal
 			if(!parentPreviousInserted)
 				filteredItems.value(ROOT)->appendChild(item);
 		}
@@ -468,7 +469,7 @@ void TreeModel::resetFilter()
 	//items.clear();
 	filteredItems.clear();
 	TreeItem * root = rootItem;
-	rootItem = rootBeforeFilter; //TODO si no se aplica el filtro previamente, esto invalidar�a en modelo
+	rootItem = rootBeforeFilter; //TODO si no se aplica el filtro previamente, esto invalidar�a en modelo
 	if(root !=0)
 		delete root;
 
@@ -518,3 +519,26 @@ void TreeModel::updateFolderFinishedStatus(const QModelIndexList &list, bool sta
 
     emit dataChanged(index(list.first().row(),TreeModel::Name),index(list.last().row(),TreeModel::Completed));
 }
+
+QStringList TreeModel::getSubfoldersNames(const QModelIndex &mi)
+{
+    QStringList result;
+    qulonglong id = 1;
+    if(mi.isValid()){
+        TreeItem * item = static_cast<TreeItem*>(mi.internalPointer());
+        id = item->id;
+    }
+
+    QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath);
+    db.transaction();
+
+    result = DBHelper::loadSubfoldersNames(id,db);
+
+    db.commit();
+    db.close();
+    QSqlDatabase::removeDatabase(_databasePath);
+
+    //TODO sort result))
+    qSort(result.begin(),result.end(),naturalSortLessThanCI);
+    return result;
+}
diff --git a/YACReaderLibrary/db/treemodel.h b/YACReaderLibrary/db/treemodel.h
index 02168cbb..d36dab40 100644
--- a/YACReaderLibrary/db/treemodel.h
+++ b/YACReaderLibrary/db/treemodel.h
@@ -85,6 +85,8 @@ public:
     void updateFolderCompletedStatus(const QModelIndexList & list, bool status);
     void updateFolderFinishedStatus(const QModelIndexList & list, bool status);
 
+    QStringList getSubfoldersNames(const QModelIndex & mi);
+
     enum Columns {
         Name = 0,
         Path = 1,
diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp
index 417d8d4d..39b18751 100644
--- a/YACReaderLibrary/db_helper.cpp
+++ b/YACReaderLibrary/db_helper.cpp
@@ -671,5 +671,18 @@ ComicInfo DBHelper::loadComicInfo(QString hash, QSqlDatabase & db)
 	else
 		comicInfo.existOnDb = false;
 
-	return comicInfo;
+    return comicInfo;
+}
+
+QList<QString> DBHelper::loadSubfoldersNames(qulonglong folderId, QSqlDatabase &db)
+{
+    QList<QString> result;
+    QSqlQuery selectQuery(db);
+    selectQuery.prepare("SELECT name FROM folder WHERE parentId = :parentId AND id <> 1"); //do not select the root folder
+    selectQuery.bindValue(":parentId", folderId);
+    selectQuery.exec();
+    while(selectQuery.next()){
+        result << selectQuery.record().value("name").toString();
+    }
+    return result;
 }
diff --git a/YACReaderLibrary/db_helper.h b/YACReaderLibrary/db_helper.h
index b4f88f89..014e65c9 100644
--- a/YACReaderLibrary/db_helper.h
+++ b/YACReaderLibrary/db_helper.h
@@ -51,6 +51,7 @@ public:
 	static ComicDB loadComic(qulonglong id, QSqlDatabase & db);
     static ComicDB loadComic(QString cname, QString cpath, QString chash, QSqlDatabase & database);
 	static ComicInfo loadComicInfo(QString hash, QSqlDatabase & db);
+    static QList<QString> loadSubfoldersNames(qulonglong folderId, QSqlDatabase & db);
 };
 
 #endif
diff --git a/YACReaderLibrary/empty_folder_widget.cpp b/YACReaderLibrary/empty_folder_widget.cpp
new file mode 100644
index 00000000..6d440f51
--- /dev/null
+++ b/YACReaderLibrary/empty_folder_widget.cpp
@@ -0,0 +1,89 @@
+#include "empty_folder_widget.h"
+
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QListView>
+#include <QPainter>
+
+
+#include <QStringListModel>
+void testListView(QListView * l)
+{
+    QStringListModel * slm = new QStringListModel(QStringList() = {"Lorem ipsum", "Hailer skualer", "Mumbaluba X", "Finger layden", "Pacum tactus filer", "Aposum", "En","Lorem ipsum", "Hailer skualer", "Mumbaluba X", "Finger layden", "Pacum tactus filer", "Aposum", "En" });
+    l->setModel(slm);
+}
+
+EmptyFolderWidget::EmptyFolderWidget(QWidget *parent) :
+    QWidget(parent),subfoldersModel(new QStringListModel())
+{
+    QVBoxLayout * layout = new QVBoxLayout;
+
+    iconLabel = new QLabel();
+    iconLabel->setPixmap(QPixmap(":/images/empty_folder.png"));
+    iconLabel->setAlignment(Qt::AlignCenter);
+
+    titleLabel = new QLabel("Subfolders in this folder");
+    titleLabel->setAlignment(Qt::AlignCenter);
+    titleLabel->setStyleSheet("QLabel {color:#CCCCCC; font-size:24px;font-family:Arial;font-weight:bold;}");
+
+    foldersView = new QListView();
+    foldersView->setMinimumWidth(282);
+    foldersView->setWrapping(true);
+
+    foldersView->setStyleSheet("QListView {background-color:transparent; border: none; color:#858585; outline:0; font-size: 18px; font:bold; show-decoration-selected: 0; margin:0}"
+                               "QListView::item:selected {background-color: #212121; color:#CCCCCC;}"
+                               "QListView::item:hover {background-color:#212121; color:#CCCCCC; }"
+
+
+                               "QScrollBar:vertical { border: none; background: #212121; width: 14px; margin: 0 10px 0 0; }"
+                               "QScrollBar::handle:vertical { background: #858585; width: 14px; min-height: 20px; }"
+                               "QScrollBar::add-line:vertical { border: none; background: #212121; height: 0px; subcontrol-position: bottom; subcontrol-origin: margin; margin: 0 3px 0 0;}"
+
+                               "QScrollBar::sub-line:vertical {  border: none; background: #212121; height: 0px; subcontrol-position: top; subcontrol-origin: margin; margin: 0 3px 0 0;}"
+                               "QScrollBar::up-arrow:vertical {border:none;width: 9px;height: 6px;background: url(':/images/folders_view/line-up.png') center top no-repeat;}"
+                               "QScrollBar::down-arrow:vertical {border:none;width: 9px;height: 6px;background: url(':/images/folders_view/line-down.png') center top no-repeat;}"
+
+                               "QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {background: none; }"
+                               "QScrollBar:horizontal{height:0px;}"
+                               );
+
+    foldersView->setSizePolicy(QSizePolicy ::Expanding , QSizePolicy ::Expanding );
+    testListView(foldersView);
+
+    layout->addSpacing(100);
+    layout->addWidget(iconLabel);
+    layout->addSpacing(30);
+    layout->addWidget(titleLabel);
+    layout->addSpacing(12);
+    layout->addWidget(foldersView,1,Qt::AlignHCenter);
+    layout->addStretch();
+    layout->setMargin(0);
+    layout->setSpacing(0);
+
+    setContentsMargins(0,0,0,0);
+
+    setStyleSheet("QWidget {background:#2A2A2A}");
+
+    setSizePolicy(QSizePolicy ::Expanding , QSizePolicy ::Expanding );
+    setLayout(layout);
+
+    connect(foldersView,SIGNAL(clicked(QModelIndex)),this,SLOT(onItemClicked(QModelIndex)));
+}
+
+void EmptyFolderWidget::setSubfolders(const QModelIndex &mi, const QStringList &foldersNames)
+{
+    parent = mi;
+    subfoldersModel->setStringList(foldersNames);
+    foldersView->setModel(subfoldersModel);
+}
+
+void EmptyFolderWidget::onItemClicked(const QModelIndex &mi)
+{
+    emit subfolderSelected(parent,mi.row());
+}
+
+void EmptyFolderWidget::paintEvent(QPaintEvent *)
+{
+    QPainter painter (this);
+    painter.fillRect(0,0,width(),height(),QColor("#2A2A2A"));
+}
diff --git a/YACReaderLibrary/empty_folder_widget.h b/YACReaderLibrary/empty_folder_widget.h
new file mode 100644
index 00000000..225948be
--- /dev/null
+++ b/YACReaderLibrary/empty_folder_widget.h
@@ -0,0 +1,32 @@
+#ifndef EMPTY_FOLDER_WIDGET_H
+#define EMPTY_FOLDER_WIDGET_H
+
+#include <QWidget>
+#include <QModelIndex>
+
+class QLabel;
+class QListView;
+class QStringListModel;
+
+class EmptyFolderWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    explicit EmptyFolderWidget(QWidget *parent = 0);
+    void setSubfolders(const QModelIndex & mi, const QStringList & foldersNames);
+signals:
+    void subfolderSelected(QModelIndex, int);
+
+public slots:
+    void onItemClicked(const QModelIndex & mi);
+
+protected:
+    QLabel * iconLabel;
+    QLabel * titleLabel;
+    QListView * foldersView;
+    QModelIndex parent;
+    QStringListModel * subfoldersModel;
+    void paintEvent(QPaintEvent *);
+};
+
+#endif // EMPTY_FOLDER_WIDGET_H
diff --git a/YACReaderLibrary/images_osx.qrc b/YACReaderLibrary/images_osx.qrc
index d5604ff7..64c41b0c 100644
--- a/YACReaderLibrary/images_osx.qrc
+++ b/YACReaderLibrary/images_osx.qrc
@@ -19,5 +19,6 @@
     <file alias="images/openLibraryIcon.png">../images/openLibraryIcon_osx.png</file>
     <file alias="images/flow_to_grid.gif">../images/flow_to_grid.gif</file>
     <file alias="images/grid_to_flow.gif">../images/grid_to_flow.gif</file>
+    <file alias="images/empty_folder.png">../images/empty_folder.png</file>
   </qresource>
 </RCC>
diff --git a/YACReaderLibrary/images_win.qrc b/YACReaderLibrary/images_win.qrc
index 5d2bd0af..ffa97d93 100644
--- a/YACReaderLibrary/images_win.qrc
+++ b/YACReaderLibrary/images_win.qrc
@@ -18,5 +18,6 @@
         <file>../images/main_toolbar/grid.png</file>
         <file>../images/flow_to_grid.gif</file>
         <file>../images/grid_to_flow.gif</file>
+        <file>../images/empty_folder.png</file>
     </qresource>
 </RCC>
diff --git a/YACReaderLibrary/library_window.cpp b/YACReaderLibrary/library_window.cpp
index 003bf740..6697f997 100644
--- a/YACReaderLibrary/library_window.cpp
+++ b/YACReaderLibrary/library_window.cpp
@@ -63,6 +63,7 @@
 #include "classic_comics_view.h"
 #include "grid_comics_view.h"
 #include "comics_view_transition.h"
+#include "empty_folder_widget.h"
 
 #include "QsLog.h"
 
@@ -205,8 +206,11 @@ void LibraryWindow::doLayout()
     doComicsViewConnections();
 
     comicsView->setToolBar(editInfoToolBar);
-    comicsViewStack->addWidget(comicsView);
     comicsViewStack->addWidget(comicsViewTransition = new ComicsViewTransition());
+    comicsViewStack->addWidget(emptyFolderWidget = new EmptyFolderWidget());
+    comicsViewStack->addWidget(comicsView);
+
+    comicsViewStack->setCurrentWidget(comicsView);
 
     fullScreenToolTip = new QLabel(comicsView);
     fullScreenToolTip->setText(tr("<font color='white'> press 'F' to close fullscreen mode </font>"));
@@ -887,6 +891,8 @@ void LibraryWindow::createConnections()
 
     connect(comicsViewTransition,SIGNAL(transitionFinished()),this,SLOT(showComicsView()));
 
+    connect(dmCV,SIGNAL(isEmpty()),this,SLOT(showEmptyFolderView()));
+    connect(emptyFolderWidget,SIGNAL(subfolderSelected(QModelIndex,int)),this,SLOT(selectSubfolder(QModelIndex,int)));
 }
 
 void LibraryWindow::loadLibrary(const QString & name)
@@ -1075,8 +1081,20 @@ void LibraryWindow::loadCovers(const QModelIndex & mi)
     QStringList paths = dmCV->getPaths(currentPath());
 	checkEmptyFolder(&paths);
 
-	if(paths.size()>0)
+    if(paths.size()>0) {
         comicsView->setCurrentIndex(dmCV->index(0,0));
+        if(comicsViewStack->currentWidget() == emptyFolderWidget)
+            comicsViewStack->setCurrentWidget(comicsView);
+    }
+    else
+        emptyFolderWidget->setSubfolders(mi,dm->getSubfoldersNames(mi));
+}
+
+void LibraryWindow::selectSubfolder(const QModelIndex &mi, int child)
+{
+    QModelIndex dest = dm->index(child,0,mi);
+    foldersView->setCurrentIndex(dest);
+    loadCovers(dest);
 }
 
 void LibraryWindow::checkEmptyFolder(QStringList * paths)
@@ -1521,7 +1539,7 @@ void LibraryWindow::switchToComicsView(ComicsView * from, ComicsView * to)
     comicsView->setToolBar(editInfoToolBar);
 
     comicsViewStack->removeWidget(from);
-    comicsViewStack->insertWidget(0,comicsView);
+    comicsViewStack->addWidget(comicsView);
 
     delete from;
 
@@ -1530,7 +1548,7 @@ void LibraryWindow::switchToComicsView(ComicsView * from, ComicsView * to)
 
 void LibraryWindow::showComicsViewTransition()
 {
-    comicsViewStack->setCurrentIndex(1);
+    comicsViewStack->setCurrentWidget(comicsViewTransition);
     comicsViewTransition->startMovie();
 }
 
@@ -1556,14 +1574,22 @@ void LibraryWindow::toggleComicsView_delayed()
 
 void LibraryWindow::showComicsView()
 {
-    comicsViewStack->setCurrentIndex(0);
+    comicsViewStack->setCurrentWidget(comicsView);
+}
+
+void LibraryWindow::showEmptyFolderView()
+{
+    comicsViewStack->setCurrentWidget(emptyFolderWidget);
 }
 
 //TODO recover the current comics selection and restore it in the destination
 void LibraryWindow::toggleComicsView()
 {
-    QTimer::singleShot(0,this,SLOT(showComicsViewTransition()));
-    QTimer::singleShot(32,this,SLOT(toggleComicsView_delayed()));
+    if(comicsViewStack->currentWidget()!=emptyFolderWidget) {
+        QTimer::singleShot(0,this,SLOT(showComicsViewTransition()));
+        QTimer::singleShot(32,this,SLOT(toggleComicsView_delayed()));
+    } else
+        toggleComicsView_delayed();
 }
 
 void LibraryWindow::asignNumbers()
diff --git a/YACReaderLibrary/library_window.h b/YACReaderLibrary/library_window.h
index 5d098c12..2f9026f6 100644
--- a/YACReaderLibrary/library_window.h
+++ b/YACReaderLibrary/library_window.h
@@ -53,6 +53,8 @@ class ComicsView;
 class ClassicComicsView;
 class GridComicsView;
 class ComicsViewTransition;
+class EmptyFolderWidget;
+
 #include "comic_db.h"
 
 using namespace YACReader;
@@ -99,6 +101,7 @@ private:
     GridComicsView * gridComicsView;
     QStackedWidget * comicsViewStack;
     ComicsViewTransition * comicsViewTransition;
+    EmptyFolderWidget * emptyFolderWidget;
 
 	YACReaderTreeView * foldersView;
 	YACReaderLibraryListWidget * selectedLibrary;
@@ -207,104 +210,107 @@ private:
     void doComicsViewConnections();
 
 
-	//ACTIONS MANAGEMENT
-	void disableComicsActions(bool disabled);
-	void disableLibrariesActions(bool disabled);
-	void disableNoUpdatedLibrariesActions(bool disabled);
-	void disableFoldersActions(bool disabled);
+    //ACTIONS MANAGEMENT
+    void disableComicsActions(bool disabled);
+    void disableLibrariesActions(bool disabled);
+    void disableNoUpdatedLibrariesActions(bool disabled);
+    void disableFoldersActions(bool disabled);
 
-	void disableAllActions();
-	//void disableActions();
-	//void enableActions();
-	//void enableLibraryActions();
+    void disableAllActions();
+    //void disableActions();
+    //void enableActions();
+    //void enableLibraryActions();
 
-	QString currentPath();
+    QString currentPath();
 
-	//settings
-	QSettings * settings;
+    //settings
+    QSettings * settings;
 
-	//navigation backward and forward
-	int currentFolderNavigation;
-	QList<QModelIndex> history;
+    //navigation backward and forward
+    int currentFolderNavigation;
+    QList<QModelIndex> history;
 
-	bool removeError;
+    bool removeError;
 
     ComicsViewStatus comicsViewStatus;
 
 protected:
-		virtual void closeEvent ( QCloseEvent * event );
+    virtual void closeEvent ( QCloseEvent * event );
 public:
-	LibraryWindow();
-	public slots:
-		void loadLibrary(const QString & path);
-		void loadCovers(const QModelIndex & mi);
-		void checkEmptyFolder(QStringList * paths = 0);
-		void reloadCovers();
-		void openComic();
-		void createLibrary();
-		void create(QString source,QString dest, QString name);
-		void showAddLibrary();
-		void openLibrary(QString path, QString name);
-		void loadLibraries();
-		void saveLibraries();
-		void reloadCurrentLibrary();
-		void openLastCreated();
-		void updateLibrary();
-		//void deleteLibrary();
-		void openContainingFolder();
-        void setFolderAsNotCompleted();
-        void setFolderAsCompleted();
-        void setFolderAsFinished();
-        void setFolderAsNotFinished();
-		void openContainingFolderComic();
-		void deleteCurrentLibrary();
-		void removeLibrary();
-		void renameLibrary();
-		void rename(QString newName);
-		void cancelCreating();
-		void stopLibraryCreator();
-		void setRootIndex();
-		void toggleFullScreen();
-		void toNormal();
-		void toFullScreen();
-		void setFoldersFilter(QString filter);
-		void showProperties();
-		void exportLibrary(QString destPath);
-		void importLibrary(QString clc,QString destPath,QString name);
-		void reloadOptions();
-		void setCurrentComicsStatusReaded(YACReaderComicReadStatus readStatus);
-		void setCurrentComicReaded();
-		void setCurrentComicUnreaded();
-		void hideComicFlow(bool hide);
-		void showExportComicsInfo();
-		void showImportComicsInfo();
-		void asignNumbers();
-		void showNoLibrariesWidget();
-		void showRootWidget();
-		void showImportingWidget();
-		void manageCreatingError(const QString & error);
-		void manageUpdatingError(const QString & error);
-		void manageOpeningLibraryError(const QString & error);
-		QModelIndexList getSelectedComics();
-		void deleteComics();
-		//void showSocial();
-		void backward();
-		void forward();
-		void updateHistory(const QModelIndex & mi);
-        void updateFoldersViewConextMenu(const QModelIndex & mi);
-		void libraryAlreadyExists(const QString & name);
-		void importLibraryPackage();
-		void updateComicsView(quint64 libraryId, const ComicDB & comic);
-		void setCurrentComicOpened();
-		void showComicVineScraper();
-		void setRemoveError();
-		void checkRemoveError();
-        void resetComicRating();
-        void switchToComicsView(ComicsView *from, ComicsView *to);
-        void showComicsViewTransition();
-        void toggleComicsView_delayed();//used in orther to avoid flickering;
-        void showComicsView();
-        void toggleComicsView();
+    LibraryWindow();
+
+public slots:
+    void loadLibrary(const QString & path);
+    void loadCovers(const QModelIndex & mi);
+    void selectSubfolder(const QModelIndex & mi, int child);
+    void checkEmptyFolder(QStringList * paths = 0);
+    void reloadCovers();
+    void openComic();
+    void createLibrary();
+    void create(QString source,QString dest, QString name);
+    void showAddLibrary();
+    void openLibrary(QString path, QString name);
+    void loadLibraries();
+    void saveLibraries();
+    void reloadCurrentLibrary();
+    void openLastCreated();
+    void updateLibrary();
+    //void deleteLibrary();
+    void openContainingFolder();
+    void setFolderAsNotCompleted();
+    void setFolderAsCompleted();
+    void setFolderAsFinished();
+    void setFolderAsNotFinished();
+    void openContainingFolderComic();
+    void deleteCurrentLibrary();
+    void removeLibrary();
+    void renameLibrary();
+    void rename(QString newName);
+    void cancelCreating();
+    void stopLibraryCreator();
+    void setRootIndex();
+    void toggleFullScreen();
+    void toNormal();
+    void toFullScreen();
+    void setFoldersFilter(QString filter);
+    void showProperties();
+    void exportLibrary(QString destPath);
+    void importLibrary(QString clc,QString destPath,QString name);
+    void reloadOptions();
+    void setCurrentComicsStatusReaded(YACReaderComicReadStatus readStatus);
+    void setCurrentComicReaded();
+    void setCurrentComicUnreaded();
+    void hideComicFlow(bool hide);
+    void showExportComicsInfo();
+    void showImportComicsInfo();
+    void asignNumbers();
+    void showNoLibrariesWidget();
+    void showRootWidget();
+    void showImportingWidget();
+    void manageCreatingError(const QString & error);
+    void manageUpdatingError(const QString & error);
+    void manageOpeningLibraryError(const QString & error);
+    QModelIndexList getSelectedComics();
+    void deleteComics();
+    //void showSocial();
+    void backward();
+    void forward();
+    void updateHistory(const QModelIndex & mi);
+    void updateFoldersViewConextMenu(const QModelIndex & mi);
+    void libraryAlreadyExists(const QString & name);
+    void importLibraryPackage();
+    void updateComicsView(quint64 libraryId, const ComicDB & comic);
+    void setCurrentComicOpened();
+    void showComicVineScraper();
+    void setRemoveError();
+    void checkRemoveError();
+    void resetComicRating();
+    void switchToComicsView(ComicsView *from, ComicsView *to);
+    void showComicsViewTransition();
+    void toggleComicsView_delayed();//used in orther to avoid flickering;
+    void showComicsView();
+    void showEmptyFolderView();
+    void toggleComicsView();
 };
 
 #endif
diff --git a/images/empty_folder.png b/images/empty_folder.png
new file mode 100644
index 0000000000000000000000000000000000000000..fa3b13cde0239492769d94f53bf767b651edaf75
GIT binary patch
literal 2515
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

literal 0
HcmV?d00001