WIP: property dialog

This commit is contained in:
Gary Wang 2020-10-30 13:06:46 +08:00
parent 0a9ea1982b
commit cf95436aa9
9 changed files with 411 additions and 31 deletions

View File

@ -23,6 +23,8 @@ set (PPIC_CPP_FILES
settings.cpp
settingsdialog.cpp
aboutdialog.cpp
metadatamodel.cpp
metadatadialog.cpp
)
set (PPIC_HEADER_FILES
@ -36,6 +38,8 @@ set (PPIC_HEADER_FILES
settings.h
settingsdialog.h
aboutdialog.h
metadatamodel.h
metadatadialog.h
)
set (PPIC_QRC_FILES

View File

@ -193,58 +193,105 @@
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.cpp" line="175"/>
<location filename="../mainwindow.cpp" line="178"/>
<source>File url list is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="408"/>
<location filename="../mainwindow.cpp" line="417"/>
<source>&amp;Copy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="429"/>
<location filename="../mainwindow.cpp" line="438"/>
<source>Copy P&amp;ixmap</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="434"/>
<location filename="../mainwindow.cpp" line="443"/>
<source>Copy &amp;File Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="444"/>
<location filename="../mainwindow.cpp" line="453"/>
<source>&amp;Paste Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="450"/>
<location filename="../mainwindow.cpp" line="459"/>
<source>&amp;Paste Image File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="492"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="30"/>
<location filename="../mainwindow.cpp" line="455"/>
<location filename="../mainwindow.cpp" line="464"/>
<source>Stay on top</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="34"/>
<location filename="../mainwindow.cpp" line="462"/>
<location filename="../mainwindow.cpp" line="471"/>
<source>Protected mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="469"/>
<location filename="../mainwindow.cpp" line="478"/>
<source>Configure...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="476"/>
<location filename="../mainwindow.cpp" line="485"/>
<source>Help</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MetadataDialog</name>
<message>
<location filename="../metadatadialog.cpp" line="16"/>
<source>Image Metadata</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MetadataModel</name>
<message>
<location filename="../metadatamodel.cpp" line="29"/>
<source>General</source>
<comment>General info about the image, section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="32"/>
<source>File Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="34"/>
<source>File Size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="36"/>
<source>Last Modified</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="38"/>
<source>Image Size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="46"/>
<source>%1 x %2</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>

View File

@ -193,58 +193,105 @@
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.cpp" line="175"/>
<location filename="../mainwindow.cpp" line="178"/>
<source>File url list is empty</source>
<translation> URL </translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="408"/>
<location filename="../mainwindow.cpp" line="417"/>
<source>&amp;Copy</source>
<translation>(&amp;C)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="429"/>
<location filename="../mainwindow.cpp" line="438"/>
<source>Copy P&amp;ixmap</source>
<translation>(&amp;I)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="434"/>
<location filename="../mainwindow.cpp" line="443"/>
<source>Copy &amp;File Path</source>
<translation>(&amp;F)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="444"/>
<location filename="../mainwindow.cpp" line="453"/>
<source>&amp;Paste Image</source>
<translation>(&amp;P)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="450"/>
<location filename="../mainwindow.cpp" line="459"/>
<source>&amp;Paste Image File</source>
<translation>(&amp;P)</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="492"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="30"/>
<location filename="../mainwindow.cpp" line="455"/>
<location filename="../mainwindow.cpp" line="464"/>
<source>Stay on top</source>
<translation></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="34"/>
<location filename="../mainwindow.cpp" line="462"/>
<location filename="../mainwindow.cpp" line="471"/>
<source>Protected mode</source>
<translation></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="469"/>
<location filename="../mainwindow.cpp" line="478"/>
<source>Configure...</source>
<translation>...</translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="476"/>
<location filename="../mainwindow.cpp" line="485"/>
<source>Help</source>
<translation></translation>
</message>
</context>
<context>
<name>MetadataDialog</name>
<message>
<location filename="../metadatadialog.cpp" line="16"/>
<source>Image Metadata</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MetadataModel</name>
<message>
<location filename="../metadatamodel.cpp" line="29"/>
<source>General</source>
<comment>General info about the image, section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="32"/>
<source>File Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="34"/>
<source>File Size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="36"/>
<source>Last Modified</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="38"/>
<source>Image Size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../metadatamodel.cpp" line="46"/>
<source>%1 x %2</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>

View File

@ -8,6 +8,8 @@
#include "graphicsscene.h"
#include "settingsdialog.h"
#include "aboutdialog.h"
#include "metadatamodel.h"
#include "metadatadialog.h"
#include <QMouseEvent>
#include <QMovie>
@ -487,6 +489,17 @@ void MainWindow::contextMenuEvent(QContextMenuEvent *event)
ad->deleteLater();
});
QAction * propertiesAction = new QAction(tr("Properties"));
connect(propertiesAction, &QAction::triggered, this, [ = ](){
MetadataModel * md = new MetadataModel();
md->setFile(currentFileUrl.toLocalFile());
MetadataDialog * ad = new MetadataDialog(this);
ad->setMetadataModel(md);
ad->exec();
ad->deleteLater();
});
if (copyMenu->actions().count() == 1) {
menu->addActions(copyMenu->actions());
} else {
@ -503,6 +516,10 @@ void MainWindow::contextMenuEvent(QContextMenuEvent *event)
menu->addSeparator();
menu->addAction(toggleSettings);
menu->addAction(helpAction);
if (currentFileUrl.isValid()) {
menu->addSeparator();
menu->addAction(propertiesAction);
}
menu->exec(mapToGlobal(event->pos()));
menu->deleteLater();

41
metadatadialog.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "metadatadialog.h"
#include <QDialogButtonBox>
#include <QTreeView>
#include <QVBoxLayout>
#include "metadatamodel.h"
MetadataDialog::MetadataDialog(QWidget *parent)
: QDialog(parent)
, m_treeView(new QTreeView(this))
{
m_treeView->setRootIsDecorated(false);
m_treeView->setIndentation(0);
setWindowTitle(tr("Image Metadata"));
QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
setLayout(new QVBoxLayout);
layout()->addWidget(m_treeView);
layout()->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::close, this, &QDialog::close);
}
MetadataDialog::~MetadataDialog()
{
}
void MetadataDialog::setMetadataModel(MetadataModel * model)
{
m_treeView->setModel(model);
m_treeView->expandAll();
}
QSize MetadataDialog::sizeHint() const
{
return QSize(520, 350);
}

