diff options
-rw-r--r-- | archivecontroller.cpp | 11 | ||||
-rw-r--r-- | archivecontroller.h | 1 | ||||
-rw-r--r-- | filepropertiesdialog.cpp | 214 | ||||
-rw-r--r-- | filepropertiesdialog.h | 34 | ||||
-rw-r--r-- | fileview.cpp | 11 | ||||
-rw-r--r-- | fileview.h | 1 | ||||
-rw-r--r-- | helper.cpp | 16 | ||||
-rw-r--r-- | helper.h | 2 | ||||
-rw-r--r-- | shemov.cpp | 17 | ||||
-rw-r--r-- | shemov.h | 3 | ||||
-rw-r--r-- | smglobals.cpp | 4 | ||||
-rw-r--r-- | smglobals.h | 7 | ||||
-rw-r--r-- | smtreeview.cpp | 5 |
13 files changed, 191 insertions, 135 deletions
diff --git a/archivecontroller.cpp b/archivecontroller.cpp index d75f52f..4475166 100644 --- a/archivecontroller.cpp +++ b/archivecontroller.cpp @@ -18,6 +18,7 @@ #include "archivemodel.h" #include "archiveview.h" #include "pictureviewer2.h" +#include "filepropertiesdialog.h" #include "smglobals.h" #include "helper.h" @@ -165,6 +166,16 @@ void ArchiveController::editFileNo(){ } } +void ArchiveController::showProperties(){ + QModelIndexList sel = mFileSelection->selectedRows(ArchiveFilesModel::FullPath); + if(sel.isEmpty()){ + return; + } + QModelIndex first = sel.first(); + FilePropertiesDialog dlg(first.data().toString()); + dlg.exec(); +} + void ArchiveController::addActionForTree(QAction *a){ mActionsForTree << a; mArchiveTree->addAction(a); diff --git a/archivecontroller.h b/archivecontroller.h index 4f24973..2fbde4e 100644 --- a/archivecontroller.h +++ b/archivecontroller.h @@ -51,6 +51,7 @@ class ArchiveController : public QObject { void editDvdNo(); void editFileType(); void editFileNo(); + void showProperties(); void addActionForTree(QAction *a); void readConfig(); diff --git a/filepropertiesdialog.cpp b/filepropertiesdialog.cpp index a22076c..f130b0b 100644 --- a/filepropertiesdialog.cpp +++ b/filepropertiesdialog.cpp @@ -5,121 +5,137 @@ 2 of the License, or (at your option) any later version. */ -#include <QtWidgets/QHBoxLayout> -#include <QtWidgets/QLabel> -#include <QtWidgets/QPushButton> -#include <QSettings> -#include <QApplication> +#include <QPushButton> +#include <QJsonDocument> +#include <QJsonArray> +#include <QJsonObject> +#include <QLabel> +#include <QHBoxLayout> +#include <QVBoxLayout> +#include <QTabWidget> +#include <QStackedWidget> +#include <QImage> #include "filepropertiesdialog.h" -#include "seriesmetadatamodel.h" +#include "smtreemodel.h" #include "smtreeitem.h" #include "smtreeview.h" #include "helper.h" -FilePropertiesDialog::FilePropertiesDialog(/*int seriesPartId, */QWidget *parent, Qt::WindowFlags f) : SmDialog(parent, f){ - //tab - mTab = new QTabWidget; +FilePropertiesDialog::FilePropertiesDialog(const QString &file, QWidget *parent, Qt::WindowFlags f) : SmDialog(parent, f), mFile(file){ + mStack = new QStackedWidget; + mTab = new QTabWidget; + QString lText = QString(tr("<b>Properties - %1</b>")).arg(mFile); + QLabel *l = new QLabel(lText); + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(l); - //stream data widget - QVBoxLayout *streamDataLayout = new QVBoxLayout; - QWidget *streamData = new QWidget; + QWidget *formatWidget = new QWidget; + mFormatView = new SmTreeView; + mFormatModel = new SmTreeModel(QStringList() << tr("Key") << tr("Value"), this); + mFormatView->setModel(mFormatModel); + QHBoxLayout *formatLayout = new QHBoxLayout; + formatLayout->addWidget(mFormatView); + formatWidget->setLayout(formatLayout); + mTab->addTab(formatWidget, tr("Format")); - //description - mDescriptionLabel = new QLabel(tr("Properties for [none]")); - mDescriptionLabel->setAutoFillBackground(true); - mDescriptionLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); - streamDataLayout->addWidget(mDescriptionLabel); - QSettings s; - QVariant varColor = s.value("ui/alternatecolor"); - QColor labelColor = varColor.value<QColor>(); - QPalette labelPalette = mDescriptionLabel->palette(); - labelPalette.setColor(QPalette::Window, labelColor); - mDescriptionLabel->setPalette(labelPalette); + QWidget *streamWidget = new QWidget; + mStreamView = new SmTreeView; + mStreamModel = new SmTreeModel(QStringList() << tr("Key") << tr("Value"), this); + mStreamView->setModel(mStreamModel); + QHBoxLayout *streamLayout = new QHBoxLayout; + streamLayout->addWidget(mStreamView); + streamWidget->setLayout(streamLayout); + mTab->addTab(streamWidget, tr("Streams")); + mStack->addWidget(mTab); - //the view + model - mModel = new SmTreeModel((QStringList() << QString() << QString()), this); - mView = new SmTreeView; - mView->setHeaderHidden(true); - mView->setEditTriggers(QAbstractItemView::NoEditTriggers); - mView->setModel(mModel); - streamDataLayout->addWidget(mView); - streamData->setLayout(streamDataLayout); - mTab->addTab(streamData, tr("Stream data")); + QWidget *picWidget = new QWidget; + mPicView = new SmTreeView; + mPicModel = new SmTreeModel(QStringList() << tr("Key") << tr("Value"), this); + mPicView->setModel(mPicModel); + QHBoxLayout *picLayout = new QHBoxLayout; + picLayout->addWidget(mPicView); + picWidget->setLayout(picLayout); + mStack->addWidget(picWidget); - //metadata widget - mMetadata = new MetadataWidget; - mTab->addTab(mMetadata, tr("Metadata")); + mainLayout->addWidget(mStack); + mOk = new QPushButton(tr("Ok")); + connect(mOk, SIGNAL(clicked()), this, SLOT(accept())); + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + buttonLayout->addWidget(mOk); + buttonLayout->addStretch(); + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); - //buttons - QHBoxLayout *buttonLayout = new QHBoxLayout; - mOk = new QPushButton(tr("Ok")); - connect(mOk, SIGNAL(clicked()), this, SLOT(accept())); - connect(mOk, SIGNAL(clicked()), mMetadata, SLOT(accept())); - mCancel = new QPushButton(tr("Cancel")); - connect(mCancel, SIGNAL(clicked()), this, SLOT(reject())); - buttonLayout->setAlignment(Qt::AlignRight); - buttonLayout->addWidget(mOk); - buttonLayout->addWidget(mCancel); + QString mimeType = Helper::mimeType(mFile); + if(mimeType.startsWith("video")){ + mStack->setCurrentIndex(0); + movieData(); + }else if(mimeType.startsWith("image")){ + mStack->setCurrentIndex(1); + pictureData(); + } +} - //main layout - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(mTab); - mainLayout->addLayout(buttonLayout); - setLayout(mainLayout); - setMinimumWidth(450); +void FilePropertiesDialog::movieData(){ + QJsonDocument jsDoc = Helper::streamData(mFile); + if(jsDoc.isNull()){ + return; + } + QJsonObject obj = jsDoc.object(); + SmTreeItem *formatItem = new SmTreeItem(2); + movieDataRecursive(obj.value("format"), formatItem); + mFormatModel->setRoot(formatItem); + mFormatView->expandAll(); + SmTreeItem *streamItem = new SmTreeItem(2); + QJsonArray streamA = obj.value("streams").toArray(); + for(int i = 0; i < streamA.size(); ++i){ + QString itemName = QString(tr("Stream %1 [%2]")).arg(QString::number(i + 1)).arg(streamA.at(i).toObject().value("codec_type").toString()); + SmTreeItem *item = new SmTreeItem(QList<QVariant>() << itemName << QVariant(), streamItem); + streamItem->appendChild(item); + movieDataRecursive(streamA.at(i), item); + } + mStreamModel->setRoot(streamItem); + mStreamView->expandAll(); } -void FilePropertiesDialog::setFileName(const QString &fileName){ - QString text = QString(tr("Properties for %1")).arg(fileName); - mDescriptionLabel->setText(text); - setWindowTitle(text); +void FilePropertiesDialog::movieDataRecursive(QJsonValue start, SmTreeItem *appendTo){ + QJsonObject sObject = start.toObject(); + QJsonObject::const_iterator it; + for(it = sObject.constBegin(); it != sObject.constEnd(); ++it){ + QList<QVariant> data = QList<QVariant>() << it.key() << it.value().toVariant(); + if(it.key() == "duration"){ + qint64 seconds = it.value().toString().toDouble(); + Helper::Duration dur(seconds); + data[1] = dur.toString(); + } + if(it.key() == "bit_rate"){ + qint64 br = it.value().toString().toInt() / 1000; + data[1] = QString("%1 kb/s").arg(QString::number(br)); + } + SmTreeItem *newItem = new SmTreeItem(data, appendTo); + appendTo->appendChild(newItem); + movieDataRecursive(*it, newItem); + } } -void FilePropertiesDialog::setStreamData(const QList<QMap<QString, QString> > &streamData){ - SmTreeItem *root = new SmTreeItem(2); - for(int i = 0; i < streamData.size(); ++i){ - QList<QVariant> titleData; - QString title = QString(tr("Stream %1")).arg(QString::number(i)); - titleData << title << QVariant(); - SmTreeItem *titleItem = new SmTreeItem(titleData, root); - root->appendChild(titleItem); - QMap<QString, QString>::const_iterator it = streamData.at(i).constBegin(); - while(it != streamData.at(i).constEnd()){ - QList<QVariant> itemData; - if(it.key() == "duration" && it.value() != "N/A"){ - qint64 duration = it.value().toFloat(); - itemData << it.key() << Helper::durationFromSecs(duration); - }else{ - itemData << it.key() << it.value(); - } - SmTreeItem *item = new SmTreeItem(itemData, titleItem); - titleItem->appendChild(item); - ++it; - } - } - mModel->setRoot(root); - mView->expandAll(); - mView->resizeColumnToContents(0); - mView->resizeColumnToContents(1); +void FilePropertiesDialog::pictureData(){ + QImage img = QImage(mFile); + if(img.isNull()){ + return; + } + SmTreeItem *rootItem = new SmTreeItem(2); + appendItem(QList<QVariant>() << tr("width") << img.width(), rootItem); + appendItem(QList<QVariant>() << tr("height") << img.height(), rootItem); + appendItem(QList<QVariant>() << tr("depth") << img.depth(), rootItem); + appendItem(QList<QVariant>() << tr("alpha channel") << (img.hasAlphaChannel() ? tr("yes") : tr("no")), rootItem); + appendItem(QList<QVariant>() << tr("qt format") << img.format(), rootItem); + appendItem(QList<QVariant>() << tr("byte count") << img.byteCount(), rootItem); + mPicModel->setRoot(rootItem); } -void FilePropertiesDialog::addData(const QString &caption, const QMap<QString, QString> &data){ - SmTreeItem *root = new SmTreeItem(*mModel->root()); - QList<QVariant> titleData; - titleData << caption << QVariant(); - SmTreeItem *titleItem = new SmTreeItem(titleData, root); - root->appendChild(titleItem); - QMap<QString, QString>::const_iterator it = data.constBegin(); - while(it != data.constEnd()){ - QList<QVariant> itemData; - itemData << it.key() << it.value(); - SmTreeItem *item = new SmTreeItem(itemData, titleItem); - titleItem->appendChild(item); - ++it; - } - mModel->setRoot(root); - mView->expandAll(); - mView->resizeColumnToContents(0); - mView->resizeColumnToContents(1); +void FilePropertiesDialog::appendItem(const QList<QVariant> &data, SmTreeItem *parent){ + SmTreeItem *item = new SmTreeItem(data, parent); + parent->appendChild(item); } diff --git a/filepropertiesdialog.h b/filepropertiesdialog.h index ee9aa96..425f6e6 100644 --- a/filepropertiesdialog.h +++ b/filepropertiesdialog.h @@ -10,29 +10,33 @@ #include "smdialog.h" +class QPushButton; class SmTreeView; -class QLabel; -class QTabWidget; +class SmTreeItem; class SmTreeModel; -class MetadataWidget; +class QTabWidget; +class QStackedWidget; class FilePropertiesDialog : public SmDialog { Q_OBJECT public: - explicit FilePropertiesDialog(/*int seriesPartId, */QWidget *parent = 0, Qt::WindowFlags f = 0); - void setFileName(const QString &fileName); - void setStreamData(const QList<QMap<QString, QString> > &streamData); - void addData(const QString &caption, const QMap<QString, QString> &data); - MetadataWidget *metaWidget() { return mMetadata; }; + explicit FilePropertiesDialog(const QString &file, QWidget *parent = 0, Qt::WindowFlags f = 0); private: - QTabWidget *mTab; - MetadataWidget *mMetadata; - SmTreeView *mView; - QPushButton *mOk; - QPushButton *mCancel; - QLabel *mDescriptionLabel; - SmTreeModel *mModel; + void movieData(); + void movieDataRecursive(QJsonValue start, SmTreeItem *appendTo); + void pictureData(); + void appendItem(const QList<QVariant> &data, SmTreeItem *parent); + QTabWidget *mTab; + QStackedWidget *mStack; + QPushButton *mOk; + SmTreeModel *mFormatModel; + SmTreeView *mFormatView; + SmTreeModel *mStreamModel; + SmTreeView *mStreamView; + SmTreeModel *mPicModel; + SmTreeView *mPicView; + QString mFile; }; #endif // FILEPROPERTIESDIALOG_H diff --git a/fileview.cpp b/fileview.cpp index 336d179..80a81bd 100644 --- a/fileview.cpp +++ b/fileview.cpp @@ -32,6 +32,7 @@ #include "hoverwindow.h" #include "smglobals.h" #include "filesystemfileproxy.h" +#include "filepropertiesdialog.h" #include "smdirmodel.h" #include "framecache.h" @@ -231,6 +232,16 @@ void FileView::selectedFilesChanged(){ emit selectedDuration(dur, false); } +void FileView::properties(){ + QModelIndexList selected = selectionModel()->selectedRows(); + if(selected.isEmpty()){ + return; + } + QString fp = selected.at(0).data(SmDirModel::FullPathRole).toString(); + FilePropertiesDialog fpd(fp, this); + fpd.exec(); +} + void FileView::saveSelection(){ mMd5Sums.clear(); QModelIndexList selected = selectionModel()->selectedRows(SmDirModel::Md5sum); @@ -49,6 +49,7 @@ class FileView : public SmTreeView { void saveSelection(); void restoreSelection(); void selectedFilesChanged(); + void properties(); protected slots: virtual void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint); @@ -223,7 +223,6 @@ namespace Helper { QSettings s; QString ffProbe = s.value("paths/ffprobe").toString(); QStringList args; - QVariantMap retval; args << "-v" << "quiet" << "-print_format" << "json" << "-show_format" << path; QProcess ffproc; ffproc.start(ffProbe, args); @@ -236,6 +235,21 @@ namespace Helper { return jsDoc.object().value("format").toObject().toVariantMap(); } + QJsonDocument streamData(const QString &path){ + QSettings s; + QString ffProbe = s.value("paths/ffprobe").toString(); + QStringList args; + args << "-v" << "quiet" << "-print_format" << "json" << "-show_format" << "-show_streams" << path; + QProcess ffproc; + ffproc.start(ffProbe, args); + if(!ffproc.waitForStarted()){ + return QJsonDocument(); + } + ffproc.waitForFinished(); + QByteArray ffData = ffproc.readAllStandardOutput(); + return QJsonDocument::fromJson(ffData); + } + Duration::Duration() : mHours(0), mMinutes(0), mSeconds(0) {} Duration::Duration(qint64 seconds){ @@ -13,6 +13,7 @@ #include <QVariant> #include <QList> #include <QMetaType> +#include <QJsonDocument> #include <magic.h> @@ -33,6 +34,7 @@ namespace Helper { const QString colorToHtml(const QColor &color); void centerWidget(QWidget *widget); QVariantMap ffmpegData(const QString &path); + QJsonDocument streamData(const QString &path); class Duration { public: Duration(); @@ -40,6 +40,7 @@ SheMov::SheMov(QWidget *parent, Qt::WindowFlags flags) : QMainWindow(parent, flags), mOpenWithGroupFS(0), mOpenWithGroupAV(0) { //application icon qApp->setWindowIcon(QIcon(":/shemov.png")); + createPalette(); setAttribute(Qt::WA_DeleteOnClose); QSplashScreen splash(QPixmap(":/shemov_splash2.png")); splash.show(); @@ -435,6 +436,8 @@ void SheMov::createActions(){ //View menu (FS) mRefreshA = new QAction(tr("Refresh"), this); connect(mRefreshA, SIGNAL(triggered()), mFSWidget->fileModel(), SLOT(refresh())); + mFSViewPropertiesA = new QAction(tr("Properties..."), this); + connect(mFSViewPropertiesA, SIGNAL(triggered()), mFSWidget->fileView(), SLOT(properties())); //Help menu QString aboutLabel = QString(tr("About %1...")).arg(qApp->applicationName()); @@ -596,6 +599,9 @@ void SheMov::createActions(){ // set file no mArchiveFilesFileNoA = new QAction(tr("Set File No. ..."), this); connect(mArchiveFilesFileNoA, SIGNAL(triggered()), c, SLOT(editFileNo())); + // show properties + mArchiveFilesPropertiesA = new QAction(tr("Properties..."), this); + connect(mArchiveFilesPropertiesA, SIGNAL(triggered()), c, SLOT(showProperties())); // db analyzer dialogs // analyze actors @@ -756,6 +762,8 @@ void SheMov::createMenus(){ mFSWidget->fileView()->addAction(mArchiveSelectedPicsA); mFSWidget->fileView()->addAction(mArchiveSelectedMovsA); + mFSWidget->fileView()->addAction(createSeparator()); + mFSWidget->fileView()->addAction(mFSViewPropertiesA); // Movie archive ArchiveController *c = SmGlobals::instance()->archiveController(); @@ -775,6 +783,8 @@ void SheMov::createMenus(){ c->archiveFiles()->addAction(mArchiveFilesDvdNoA); c->archiveFiles()->addAction(mArchiveFilesTypeA); c->archiveFiles()->addAction(mArchiveFilesFileNoA); + c->archiveFiles()->addAction(createSeparator()); + c->archiveFiles()->addAction(mArchiveFilesPropertiesA); QMenu *archiveFilesM = new QMenu(tr("Files"), this); archiveFilesM->addActions(c->archiveFiles()->actions()); @@ -867,12 +877,7 @@ void SheMov::createPalette(){ pal.setColor(QPalette::Base, Qt::white); pal.setColor(QPalette::AlternateBase, Qt::white); } - foreach(QWidget *w, SmGlobals::instance()->treeWidgets()){ - SmTreeView *aiv = qobject_cast<SmTreeView*>(w); - if(aiv){ - aiv->setPalette(pal); - } - } + qApp->setPalette(pal); } void SheMov::rebuildFrameCache(){ @@ -16,7 +16,6 @@ class FilesystemWidget; class QLabel; class QSignalMapper; class QActionGroup; -//class ArchiveTreeView; class NewMovieWizard; class PicturesWidget; class SmTreeModel; @@ -108,6 +107,7 @@ class SheMov : public QMainWindow { QAction *mRebuildFrameCacheA; QAction *mNewMovieWizardA; QAction *mMoveToArchiveA; + QAction *mFSViewPropertiesA; //Filesystem View Actions QActionGroup *mFSHoverGroup; @@ -150,6 +150,7 @@ class SheMov : public QMainWindow { QAction *mArchiveFilesDvdNoA; QAction *mArchiveFilesTypeA; QAction *mArchiveFilesFileNoA; + QAction *mArchiveFilesPropertiesA; //DB analyze actions QAction *mAnalyzeActorsA; diff --git a/smglobals.cpp b/smglobals.cpp index 2ed698c..949b5ae 100644 --- a/smglobals.cpp +++ b/smglobals.cpp @@ -115,10 +115,6 @@ FrameCache *SmGlobals::frameCache() { return mFrameCache; } -SeriesTreeWidget *SmGlobals::seriesTreeWidget(){ - return mSeriesTreeWidget; -} - QSize SmGlobals::cursorSize() { if(!mCursorSize.isValid()){ Display *dpy = XOpenDisplay(0); diff --git a/smglobals.h b/smglobals.h index 5580f47..72604ab 100644 --- a/smglobals.h +++ b/smglobals.h @@ -9,11 +9,8 @@ #define SMUBERMODELSINGLETON_H #include <QObject> - #include <QHash> #include <QSize> -#include <QPair> -#include <QList> class QAbstractItemModel; class PictureViewer2; @@ -30,8 +27,6 @@ class SmGlobals : public QObject { QAbstractItemModel *model(const QString &which); PictureViewer2 *pictureViewer(); FrameCache *frameCache(); - void setSeriesTreeWidget(SeriesTreeWidget *stree) { mSeriesTreeWidget = stree; } - SeriesTreeWidget *seriesTreeWidget(); void setArchiveController(ArchiveController *c) { mArchiveController = c; } ArchiveController *archiveController() { return mArchiveController; } QSize cursorSize(); @@ -39,7 +34,6 @@ class SmGlobals : public QObject { const QSize minPVSize() const { return QSize(640, 480); } const QHash<QString, QString> & icons() const { return mIcons; } qint64 dvdSize() const { return mDvdSize; } - QList<QWidget*> &treeWidgets() { return mTreeWidgets; } QHash<int, QString> filetypeMap() const { return mFiletypeMap; } private: @@ -54,7 +48,6 @@ class SmGlobals : public QObject { QSize mCursorSize; QHash<QString, QString> mIcons; qint64 mDvdSize; - QList<QWidget*> mTreeWidgets; ArchiveController *mArchiveController; QHash<int, QString> mFiletypeMap; }; diff --git a/smtreeview.cpp b/smtreeview.cpp index d4faab8..7fd7b48 100644 --- a/smtreeview.cpp +++ b/smtreeview.cpp @@ -11,20 +11,21 @@ #include <QMenu> #include <QContextMenuEvent> #include <QSettings> +#include <QApplication> #include "smtreeview.h" #include "smglobals.h" SmTreeView::SmTreeView(QWidget *parent) : QTreeView(parent) { header()->setSectionResizeMode(QHeaderView::ResizeToContents); - SmGlobals::instance()->treeWidgets().append(this); setAlternatingRowColors(true); + setPalette(qApp->palette()); } SmTreeView::SmTreeView(const QString &hSetting, QWidget *parent) : QTreeView(parent), mHeaderSetting(hSetting){ header()->setSectionResizeMode(QHeaderView::ResizeToContents); - SmGlobals::instance()->treeWidgets().append(this); setAlternatingRowColors(true); + setPalette(qApp->palette()); } void SmTreeView::readHeaderConfig(){ |