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;  };  | 
