Compare commits
5 Commits
wip-proper
...
property-d
Author | SHA1 | Date | |
---|---|---|---|
cf95436aa9 | |||
0a9ea1982b | |||
0dfbb45238 | |||
7e7825760a | |||
203274a522 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
# User files
|
||||
*.user
|
||||
*.user.*
|
||||
|
||||
# Translation files
|
||||
*.qm
|
||||
|
@ -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
|
||||
|
@ -33,7 +33,7 @@ BottomButtonGroup::BottomButtonGroup(QWidget *parent)
|
||||
QPushButton * btn = new QPushButton(QIcon(QStringLiteral(":/icons/") + text), "");
|
||||
btn->setIconSize(QSize(40, 40));
|
||||
btn->setFixedSize(40, 40);
|
||||
connect(btn, &QAbstractButton::clicked, btn, func);
|
||||
QObject::connect(btn, &QAbstractButton::clicked, btn, func);
|
||||
return btn;
|
||||
};
|
||||
addButton(newBtn("zoom-original", [this]() {
|
||||
|
@ -2,7 +2,7 @@
|
||||
<component type="desktop-application">
|
||||
<id>net.blumia.pineapple-pictures</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-3.0+</project_license>
|
||||
<project_license>MIT</project_license>
|
||||
<name>Pineapple Pictures</name>
|
||||
<name xml:lang="zh-CN">菠萝看图</name>
|
||||
<summary>Image Viewer</summary>
|
||||
|
1956
icons/app-icon.svg
1956
icons/app-icon.svg
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 44 KiB |
@ -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>&Copy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="429"/>
|
||||
<location filename="../mainwindow.cpp" line="438"/>
|
||||
<source>Copy P&ixmap</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="434"/>
|
||||
<location filename="../mainwindow.cpp" line="443"/>
|
||||
<source>Copy &File Path</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="444"/>
|
||||
<location filename="../mainwindow.cpp" line="453"/>
|
||||
<source>&Paste Image</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="450"/>
|
||||
<location filename="../mainwindow.cpp" line="459"/>
|
||||
<source>&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>
|
||||
|
@ -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>&Copy</source>
|
||||
<translation>复制(&C)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="429"/>
|
||||
<location filename="../mainwindow.cpp" line="438"/>
|
||||
<source>Copy P&ixmap</source>
|
||||
<translation>复制位图(&I)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="434"/>
|
||||
<location filename="../mainwindow.cpp" line="443"/>
|
||||
<source>Copy &File Path</source>
|
||||
<translation>复制文件路径(&F)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="444"/>
|
||||
<location filename="../mainwindow.cpp" line="453"/>
|
||||
<source>&Paste Image</source>
|
||||
<translation>粘贴图像(&P)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="450"/>
|
||||
<location filename="../mainwindow.cpp" line="459"/>
|
||||
<source>&Paste Image File</source>
|
||||
<translation>粘贴图像文件(&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>
|
||||
|
@ -8,8 +8,8 @@
|
||||
#include "graphicsscene.h"
|
||||
#include "settingsdialog.h"
|
||||
#include "aboutdialog.h"
|
||||
#include "metadatadialog.h"
|
||||
#include "metadatamodel.h"
|
||||
#include "metadatadialog.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QMovie>
|
||||
@ -24,6 +24,7 @@
|
||||
#include <QCollator>
|
||||
#include <QClipboard>
|
||||
#include <QMimeData>
|
||||
#include <QWindow>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
@ -341,7 +342,13 @@ void MainWindow::mousePressEvent(QMouseEvent *event)
|
||||
void MainWindow::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->buttons() & Qt::LeftButton && m_clickedOnWindow && !isMaximized()) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
if (!window()->windowHandle()->startSystemMove()) {
|
||||
move(event->globalPos() - m_oldMousePos);
|
||||
}
|
||||
#else
|
||||
move(event->globalPos() - m_oldMousePos);
|
||||
#endif // QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
event->accept();
|
||||
}
|
||||
|
||||
|
81
metadata.cpp
81
metadata.cpp
@ -1,81 +0,0 @@
|
||||
#include "metadata.h"
|
||||
|
||||
Section::Section()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Section::~Section()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Warning! this method won't copy anything from the given argument!
|
||||
// we actually doesn't care about this, but since QList and QMap are not movable
|
||||
// so there won't be a (not ill-formed) default ctor to use and we won't get a
|
||||
// proper copy ctor, thus the operator= will be deleted.
|
||||
// When accessing QMap value if not exist, we just use this to create a new Section.
|
||||
Section & Section::operator=(const Section &)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
int Section::count() const
|
||||
{
|
||||
return m_propertiesValueMap.count();
|
||||
}
|
||||
|
||||
void Section::setSectionName(const QString &displayName)
|
||||
{
|
||||
m_displayName = displayName;
|
||||
}
|
||||
|
||||
void Section::setValue(PropertyType type, const QString &value)
|
||||
{
|
||||
if (!m_propertiesValueMap.contains(type)) {
|
||||
m_propertyIndexes.append(type);
|
||||
}
|
||||
|
||||
m_propertiesValueMap[type] = value;
|
||||
}
|
||||
|
||||
QString Section::valueAt(int index) const
|
||||
{
|
||||
Q_ASSERT(index >= 0 && index < m_propertyIndexes.count());
|
||||
|
||||
return m_propertiesValueMap[m_propertyIndexes[index]];
|
||||
}
|
||||
|
||||
QString Section::value(Section::PropertyType type) const
|
||||
{
|
||||
return m_propertiesValueMap.value(type, tr("Unknown"));
|
||||
}
|
||||
|
||||
QString Section::propertyName(PropertyType type) const
|
||||
{
|
||||
return m_propertiesOverrideDisplayNameMap.value(
|
||||
type,
|
||||
m_builtinPropDisplayNameMap.value(type, tr("Unknown"))
|
||||
);
|
||||
}
|
||||
|
||||
Metadata::Metadata()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Metadata::~Metadata()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Metadata::setSectionName(SectionType type, const QString &displayName)
|
||||
{
|
||||
m_sections[type].setSectionName(displayName);
|
||||
}
|
||||
|
||||
void Metadata::setPropertyValue(Metadata::SectionType type, Section::PropertyType propType, QString value)
|
||||
{
|
||||
m_sections[type].setValue(propType, value);
|
||||
}
|
||||
|
66
metadata.h
66
metadata.h
@ -1,66 +0,0 @@
|
||||
#ifndef METADATA_H
|
||||
#define METADATA_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
#include <QCoreApplication>
|
||||
|
||||
class Section
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Section)
|
||||
public:
|
||||
Section();
|
||||
~Section();
|
||||
Section & operator=(const Section& other);
|
||||
|
||||
// TODO: maybe use QString instead of a enum? different section won't share a same
|
||||
// enum value in any way...
|
||||
enum PropertyType : int {
|
||||
NameProp,
|
||||
FileSizeProp,
|
||||
LastModifiedProp,
|
||||
ImageSizeProp,
|
||||
};
|
||||
|
||||
int count() const;
|
||||
void setSectionName(const QString & displayName);
|
||||
void setValue(PropertyType type, const QString & value);
|
||||
QString value(PropertyType type) const;
|
||||
QString valueAt(int index) const;
|
||||
QString propertyName(PropertyType type) const;
|
||||
|
||||
private:
|
||||
QString m_displayName;
|
||||
QList<PropertyType> m_propertyIndexes;
|
||||
QMap<PropertyType, QString> m_propertiesValueMap;
|
||||
QMap<PropertyType, QString> m_propertiesOverrideDisplayNameMap;
|
||||
|
||||
const QMap<PropertyType, QString> m_builtinPropDisplayNameMap {
|
||||
{NameProp, tr("Name")},
|
||||
{FileSizeProp, tr("File Size")},
|
||||
{LastModifiedProp, tr("Last Modified")},
|
||||
{ImageSizeProp, tr("Image Size")},
|
||||
};
|
||||
};
|
||||
|
||||
class Metadata
|
||||
{
|
||||
public:
|
||||
enum SectionType : int {
|
||||
GeneralSection,
|
||||
ExifSection,
|
||||
};
|
||||
|
||||
Metadata();
|
||||
~Metadata();
|
||||
|
||||
private:
|
||||
QList<SectionType> m_sectionIndexes;
|
||||
QMap<SectionType, Section> m_sections;
|
||||
|
||||
void setSectionName(SectionType type, const QString & displayName);
|
||||
void setPropertyValue(SectionType type, Section::PropertyType propType, QString value);
|
||||
|
||||
};
|
||||
|
||||
#endif // METADATA_H
|
@ -10,7 +10,7 @@ MetadataDialog::MetadataDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, m_treeView(new QTreeView(this))
|
||||
{
|
||||
// m_treeView->setRootIsDecorated(false);
|
||||
m_treeView->setRootIsDecorated(false);
|
||||
m_treeView->setIndentation(0);
|
||||
|
||||
setWindowTitle(tr("Image Metadata"));
|
||||
|
@ -1,137 +1,44 @@
|
||||
#include "metadatamodel.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QLocale>
|
||||
#include <QSize>
|
||||
#include <QFileInfo>
|
||||
#include <QImageReader>
|
||||
|
||||
// This model is very similar to imagemetainfomodel.cpp in
|
||||
// Gwenview, since We don't care about ABI here and we won't
|
||||
// have any KDE lib as dept (KIO is a tier 3 framework from
|
||||
// KDE for example) which might cause this project no longer
|
||||
// tiny and easy to maintain, I'll just create a simpler
|
||||
// implementation than do a simple copy-paste...
|
||||
|
||||
enum Sections : int {
|
||||
GeneralSection,
|
||||
ExifSection,
|
||||
CustomSection = 61,
|
||||
};
|
||||
|
||||
class MetadataSection
|
||||
MetadataModel::MetadataModel(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
public:
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
// key: for internal indexing.
|
||||
// label: display name of the key.
|
||||
Entry(const QString & key, const QString & label, const QString & value)
|
||||
: m_key(key)
|
||||
, m_label(label.trimmed())
|
||||
, m_value(value.trimmed())
|
||||
{}
|
||||
|
||||
QString m_key;
|
||||
QString m_label;
|
||||
QString m_value;
|
||||
};
|
||||
|
||||
MetadataSection(const QString & sectionName)
|
||||
: m_sectionName(sectionName)
|
||||
{}
|
||||
|
||||
~MetadataSection()
|
||||
{
|
||||
qDeleteAll(m_entries);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
qDeleteAll(m_entries);
|
||||
m_entries.clear();
|
||||
}
|
||||
|
||||
void addEnrty(const QString & key, const QString & label, const QString & value = QString())
|
||||
{
|
||||
Entry * e = new Entry(key, label, value);
|
||||
m_entries << e;
|
||||
m_keyEntryMap[e->m_key] = m_entries.size() - 1;
|
||||
}
|
||||
|
||||
QString keyAt(int index) const
|
||||
{
|
||||
Q_ASSERT(index < m_entries.size());
|
||||
return m_entries[index]->m_key;
|
||||
}
|
||||
|
||||
QString valueAt(int index) const
|
||||
{
|
||||
Q_ASSERT(index < m_entries.size());
|
||||
return m_entries[index]->m_value;
|
||||
}
|
||||
|
||||
void setValueAt(int index, const QString & value)
|
||||
{
|
||||
Q_ASSERT(index < m_entries.size());
|
||||
m_entries[index]->m_value = value;
|
||||
}
|
||||
|
||||
QString labelAt(int index) const
|
||||
{
|
||||
Q_ASSERT(index < m_entries.size());
|
||||
return m_entries[index]->m_label;
|
||||
}
|
||||
|
||||
int keyIndex(const QString & key) {
|
||||
return m_keyEntryMap.value(key, -1);
|
||||
}
|
||||
|
||||
QString sectionName() const
|
||||
{
|
||||
return m_sectionName;
|
||||
}
|
||||
|
||||
int size() const
|
||||
{
|
||||
return m_entries.size();
|
||||
}
|
||||
|
||||
private:
|
||||
QList<Entry*> m_entries;
|
||||
QHash<QString, int> m_keyEntryMap;
|
||||
QString m_sectionName;
|
||||
};
|
||||
|
||||
MetadataModel::MetadataModel()
|
||||
{
|
||||
sectionRegister(GeneralSection, new MetadataSection(tr("General", "General info about the image, section name in metadata dialog")));
|
||||
|
||||
initGeneralSection();
|
||||
}
|
||||
|
||||
MetadataModel::~MetadataModel()
|
||||
{
|
||||
qDeleteAll(m_sections);
|
||||
|
||||
}
|
||||
|
||||
void MetadataModel::setFile(const QString &path)
|
||||
void MetadataModel::setFile(const QString &imageFilePath)
|
||||
{
|
||||
QFileInfo fileInfo(path);
|
||||
const QString sizeString = QLocale().formattedDataSize(fileInfo.size());
|
||||
const QString timeString = QLocale().toString(fileInfo.lastModified(), QLocale::LongFormat);
|
||||
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);
|
||||
|
||||
// FIXME: this implementation is very dirty!
|
||||
QImageReader imgReader(path);
|
||||
setImageSize(imgReader.size());
|
||||
const QString & sizeString = QLocale().formattedDataSize(fileInfo.size());
|
||||
const QString & timeString = QLocale().toString(fileInfo.lastModified(), QLocale::LongFormat);
|
||||
const QString & imageSizeString = imageSize(imgReader.size());
|
||||
|
||||
setSectionEntryValue(GeneralSection, QStringLiteral("General.Name"), fileInfo.fileName());
|
||||
setSectionEntryValue(GeneralSection, QStringLiteral("General.Size"), sizeString);
|
||||
setSectionEntryValue(GeneralSection, QStringLiteral("General.Time"), timeString);
|
||||
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);
|
||||
}
|
||||
|
||||
void MetadataModel::setImageSize(const QSize &size)
|
||||
QString MetadataModel::imageSize(const QSize &size)
|
||||
{
|
||||
QString imageSize;
|
||||
|
||||
@ -141,55 +48,91 @@ void MetadataModel::setImageSize(const QSize &size)
|
||||
imageSize = QLatin1Char('-');
|
||||
}
|
||||
|
||||
setSectionEntryValue(GeneralSection, QStringLiteral("General.ImageSize"), imageSize);
|
||||
return imageSize;
|
||||
}
|
||||
|
||||
QModelIndex MetadataModel::index(int row, int col, const QModelIndex &parent) const
|
||||
bool MetadataModel::appendSection(const QString §ionKey, const QString §ionDisplayName)
|
||||
{
|
||||
if (col < 0 || col > 1) {
|
||||
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 §ionKey, 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()) {
|
||||
// This is a group
|
||||
if (row < 0 || row >= m_sections.size()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
return createIndex(row, col, col == 0 ? 2 : 3); // ????????
|
||||
return createIndex(row, column, RowType::SectionRow);
|
||||
} else {
|
||||
// This is an entry
|
||||
int group = parent.row();
|
||||
if (row < 0 || row >= m_sections[group]->size()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
return createIndex(row, col, static_cast<quintptr>(group));
|
||||
// internalid param: row means nth section it belongs to.
|
||||
return createIndex(row, column, RowType::PropertyRow + parent.row());
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex MetadataModel::parent(const QModelIndex & index) const
|
||||
QModelIndex MetadataModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
if (!index.isValid()) {
|
||||
if (!child.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
if (index.internalId() == 2 || index.internalId() == 3) {
|
||||
|
||||
if (child.internalId() == RowType::SectionRow) {
|
||||
return QModelIndex();
|
||||
} else {
|
||||
return createIndex(static_cast<int>(index.internalId()), 0, 2);
|
||||
return createIndex(child.internalId() - RowType::PropertyRow, 0, SectionRow);
|
||||
}
|
||||
}
|
||||
|
||||
int MetadataModel::rowCount(const QModelIndex & parent) const
|
||||
int MetadataModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!parent.isValid()) {
|
||||
return m_sections.size();
|
||||
} else if (parent.internalId() == 2) {
|
||||
return m_sections[parent.row()]->size();
|
||||
} else {
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -199,69 +142,18 @@ QVariant MetadataModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return displayData(index);
|
||||
default:
|
||||
if (role != Qt::DisplayRole) {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void MetadataModel::initGeneralSection()
|
||||
{
|
||||
MetadataSection * s = section(GeneralSection);
|
||||
|
||||
s->addEnrty(QStringLiteral("General.Name"), tr("File Name"));
|
||||
s->addEnrty(QStringLiteral("General.Size"), tr("File Size"));
|
||||
s->addEnrty(QStringLiteral("General.Time"), tr("Last Modified"));
|
||||
s->addEnrty(QStringLiteral("General.ImageSize"), tr("Image Size"));
|
||||
}
|
||||
|
||||
bool MetadataModel::sectionRegister(Sections sectionType, MetadataSection *section)
|
||||
{
|
||||
if (m_sectionEnumIndexMap.contains(sectionType)) {
|
||||
return false;
|
||||
}
|
||||
m_sections.append(section);
|
||||
m_sectionEnumIndexMap[sectionType] = section;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MetadataModel::setSectionEntryValue(Sections sectionType, const QString &key, const QString &value)
|
||||
{
|
||||
MetadataSection * s = section(sectionType);
|
||||
int entryIndex = s->keyIndex(key);
|
||||
if (entryIndex < 0) {
|
||||
// no such entry
|
||||
return;
|
||||
}
|
||||
s->setValueAt(entryIndex, value);
|
||||
}
|
||||
|
||||
MetadataSection *MetadataModel::section(Sections sectionType)
|
||||
{
|
||||
return m_sectionEnumIndexMap[sectionType];
|
||||
}
|
||||
|
||||
QVariant MetadataModel::displayData(const QModelIndex &index) const
|
||||
{
|
||||
if (index.internalId() == 2) {
|
||||
if (index.column() != 0) {
|
||||
return QVariant();
|
||||
}
|
||||
QString label = m_sections[index.row()]->sectionName();
|
||||
return QVariant(label);
|
||||
}
|
||||
|
||||
if (index.internalId() == 3) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
MetadataSection* group = m_sections[index.internalId()];
|
||||
if (index.column() == 0) {
|
||||
return group->labelAt(index.row());
|
||||
if (index.internalId() == RowType::SectionRow) {
|
||||
return (index.column() == 0) ? m_sectionProperties[m_sections[index.row()]].first
|
||||
: QVariant();
|
||||
} else {
|
||||
return group->valueAt(index.row());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +1,41 @@
|
||||
#ifndef METADATAMODEL_H
|
||||
#define METADATAMODEL_H
|
||||
|
||||
#include <QVector>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
enum Sections : int;
|
||||
class MetadataSection;
|
||||
class MetadataModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MetadataModel();
|
||||
~MetadataModel() override;
|
||||
explicit MetadataModel(QObject *parent = nullptr);
|
||||
~MetadataModel();
|
||||
|
||||
void setFile(const QString & url);
|
||||
void setImageSize(const QSize & size);
|
||||
|
||||
QModelIndex index(int row, int col, const QModelIndex& parent = QModelIndex()) const override;
|
||||
QModelIndex parent(const QModelIndex & index) 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;
|
||||
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:
|
||||
QList<MetadataSection *> m_sections; // associated pointers free at destructor function.
|
||||
QMap<Sections, MetadataSection *> m_sectionEnumIndexMap; // pointer shared with m_sections
|
||||
enum RowType : quintptr {
|
||||
SectionRow,
|
||||
PropertyRow,
|
||||
};
|
||||
|
||||
void initGeneralSection();
|
||||
bool sectionRegister(Sections sectionType, MetadataSection * section);
|
||||
void setSectionEntryValue(Sections sectionType, const QString & key, const QString & value);
|
||||
MetadataSection * section(Sections sectionType);
|
||||
QVariant displayData(const QModelIndex & index) const;
|
||||
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
|
||||
|
@ -1,9 +1,3 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2019-09-26T23:36:07
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core widgets gui svg
|
||||
|
||||
TARGET = ppic
|
||||
@ -24,34 +18,32 @@ CONFIG += c++11 lrelease embed_translations
|
||||
|
||||
SOURCES += \
|
||||
aboutdialog.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
graphicsview.cpp \
|
||||
bottombuttongroup.cpp \
|
||||
graphicsscene.cpp \
|
||||
metadata.cpp \
|
||||
metadatadialog.cpp \
|
||||
metadatamodel.cpp \
|
||||
navigatorview.cpp \
|
||||
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 \
|
||||
metadata.h \
|
||||
metadatadialog.h \
|
||||
metadatamodel.h \
|
||||
navigatorview.h \
|
||||
opacityhelper.h \
|
||||
toolbutton.h \
|
||||
settings.h \
|
||||
settingsdialog.h
|
||||
settingsdialog.h \
|
||||
metadatamodel.h \
|
||||
metadatadialog.h
|
||||
|
||||
TRANSLATIONS = \
|
||||
languages/PineapplePictures.ts \
|
||||
|
Reference in New Issue
Block a user