diff options
-rw-r--r-- | archivetreeview.cpp | 190 | ||||
-rw-r--r-- | archivetreeview.h | 68 | ||||
-rw-r--r-- | seriestreemodel.cpp | 10 | ||||
-rw-r--r-- | seriestreemodel.h | 2 | ||||
-rw-r--r-- | shemov.cpp | 6 | ||||
-rw-r--r-- | shemov.h | 1 | ||||
-rw-r--r-- | shemov.qrc | 1 | ||||
-rw-r--r-- | smtreemodel.h | 3 |
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; @@ -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); @@ -115,6 +115,7 @@ class SheMov : public QMainWindow { QAction *mShowLocalA; QAction *mShowArchivedA; QAction *mShowNormalA; + QAction *mShowNoCoverDialogA; QActionGroup *mViewTreeGroup; //TreeView FileWidget Actions @@ -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; }; |