26
metadatadialog.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef METADATADIALOG_H
#define METADATADIALOG_H
#include <QDialog>
QT_BEGIN_NAMESPACE
class QTreeView;
QT_END_NAMESPACE
class MetadataModel;
class MetadataDialog : public QDialog
{
Q_OBJECT
public:
explicit MetadataDialog(QWidget * parent);
~MetadataDialog() override;
void setMetadataModel(MetadataModel * model);
QSize sizeHint() const override;
private:
QTreeView * m_treeView = nullptr;
};
#endif // METADATADIALOG_H

159
metadatamodel.cpp Normal file
View File

@ -0,0 +1,159 @@
#include "metadatamodel.h"
#include <QDebug>
#include <QDateTime>
#include <QFileInfo>
#include <QImageReader>
MetadataModel::MetadataModel(QObject *parent)
: QAbstractItemModel(parent)
{
}
MetadataModel::~MetadataModel()
{
}
void MetadataModel::setFile(const QString &imageFilePath)
{
QFileInfo fileInfo(imageFilePath);
// It'll be fine if we don't re-use the image reader we pass to the graphics scene for now.
QImageReader imgReader(imageFilePath);
const QString & sizeString = QLocale().formattedDataSize(fileInfo.size());
const QString & timeString = QLocale().toString(fileInfo.lastModified(), QLocale::LongFormat);
const QString & imageSizeString = imageSize(imgReader.size());
appendSection(QStringLiteral("General"), tr("General", "General info about the image, section name."));
appendProperty(QStringLiteral("General"), QStringLiteral("General.Name"),
tr("File Name"), fileInfo.fileName());
appendProperty(QStringLiteral("General"), QStringLiteral("General.Size"),
tr("File Size"), sizeString);
appendProperty(QStringLiteral("General"), QStringLiteral("General.Time"),
tr("Last Modified"), timeString);
appendProperty(QStringLiteral("General"), QStringLiteral("General.ImageSize"),
tr("Image Size"), imageSizeString);
}
QString MetadataModel::imageSize(const QSize &size)
{
QString imageSize;
if (size.isValid()) {
imageSize = tr("%1 x %2").arg(QString::number(size.width()), QString::number(size.height()));
} else {
imageSize = QLatin1Char('-');
}
return imageSize;
}
bool MetadataModel::appendSection(const QString &sectionKey, const QString &sectionDisplayName)
{
if (m_sections.contains(sectionKey)) {
return false;
}
m_sections.append(sectionKey);
m_sectionProperties[sectionKey] = qMakePair<QString, QList<QString> >(sectionDisplayName, {});
return true;
}
bool MetadataModel::appendProperty(const QString &sectionKey, const QString &propertyKey, const QString &propertyDisplayName, const QString &propertyValue)
{
if (!m_sections.contains(sectionKey)) {
return false;
}
QList<QString> & propertyList = m_sectionProperties[sectionKey].second;
if (!propertyList.contains(propertyKey)) {
propertyList.append(propertyKey);
}
m_properties[propertyKey] = qMakePair<QString, QString>(propertyDisplayName, propertyValue);
return true;
}
bool MetadataModel::updateProperty(const QString &propertyKey, const QString &propertyValue)
{
if (m_properties.contains(propertyKey)) {
m_properties[propertyKey].second = propertyValue;
return true;
}
return false;
}
QModelIndex MetadataModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
if (!parent.isValid()) {
return createIndex(row, column, RowType::SectionRow);
} else {
// internalid param: row means nth section it belongs to.
return createIndex(row, column, RowType::PropertyRow + parent.row());
}
}
QModelIndex MetadataModel::parent(const QModelIndex &child) const
{
if (!child.isValid()) {
return QModelIndex();
}
if (child.internalId() == RowType::SectionRow) {
return QModelIndex();
} else {
return createIndex(child.internalId() - RowType::PropertyRow, 0, SectionRow);
}
}
int MetadataModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid()) {
return m_sections.count();
}
if (parent.internalId() == RowType::SectionRow) {
const QString & sectionKey = m_sections[parent.row()];
return m_sectionProperties[sectionKey].second.count();
}
return 0;
}
int MetadataModel::columnCount(const QModelIndex &) const
{
// Always key(display name) and value.
return 2;
}
QVariant MetadataModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
if (role != Qt::DisplayRole) {
return QVariant();
}
if (index.internalId() == RowType::SectionRow) {
return (index.column() == 0) ? m_sectionProperties[m_sections[index.row()]].first
: QVariant();
} else {
int sectionIndex = index.internalId() - RowType::PropertyRow;
const QString & sectionKey = m_sections[sectionIndex];
const QList<QString> & propertyList = m_sectionProperties[sectionKey].second;
return (index.column() == 0) ? m_properties[propertyList[index.row()]].first
: m_properties[propertyList[index.row()]].second;
}
}

