summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArno <am@disconnect.de>2010-11-27 12:28:34 +0100
committerArno <am@disconnect.de>2010-11-27 12:28:34 +0100
commitda30a02976792a07c72e8be01aebde019a6a09d5 (patch)
tree7643cddb956a258eea9aeda2990313fd6fa92d32
parent0f3f7598e4a3ee58c330cc7424cf89ea3e692da0 (diff)
downloadSheMov-da30a02976792a07c72e8be01aebde019a6a09d5.tar.gz
SheMov-da30a02976792a07c72e8be01aebde019a6a09d5.tar.bz2
SheMov-da30a02976792a07c72e8be01aebde019a6a09d5.zip
Implemented dialog for showing movies without covers
Implemented a new dialog to show movies without covers. The view is a QTreeView with another model. While working on the model several shortcomings of SmTreeModel were resolved. findValue() now takes another argument to indicate the column the returned QModelIndex() should represent. Also, itemAt() was promoted from private to protected. It's quite useful for derived classes.
-rw-r--r--archivetreeview.cpp190
-rw-r--r--archivetreeview.h68
-rw-r--r--seriestreemodel.cpp10
-rw-r--r--seriestreemodel.h2
-rw-r--r--shemov.cpp6
-rw-r--r--shemov.h1
-rw-r--r--shemov.qrc1
-rw-r--r--smtreemodel.h3
8 files changed, 276 insertions, 5 deletions
diff --git a/archivetreeview.cpp b/archivetreeview.cpp
index b00737e..3529b01 100644
--- a/archivetreeview.cpp
+++ b/archivetreeview.cpp
@@ -17,10 +17,25 @@
#include <QHash>
#include <QProcess>
#include <QMessageBox>
+#include <QSqlDatabase>
+#include <QSqlQuery>
+#include <QMenu>
+#include <QAction>
+#include <QContextMenuEvent>
+#include <QLabel>
+#include <QPushButton>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QProcess>
+#include <QUrl>
+#include <QMessageBox>
+#include <QClipboard>
+#include <QApplication>
#include "archivetreeview.h"
#include "smglobals.h"
#include "smtreemodel.h"
+#include "smtreeitem.h"
#include "seriestreewidget.h"
#include "filestreewidget.h"
#include "filestreemodel.h"
@@ -67,6 +82,11 @@ ArchiveTreeView::ArchiveTreeView(QWidget *parent) : QWidget(parent){
verticalSplitter->setStretchFactor(0, 3);
verticalSplitter->setStretchFactor(1, 1);
+ // misc
+ mNoCoverDialog = new NoCoverMovieDialog(this);
+ mNoCoverDialog->setHidden(true);
+ connect(mNoCoverDialog->view(), SIGNAL(doubleClicked(QModelIndex)), this, SLOT(selectMovie(QModelIndex)));
+
// layout
QHBoxLayout *mainLayout = new QHBoxLayout;
QSplitter *splitter = new QSplitter;
@@ -132,6 +152,28 @@ void ArchiveTreeView::cleanDatabase(const QString &table){
}
}
+void ArchiveTreeView::showNoCoverDialog(){
+ mNoCoverDialog->show();
+}
+
+void ArchiveTreeView::selectMovie(const QModelIndex &idx){
+ if(!idx.isValid()){
+ return;
+ }
+ QVariant movieName = idx.data(NoCoverMovieModel::SeriesNameRole);
+ QVariant part = idx.data(NoCoverMovieModel::SeriesPartRole);
+ QModelIndex movieIdx = mSeriesModel->findValue(movieName, QModelIndex(), SeriesTreeModel::Name);
+ if(!movieIdx.isValid()){
+ return;
+ }
+ QModelIndex partIdx = mSeriesModel->findValue(part, movieIdx, SeriesTreeModel::SeriesPart, 0);
+ QModelIndex toSelect = partIdx.isValid() ? mSeriesWidget->seriesProxy()->mapFromSource(partIdx) : mSeriesWidget->seriesProxy()->mapFromSource(movieIdx);
+ mSeriesWidget->seriesTree()->expand(mSeriesWidget->seriesProxy()->mapFromSource(movieIdx));
+ mSeriesWidget->seriesTree()->selectionModel()->select(toSelect, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ mSeriesWidget->seriesTree()->scrollTo(toSelect, QAbstractItemView::PositionAtCenter);
+ mNoCoverDialog->hide();
+}
+
void ArchiveTreeView::currentChanged(const QItemSelection &selected, const QItemSelection &deselected){
Q_UNUSED(selected);
Q_UNUSED(deselected);
@@ -224,3 +266,151 @@ void ArchiveTreeView::constructWindowTitle(){
mWindowTitle = QString("Movie Archive - [%1]").arg(modeString);
emit needWindowTitleChange(mWindowTitle);
}
+
+//NoCoverMovieModel
+
+NoCoverMovieModel::NoCoverMovieModel(const QStringList &headers, QObject *parent) : SmTreeModel(headers, parent){
+ mDb = QSqlDatabase::database("treedb");
+ mDataQuery = new QSqlQuery(mDb);
+ mDataQuery->prepare("SELECT files.iseriespart_id, series.tseries_name, seriesparts.iseriespart FROM files, series, seriesparts WHERE files.iseriespart_id = seriesparts.iseriesparts_id AND seriesparts.iseries_id = series.iseries_id GROUP BY files.iseriespart_id,series.tseries_name,seriesparts.iseriespart HAVING COUNT(iseriespart_id) = 1 ORDER BY series.tseries_name");
+ refresh();
+}
+
+QVariant NoCoverMovieModel::data(const QModelIndex &index, int role) const{
+ if(!index.isValid()){
+ return QVariant();
+ }
+ SmTreeItem *item = itemAt(index);
+ if(role == SeriesNameRole){
+ return item->data(SeriesName);
+ }
+ if(role == SeriesPartRole){
+ return item->data(SeriesPart);
+ }
+ if(role == SeriesIdRole){
+ return item->data(SeriesId);
+ }
+ return SmTreeModel::data(index, role);
+} void populate();
+
+
+void NoCoverMovieModel::refresh(){
+ SmTreeItem *rootItem = new SmTreeItem(4);
+ mDataQuery->exec();
+ while(mDataQuery->next()){
+ QString displayName = QString("%1 %2").arg(mDataQuery->value(1).toString()).arg(QString::number(mDataQuery->value(2).toInt()));
+ QList<QVariant> data;
+ data << displayName << mDataQuery->value(1) << mDataQuery->value(2) << mDataQuery->value(0);
+ SmTreeItem *child = new SmTreeItem(data, rootItem);
+ rootItem->appendChild(child);
+ }
+ setRoot(rootItem);
+ emit refreshed();
+}
+
+Qt::ItemFlags NoCoverMovieModel::flags(const QModelIndex &index) const{
+ if(!index.isValid()){
+ return 0;
+ }
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+}
+
+//NoCoverMovieView
+
+NoCoverMovieView::NoCoverMovieView(QWidget *parent) : QTreeView(parent) {}
+
+void NoCoverMovieView::contextMenuEvent(QContextMenuEvent *e){
+ QMenu ctxMenu;
+ foreach(QAction *a, actions()){
+ ctxMenu.addAction(a);
+ }
+ ctxMenu.exec(e->globalPos());
+}
+
+//NoCoverMovieDialog
+
+NoCoverMovieDialog::NoCoverMovieDialog(QWidget *parent, Qt::WindowFlags flags) : QDialog(parent, flags){
+ //model + view
+ mView = new NoCoverMovieView;
+ QStringList headers = QStringList() << "Movie" << "Name" << "Part" << "Id";
+ mModel = new NoCoverMovieModel(headers);
+ mView->setModel(mModel);
+ connect(mModel, SIGNAL(refreshed()), this, SLOT(updateLabel()));
+ mView->setColumnHidden(1, true);
+ mView->setColumnHidden(2, true);
+ mView->setColumnHidden(3, true);
+ mView->resizeColumnToContents(0);
+
+ //actions
+ mBrowserA = new QAction(tr("Search with google..."), this);
+ connect(mBrowserA, SIGNAL(triggered()), this, SLOT(openInBrowser()));
+ mView->addAction(mBrowserA);
+ mCopyA = new QAction(tr("Copy name"), this);
+ connect(mCopyA, SIGNAL(triggered()), this, SLOT(copyToClipboard()));
+ mView->addAction(mCopyA);
+
+ //buttons
+ QHBoxLayout *buttonLayout = new QHBoxLayout;
+ mClose = new QPushButton(tr("Close"));
+ connect(mClose, SIGNAL(clicked()), this, SLOT(hide()));
+ mRefresh = new QPushButton(tr("Refresh"));
+ connect(mRefresh, SIGNAL(clicked()), mModel, SLOT(refresh()));
+ buttonLayout->addWidget(mRefresh);
+ buttonLayout->addStretch();
+ buttonLayout->addWidget(mClose);
+
+ //label
+ mMovieLabel = new QLabel(labelText());
+
+ //main
+ QVBoxLayout *mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(mMovieLabel);
+ mainLayout->addWidget(mView);
+ mainLayout->addLayout(buttonLayout);
+ setLayout(mainLayout);
+}
+
+void NoCoverMovieDialog::openInBrowser(){
+ QString selText = selectedText();
+ if(selText.isEmpty()){
+ return;
+ }
+ selText.append(" covers");
+ QByteArray searchString = QUrl::toPercentEncoding(selText);
+ QString url = QString("http://www.google.com/search?hl=en&q=%1").arg(QString(searchString));
+ QStringList args = QStringList() << "openURL" << url;
+ bool success = QProcess::startDetached("kfmclient", args);
+ if(!success){
+ QMessageBox::critical(this, tr("Error"), tr("Launching browser failed. Most likely kfmclient is not installed"));
+ }
+}
+
+void NoCoverMovieDialog::copyToClipboard(){
+ QString selText = selectedText();
+ if(selText.isEmpty()){
+ return;
+ }
+ QClipboard *clip = QApplication::clipboard();
+ clip->setText(selText);
+}
+
+void NoCoverMovieDialog::updateLabel(){
+ mMovieLabel->setText(labelText());
+}
+
+const QString NoCoverMovieDialog::selectedText() const{
+ QModelIndexList selected = mView->selectionModel()->selectedRows();
+ if(selected.isEmpty()){
+ return QString();
+ }
+ QModelIndex real = mModel->index(selected.at(0).row(), 0, selected.at(0).parent());
+ if(!real.isValid()){
+ return QString();
+ }
+ return real.data().toString();
+}
+
+const QString NoCoverMovieDialog::labelText() const{
+ QString retval = QString(tr("Movies without covers (%1)")).arg(QString::number(mModel->rowCount(QModelIndex())));
+ return retval;
+}
diff --git a/archivetreeview.h b/archivetreeview.h
index ddfad7e..2789298 100644
--- a/archivetreeview.h
+++ b/archivetreeview.h
@@ -11,6 +11,11 @@
#include <QWidget>
#include <QModelIndexList>
#include <QList>
+#include <QSqlDatabase>
+#include <QTreeView>
+#include <QDialog>
+
+#include "smtreemodel.h"
class SeriesTreeWidget;
class FilesTreeWidget;
@@ -18,7 +23,12 @@ class FilesTreeModel;
class SeriesTreeModel;
class MappingTableWidget;
class MappingTableModel;
+class NoCoverMovieDialog;
class QItemSelection;
+class QSqlQuery;
+class QPushButton;
+class QContextMenuEvent;
+class QLabel;
class ArchiveTreeView : public QWidget
{
@@ -35,6 +45,8 @@ class ArchiveTreeView : public QWidget
public slots:
void setFileViewMode(int mode);
void cleanDatabase(const QString &table);
+ void showNoCoverDialog();
+ void selectMovie(const QModelIndex &idx);
private slots:
void currentChanged(const QItemSelection &selected, const QItemSelection &deselected);
@@ -59,6 +71,62 @@ class ArchiveTreeView : public QWidget
//misc
QString mWindowTitle;
+ NoCoverMovieDialog *mNoCoverDialog;
+};
+
+class NoCoverMovieModel : public SmTreeModel {
+ Q_OBJECT
+ public:
+ enum CustomRoles { SeriesNameRole = Qt::UserRole + 1, SeriesPartRole = Qt::UserRole + 2, SeriesIdRole = Qt::UserRole + 3 };
+ enum Fields { Display = 0, SeriesName = 1, SeriesPart = 2, SeriesId = 3 };
+ explicit NoCoverMovieModel(const QStringList &headers, QObject *parent = 0);
+ virtual ~NoCoverMovieModel() {}
+ virtual QVariant data(const QModelIndex &index, int role) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ public slots:
+ void refresh();
+
+ signals:
+ void refreshed();
+
+ private:
+ QSqlDatabase mDb;
+ QSqlQuery *mDataQuery;
+};
+
+class NoCoverMovieView : public QTreeView {
+ Q_OBJECT
+ public:
+ explicit NoCoverMovieView(QWidget *parent = 0);
+ virtual ~NoCoverMovieView() {}
+
+ protected:
+ void contextMenuEvent(QContextMenuEvent *e);
+};
+
+class NoCoverMovieDialog : public QDialog {
+ Q_OBJECT
+ public:
+ explicit NoCoverMovieDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ virtual ~NoCoverMovieDialog() {}
+ NoCoverMovieView *view() { return mView; }
+
+ private slots:
+ void openInBrowser();
+ void copyToClipboard();
+ void updateLabel();
+
+ private:
+ const QString selectedText() const;
+ const QString labelText() const;
+ QPushButton *mClose;
+ QPushButton *mRefresh;
+ NoCoverMovieView *mView;
+ NoCoverMovieModel *mModel;
+ QLabel *mMovieLabel;
+ QAction *mCopyA;
+ QAction *mBrowserA;
};
#endif
diff --git a/seriestreemodel.cpp b/seriestreemodel.cpp
index ab3fe8c..a2bde55 100644
--- a/seriestreemodel.cpp
+++ b/seriestreemodel.cpp
@@ -164,15 +164,19 @@ QList<QVariant> SeriesTreeModel::childrenColumnList(const QModelIndex &parent, i
return retval;
}
-QModelIndex SeriesTreeModel::findValue(const QVariant &value, const QModelIndex &parent, int column) const{
+QModelIndex SeriesTreeModel::findValue(const QVariant &value, const QModelIndex &parent, int searchColumn, int indexColumn) const{
SmTreeItem *parentItem = root();
if(parent != QModelIndex()){
parentItem = static_cast<SmTreeItem*>(parent.internalPointer());
}
for(int i = 0; i < parentItem->childCount(); ++i){
SmTreeItem *childItem = parentItem->child(i);
- if(value == childItem->data(column)){
- return createIndex(i, column, childItem);
+ if(value == childItem->data(searchColumn)){
+ if(indexColumn == -1){
+ return createIndex(i, searchColumn, childItem);
+ }else{
+ return createIndex(i, indexColumn, childItem);
+ }
}
}
return QModelIndex();
diff --git a/seriestreemodel.h b/seriestreemodel.h
index 63820ec..e26e49b 100644
--- a/seriestreemodel.h
+++ b/seriestreemodel.h
@@ -35,7 +35,7 @@ class SeriesTreeModel : public SmTreeModel {
QList<QVariant> childrenColumnList(const QModelIndex &parent, int column) const;
//find
- QModelIndex findValue(const QVariant &value, const QModelIndex &parent = QModelIndex(), int column = 0) const;
+ QModelIndex findValue(const QVariant &value, const QModelIndex &parent = QModelIndex(), int searchColumn = 0, int indexColumn = -1) const;
QFileInfoList findFiles(const QModelIndex &where) const;
QFileInfoList findMovies(const QModelIndexList &from) const;
QFileInfoList findSortedMovies(const QModelIndex &from) const;
diff --git a/shemov.cpp b/shemov.cpp
index 8821a7b..7cbbce6 100644
--- a/shemov.cpp
+++ b/shemov.cpp
@@ -165,6 +165,7 @@ void SheMov::tabChanged(int newTab){
mShowNormalA->setEnabled(false);
mShowArchivedA->setEnabled(false);
mShowLocalA->setEnabled(false);
+ mShowNoCoverDialogA->setEnabled(false);
}
if(newTab == 1){
setWindowTitle(mATree->windowTitle());
@@ -173,6 +174,7 @@ void SheMov::tabChanged(int newTab){
mShowNormalA->setEnabled(true);
mShowArchivedA->setEnabled(true);
mShowLocalA->setEnabled(true);
+ mShowNoCoverDialogA->setEnabled(true);
}
updateSelectionCount(QItemSelection(), QItemSelection());
}
@@ -413,6 +415,8 @@ void SheMov::createActions(){
connect(mShowNormalA, SIGNAL(triggered()), viewMapper, SLOT(map()));
mShowNormalA->setCheckable(true);
mShowNormalA->setChecked(true);
+ mShowNoCoverDialogA = new QAction(QIcon(":/higheels.png"), tr("List movies without cover..."), this);
+ connect(mShowNoCoverDialogA, SIGNAL(triggered()), mATree, SLOT(showNoCoverDialog()));
//Tree FileWidget actions
mMoveToBurnA = new QAction(tr("Move to burn directory"), this);
@@ -457,6 +461,7 @@ void SheMov::createMenus(){
cleanupMenu->addActions(mCleanupGroup->actions());
fileMenu->addMenu(cleanupMenu);
fileMenu->addAction(mConsistencyA);
+ fileMenu->addAction(mShowNoCoverDialogA);
fileMenu->addSeparator();
fileMenu->addAction(mQuitA);
menuBar()->addMenu(fileMenu);
@@ -638,6 +643,7 @@ void SheMov::createToolBar(){
toolBar->addAction(mCdupA);
toolBar->addSeparator();
toolBar->addAction(mConfigA);
+ toolBar->addAction(mShowNoCoverDialogA);
toolBar->addSeparator();
toolBar->addAction(mShowNormalA);
toolBar->addAction(mShowArchivedA);
diff --git a/shemov.h b/shemov.h
index 9ffa69b..de80a41 100644
--- a/shemov.h
+++ b/shemov.h
@@ -115,6 +115,7 @@ class SheMov : public QMainWindow {
QAction *mShowLocalA;
QAction *mShowArchivedA;
QAction *mShowNormalA;
+ QAction *mShowNoCoverDialogA;
QActionGroup *mViewTreeGroup;
//TreeView FileWidget Actions
diff --git a/shemov.qrc b/shemov.qrc
index 068dfef..5f7e302 100644
--- a/shemov.qrc
+++ b/shemov.qrc
@@ -16,5 +16,6 @@
<file>bald_pussy.png</file>
<file>prince_albert.png</file>
<file>diaper.png</file>
+ <file>higheels.png</file>
</qresource>
</RCC>
diff --git a/smtreemodel.h b/smtreemodel.h
index 6d89fb2..3eae432 100644
--- a/smtreemodel.h
+++ b/smtreemodel.h
@@ -46,9 +46,10 @@ class SmTreeModel : public QAbstractItemModel {
bool removeRows(int row, int count, const QModelIndex &parent);
bool addRow(const QList<QVariant> &data, const QModelIndex &parent);
+ protected:
+ SmTreeItem *itemAt(const QModelIndex &index) const;
private:
- SmTreeItem *itemAt(const QModelIndex &index) const;
QStringList mHeaders;
SmTreeItem *mRootItem;
};