41
metadatamodel.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef METADATAMODEL_H
#define METADATAMODEL_H
#include <QAbstractItemModel>
class MetadataModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit MetadataModel(QObject *parent = nullptr);
~MetadataModel();
void setFile(const QString & imageFilePath);
static QString imageSize(const QSize &size);
bool appendSection(const QString & sectionKey, const QString & sectionDisplayName);
bool appendProperty(const QString & sectionKey, const QString & propertyKey,
const QString & propertyDisplayName, const QString & propertyValue = QString());
bool updateProperty(const QString & propertyKey, const QString & propertyValue);
private:
enum RowType : quintptr {
SectionRow,
PropertyRow,
};
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex & = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
// [SECTION_KEY]
QList<QString> m_sections;
// {SECTION_KEY: (SECTION_DISPLAY_NAME, [PROPERTY_KEY])}
QMap<QString, QPair<QString, QList<QString> > > m_sectionProperties;
// {PROPERTY_KEY: (PROPERTY_DISPLAY_NAME, PROPERTY_VALUE)}
QMap<QString, QPair<QString, QString> > m_properties;
};
#endif // METADATAMODEL_H

View File

@ -1,9 +1,3 @@
#-------------------------------------------------
#
# Project created by QtCreator 2019-09-26T23:36:07
#
#-------------------------------------------------
QT += core widgets gui svg
TARGET = ppic
@ -24,8 +18,8 @@ CONFIG += c++11 lrelease embed_translations
SOURCES += \
aboutdialog.cpp \
main.cpp \
mainwindow.cpp \
main.cpp \
mainwindow.cpp \
graphicsview.cpp \
bottombuttongroup.cpp \
graphicsscene.cpp \
@ -33,11 +27,13 @@ SOURCES += \
opacityhelper.cpp \
toolbutton.cpp \
settings.cpp \
settingsdialog.cpp
settingsdialog.cpp \
metadatamodel.cpp \
metadatadialog.cpp
HEADERS += \
aboutdialog.h \
mainwindow.h \
mainwindow.h \
graphicsview.h \
bottombuttongroup.h \
graphicsscene.h \
@ -45,7 +41,9 @@ HEADERS += \
opacityhelper.h \
toolbutton.h \
settings.h \
settingsdialog.h
settingsdialog.h \
metadatamodel.h \
metadatadialog.h
TRANSLATIONS = \
languages/PineapplePictures.ts \