Compare commits

..
Author SHA1 Message Date
Gary Wang 83246f04ae WIP: properties dialog 2020-10-13 00:28:03 +08:00
38 changed files with 1233 additions and 2378 deletions

No files matched your search

-1
View File
@@ -1,6 +1,5 @@
# User files # User files
*.user *.user
*.user.*
# Translation files # Translation files
*.qm *.qm
+22 -26
View File
@@ -12,34 +12,30 @@ set (QT_MINIMUM_VERSION "5.10")
find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Widgets Svg LinguistTools) find_package(Qt5 ${QT_MINIMUM_VERSION} CONFIG REQUIRED Widgets Svg LinguistTools)
set (PPIC_CPP_FILES set (PPIC_CPP_FILES
app/main.cpp main.cpp
app/mainwindow.cpp mainwindow.cpp
app/graphicsview.cpp graphicsview.cpp
app/graphicsscene.cpp graphicsscene.cpp
app/bottombuttongroup.cpp bottombuttongroup.cpp
app/navigatorview.cpp navigatorview.cpp
app/opacityhelper.cpp opacityhelper.cpp
app/toolbutton.cpp toolbutton.cpp
app/settings.cpp settings.cpp
app/settingsdialog.cpp settingsdialog.cpp
app/aboutdialog.cpp aboutdialog.cpp
app/metadatamodel.cpp
app/metadatadialog.cpp
) )
set (PPIC_HEADER_FILES set (PPIC_HEADER_FILES
app/mainwindow.h mainwindow.h
app/graphicsview.h graphicsview.h
app/graphicsscene.h graphicsscene.h
app/bottombuttongroup.h bottombuttongroup.h
app/navigatorview.h navigatorview.h
app/opacityhelper.h opacityhelper.h
app/toolbutton.h toolbutton.h
app/settings.h settings.h
app/settingsdialog.h settingsdialog.h
app/aboutdialog.h aboutdialog.h
app/metadatamodel.h
app/metadatadialog.h
) )
set (PPIC_QRC_FILES set (PPIC_QRC_FILES
@@ -53,7 +49,7 @@ set (PPIC_RC_FILES
set (EXE_NAME ppic) set (EXE_NAME ppic)
# Translation # Translation
file (GLOB PPIC_TS_FILES translations/*.ts) file (GLOB PPIC_TS_FILES languages/*.ts)
set (PPIC_CPP_FILES_FOR_I18N ${PPIC_CPP_FILES}) set (PPIC_CPP_FILES_FOR_I18N ${PPIC_CPP_FILES})
qt5_create_translation(PPIC_QM_FILES ${PPIC_CPP_FILES_FOR_I18N} ${PPIC_TS_FILES}) qt5_create_translation(PPIC_QM_FILES ${PPIC_CPP_FILES_FOR_I18N} ${PPIC_TS_FILES})
File renamed without changes.
View File
File renamed without changes.
-101
View File
@@ -1,101 +0,0 @@
#include "metadatadialog.h"
#include <QDialogButtonBox>
#include <QPainter>
#include <QStyledItemDelegate>
#include <QTreeView>
#include <QVBoxLayout>
#include <QHeaderView>
#include "metadatamodel.h"
class PropertyTreeView : public QTreeView
{
public:
explicit PropertyTreeView(QWidget* parent) : QTreeView(parent) {}
~PropertyTreeView() {}
protected:
void rowsInserted(const QModelIndex& parent, int start, int end) override
{
QTreeView::rowsInserted(parent, start, end);
if (!parent.isValid()) {
for (int row = start; row <= end; ++row) {
setupSection(row);
}
}
}
void reset() override
{
QTreeView::reset();
if (model()) {
for (int row = 0; row < model()->rowCount(); ++row) {
setupSection(row);
}
}
}
private:
void setupSection(int row)
{
expand(model()->index(row, 0));
setFirstColumnSpanned(row, QModelIndex(), true);
}
};
class PropertyTreeItemDelegate : public QStyledItemDelegate
{
public:
PropertyTreeItemDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{}
protected:
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
{
QStyleOptionViewItem opt = option;
if (!index.parent().isValid()) {
opt.font.setBold(true);
opt.features.setFlag(QStyleOptionViewItem::Alternate);
}
QStyledItemDelegate::paint(painter, opt, index);
}
};
MetadataDialog::MetadataDialog(QWidget *parent)
: QDialog(parent)
, m_treeView(new PropertyTreeView(this))
{
m_treeView->setRootIsDecorated(false);
m_treeView->setIndentation(0);
m_treeView->setItemDelegate(new PropertyTreeItemDelegate(m_treeView));
m_treeView->header()->resizeSection(0, sizeHint().width() / 2);
setWindowTitle(tr("Image Metadata"));
QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
setLayout(new QVBoxLayout);
layout()->addWidget(m_treeView);
layout()->addWidget(buttonBox);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::close);
setWindowFlag(Qt::WindowContextHelpButtonHint, false);
}
MetadataDialog::~MetadataDialog()
{
}
void MetadataDialog::setMetadataModel(MetadataModel * model)
{
m_treeView->setModel(model);
}
QSize MetadataDialog::sizeHint() const
{
return QSize(520, 350);
}
-205
View File
@@ -1,205 +0,0 @@
#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);
imgReader.setAutoTransform(true);
imgReader.setDecideFormatFromContent(true);
const QString & itemTypeString = tr("%1 File").arg(QString(imgReader.format().toUpper()));
const QString & sizeString = QLocale().formattedDataSize(fileInfo.size());
const QString & birthTimeString = QLocale().toString(fileInfo.birthTime(), QLocale::LongFormat);
const QString & lastModifiedTimeString = QLocale().toString(fileInfo.lastModified(), QLocale::LongFormat);
const QString & imageDimensionsString = imageSize(imgReader.size());
const QString & imageRatioString = imageSizeRatio(imgReader.size());
#if 0
appendSection(QStringLiteral("Description"), tr("Description", "Section name."));
appendSection(QStringLiteral("Origin"), tr("Origin", "Section name."));
#endif // 0
appendSection(QStringLiteral("Image"), tr("Image", "Section name."));
#if 0
appendSection(QStringLiteral("Camera"), tr("Camera", "Section name."));
appendSection(QStringLiteral("AdvancedPhoto"), tr("Advanced photo", "Section name."));
appendSection(QStringLiteral("GPS"), tr("GPS", "Section name."));
#endif // 0
appendSection(QStringLiteral("File"), tr("File", "Section name."));
appendProperty(QStringLiteral("Image"), QStringLiteral("Image.Dimensions"),
tr("Dimensions"), imageDimensionsString);
appendProperty(QStringLiteral("Image"), QStringLiteral("Image.SizeRatio"),
tr("Aspect Ratio"), imageRatioString);
appendProperty(QStringLiteral("File"), QStringLiteral("File.Name"),
tr("Name"), fileInfo.fileName());
appendProperty(QStringLiteral("File"), QStringLiteral("File.ItemType"),
tr("Item type"), itemTypeString);
appendProperty(QStringLiteral("File"), QStringLiteral("File.Path"),
tr("Folder path"), fileInfo.path());
appendProperty(QStringLiteral("File"), QStringLiteral("File.Size"),
tr("Size"), sizeString);
appendProperty(QStringLiteral("File"), QStringLiteral("File.CreatedTime"),
tr("Date Created"), birthTimeString);
appendProperty(QStringLiteral("File"), QStringLiteral("File.LastModified"),
tr("Date Modified"), lastModifiedTimeString);
}
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;
}
int simplegcd(int a, int b) {
return b == 0 ? a : simplegcd(b, a % b);
}
QString MetadataModel::imageSizeRatio(const QSize &size)
{
if (!size.isValid()) {
return QStringLiteral("-");
}
int gcd = simplegcd(size.width(), size.height());
return tr("%1 : %2").arg(QString::number(size.width() / gcd), QString::number(size.height() / gcd));
}
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;
}
}
QVariant MetadataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical || role != Qt::DisplayRole) {
return QVariant();
}
return section == 0 ? tr("Property") : tr("Value");
}
-43
View File
@@ -1,43 +0,0 @@
#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);
static QString imageSizeRatio(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;
QVariant headerData(int section, Qt::Orientation orientation, 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
@@ -33,7 +33,7 @@ BottomButtonGroup::BottomButtonGroup(QWidget *parent)
QPushButton * btn = new QPushButton(QIcon(QStringLiteral(":/icons/") + text), ""); QPushButton * btn = new QPushButton(QIcon(QStringLiteral(":/icons/") + text), "");
btn->setIconSize(QSize(40, 40)); btn->setIconSize(QSize(40, 40));
btn->setFixedSize(40, 40); btn->setFixedSize(40, 40);
QObject::connect(btn, &QAbstractButton::clicked, btn, func); connect(btn, &QAbstractButton::clicked, btn, func);
return btn; return btn;
}; };
addButton(newBtn("zoom-original", [this]() { addButton(newBtn("zoom-original", [this]() {
File renamed without changes.
+1 -1
View File
@@ -2,7 +2,7 @@
<component type="desktop-application"> <component type="desktop-application">
<id>net.blumia.pineapple-pictures</id> <id>net.blumia.pineapple-pictures</id>
<metadata_license>CC0-1.0</metadata_license> <metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license> <project_license>GPL-3.0+</project_license>
<name>Pineapple Pictures</name> <name>Pineapple Pictures</name>
<name xml:lang="zh-CN">菠萝看图</name> <name xml:lang="zh-CN">菠萝看图</name>
<summary>Image Viewer</summary> <summary>Image Viewer</summary>
File renamed without changes.
File renamed without changes.
+1 -8
View File
@@ -51,15 +51,8 @@ void GraphicsView::showFileFromUrl(const QUrl &url, bool doRequestGallery)
// QImage::Format imageFormat = imageReader.imageFormat(); // QImage::Format imageFormat = imageReader.imageFormat();
if (imageReader.format().isEmpty()) { if (imageReader.format().isEmpty()) {
showText(tr("File is not a valid image")); showText(tr("File is not a valid image"));
} else if (!imageReader.supportsAnimation() && !imageReader.canRead()) {
showText(tr("Image data is invalid or currently unsupported"));
} else { } else {
const QPixmap & pixmap = QPixmap::fromImageReader(&imageReader); showImage(QPixmap::fromImageReader(&imageReader));
if (pixmap.isNull()) {
showText(tr("Image data is invalid or currently unsupported"));
} else {
showImage(pixmap);
}
} }
} }
File renamed without changes.
+331 -1349
View File
File diff suppressed because it is too large. Load diff

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 40 KiB

+294
View File
@@ -0,0 +1,294 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>AboutDialog</name>
<message>
<location filename="../aboutdialog.cpp" line="22"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="25"/>
<source>Launch application with image file path as argument to load the file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="26"/>
<source>Drag and drop image file onto the window is also supported.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="27"/>
<source>Context menu option explanation:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="31"/>
<source>Make window stay on top of all other windows.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="35"/>
<source>Avoid close window accidentally. (eg. by double clicking the window)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="44"/>
<source>Version: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="47"/>
<source>Copyright (c) 2020 %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="49"/>
<source>Logo designed by %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="51"/>
<source>Built with Qt %1 (%2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="52"/>
<source>Source code</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="58"/>
<source>Contributors</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="60"/>
<source>List of contributors on GitHub</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="61"/>
<source>Thanks to all people who contributed to this project.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="65"/>
<source>Translators</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="66"/>
<source>I would like to thank the following people who volunteered to translate this application.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="131"/>
<source>&amp;Special Thanks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="133"/>
<source>&amp;Third-party Libraries</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="72"/>
<source>Your Rights</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="74"/>
<source>%1 is released under the MIT License.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="75"/>
<source>This license grants people a number of freedoms:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="76"/>
<source>You are free to use %1, for any purpose</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="77"/>
<source>You are free to distribute %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="78"/>
<source>You can study how %1 works and change it</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="79"/>
<source>You can distribute changed versions of %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="81"/>
<source>The MIT license guarantees you this freedom. Nobody is ever permitted to take it away.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="109"/>
<source>Third-party Libraries used by %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="110"/>
<source>%1 is built on the following free software libraries:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="129"/>
<source>&amp;Help</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="130"/>
<source>&amp;About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="132"/>
<source>&amp;License</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GraphicsScene</name>
<message>
<location filename="../graphicsscene.cpp" line="16"/>
<source>Drag image here</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GraphicsView</name>
<message>
<location filename="../graphicsview.cpp" line="254"/>
<source>File url list is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../graphicsview.cpp" line="53"/>
<source>File is not a valid image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../graphicsview.cpp" line="262"/>
<source>Image data is invalid</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../graphicsview.cpp" line="269"/>
<source>Not supported mimedata: %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../mainwindow.cpp" line="175"/>
<source>File url list is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="408"/>
<source>&amp;Copy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="429"/>
<source>Copy P&amp;ixmap</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="434"/>
<source>Copy &amp;File Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="444"/>
<source>&amp;Paste Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="450"/>
<source>&amp;Paste Image File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="30"/>
<location filename="../mainwindow.cpp" line="455"/>
<source>Stay on top</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../aboutdialog.cpp" line="34"/>
<location filename="../mainwindow.cpp" line="462"/>
<source>Protected mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="469"/>
<source>Configure...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../mainwindow.cpp" line="476"/>
<source>Help</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../settingsdialog.cpp" line="15"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog.cpp" line="20"/>
<source>Do nothing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog.cpp" line="21"/>
<source>Close the window</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog.cpp" line="22"/>
<source>Toggle maximize</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog.cpp" line="30"/>
<source>Stay on top when start-up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../settingsdialog.cpp" line="31"/>
<source>Double-click behavior</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../main.cpp" line="27"/>
<source>Pineapple Pictures</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../main.cpp" line="31"/>
<source>File list.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
@@ -4,157 +4,157 @@
<context> <context>
<name>AboutDialog</name> <name>AboutDialog</name>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="22"/> <location filename="../aboutdialog.cpp" line="22"/>
<source>About</source> <source>About</source>
<translation>关于</translation> <translation>关于</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="25"/> <location filename="../aboutdialog.cpp" line="25"/>
<source>Launch application with image file path as argument to load the file.</source> <source>Launch application with image file path as argument to load the file.</source>
<translation>以图片文件的路径作为参数运行程序即可直接打开图片文件。</translation> <translation>以图片文件的路径作为参数运行程序即可直接打开图片文件。</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="26"/> <location filename="../aboutdialog.cpp" line="26"/>
<source>Drag and drop image file onto the window is also supported.</source> <source>Drag and drop image file onto the window is also supported.</source>
<translation>也支持拖放图片文件到窗口内来加载图片。</translation> <translation>也支持拖放图片文件到窗口内来加载图片。</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="27"/> <location filename="../aboutdialog.cpp" line="27"/>
<source>Context menu option explanation:</source> <source>Context menu option explanation:</source>
<translation>菜单项说明:</translation> <translation>菜单项说明:</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="31"/> <location filename="../aboutdialog.cpp" line="31"/>
<source>Make window stay on top of all other windows.</source> <source>Make window stay on top of all other windows.</source>
<translation>使窗口始终至于其它非置顶窗口上方。</translation> <translation>使窗口始终至于其它非置顶窗口上方。</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="35"/> <location filename="../aboutdialog.cpp" line="35"/>
<source>Avoid close window accidentally. (eg. by double clicking the window)</source> <source>Avoid close window accidentally. (eg. by double clicking the window)</source>
<translation>避免窗口意外关闭。(如:不小心双击了窗口触发了关闭窗口行为)</translation> <translation>避免窗口意外关闭。(如:不小心双击了窗口触发了关闭窗口行为)</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="44"/> <location filename="../aboutdialog.cpp" line="44"/>
<source>Version: %1</source> <source>Version: %1</source>
<translation>版本: %1</translation> <translation>版本: %1</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="47"/> <location filename="../aboutdialog.cpp" line="47"/>
<source>Copyright (c) 2020 %1</source> <source>Copyright (c) 2020 %1</source>
<translation>版权所有 (c) 2020 %1</translation> <translation>版权所有 (c) 2020 %1</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="49"/> <location filename="../aboutdialog.cpp" line="49"/>
<source>Logo designed by %1</source> <source>Logo designed by %1</source>
<translation>Logo 由 %1 设计</translation> <translation>Logo 由 %1 设计</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="51"/> <location filename="../aboutdialog.cpp" line="51"/>
<source>Built with Qt %1 (%2)</source> <source>Built with Qt %1 (%2)</source>
<translation>使用 Qt %1 (%2) 进行构建</translation> <translation>使用 Qt %1 (%2) 进行构建</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="52"/> <location filename="../aboutdialog.cpp" line="52"/>
<source>Source code</source> <source>Source code</source>
<translation>源代码</translation> <translation>源代码</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="58"/> <location filename="../aboutdialog.cpp" line="58"/>
<source>Contributors</source> <source>Contributors</source>
<translation>贡献者</translation> <translation>贡献者</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="60"/> <location filename="../aboutdialog.cpp" line="60"/>
<source>List of contributors on GitHub</source> <source>List of contributors on GitHub</source>
<translation>GitHub 上的贡献者列表</translation> <translation>GitHub 上的贡献者列表</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="61"/> <location filename="../aboutdialog.cpp" line="61"/>
<source>Thanks to all people who contributed to this project.</source> <source>Thanks to all people who contributed to this project.</source>
<translation>感谢所有参与此项目的朋友。</translation> <translation>感谢所有参与此项目的朋友。</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="65"/> <location filename="../aboutdialog.cpp" line="65"/>
<source>Translators</source> <source>Translators</source>
<translation>翻译者</translation> <translation>翻译者</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="66"/> <location filename="../aboutdialog.cpp" line="66"/>
<source>I would like to thank the following people who volunteered to translate this application.</source> <source>I would like to thank the following people who volunteered to translate this application.</source>
<translation>我想要感谢下列自愿参与翻译此应用程序的朋友。</translation> <translation>我想要感谢下列自愿参与翻译此应用程序的朋友。</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="131"/> <location filename="../aboutdialog.cpp" line="131"/>
<source>&amp;Special Thanks</source> <source>&amp;Special Thanks</source>
<translation>致谢(&amp;S)</translation> <translation>致谢(&amp;S)</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="133"/> <location filename="../aboutdialog.cpp" line="133"/>
<source>&amp;Third-party Libraries</source> <source>&amp;Third-party Libraries</source>
<translation>第三方程序库(&amp;T)</translation> <translation>第三方程序库(&amp;T)</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="72"/> <location filename="../aboutdialog.cpp" line="72"/>
<source>Your Rights</source> <source>Your Rights</source>
<translation>用户的权利</translation> <translation>用户的权利</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="74"/> <location filename="../aboutdialog.cpp" line="74"/>
<source>%1 is released under the MIT License.</source> <source>%1 is released under the MIT License.</source>
<translation>%1 是在 MIT 许可协议下发布的。</translation> <translation>%1 是在 MIT 许可协议下发布的。</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="75"/> <location filename="../aboutdialog.cpp" line="75"/>
<source>This license grants people a number of freedoms:</source> <source>This license grants people a number of freedoms:</source>
<translation>此许可证赋予人们以下自由的权利:</translation> <translation>此许可证赋予人们以下自由的权利:</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="76"/> <location filename="../aboutdialog.cpp" line="76"/>
<source>You are free to use %1, for any purpose</source> <source>You are free to use %1, for any purpose</source>
<translation>任何人都可以为了任何目的自由地使用 %1</translation> <translation>任何人都可以为了任何目的自由地使用 %1</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="77"/> <location filename="../aboutdialog.cpp" line="77"/>
<source>You are free to distribute %1</source> <source>You are free to distribute %1</source>
<translation>任何人都可以自由地分发 %1</translation> <translation>任何人都可以自由地分发 %1</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="78"/> <location filename="../aboutdialog.cpp" line="78"/>
<source>You can study how %1 works and change it</source> <source>You can study how %1 works and change it</source>
<translation>任何人都可以自由地研究 %1 的工作原理并对其进行修改</translation> <translation>任何人都可以自由地研究 %1 的工作原理并对其进行修改</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="79"/> <location filename="../aboutdialog.cpp" line="79"/>
<source>You can distribute changed versions of %1</source> <source>You can distribute changed versions of %1</source>
<translation>任何人都可以自由地分发修改过的 %1 版本</translation> <translation>任何人都可以自由地分发修改过的 %1 版本</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="81"/> <location filename="../aboutdialog.cpp" line="81"/>
<source>The MIT license guarantees you this freedom. Nobody is ever permitted to take it away.</source> <source>The MIT license guarantees you this freedom. Nobody is ever permitted to take it away.</source>
<translation>此软件通过 MIT 许可证赋予用户上述自由,任何人无权剥夺。</translation> <translation>此软件通过 MIT 许可证赋予用户上述自由,任何人无权剥夺。</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="109"/> <location filename="../aboutdialog.cpp" line="109"/>
<source>Third-party Libraries used by %1</source> <source>Third-party Libraries used by %1</source>
<translation>%1 使用的第三方程序库</translation> <translation>%1 使用的第三方程序库</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="110"/> <location filename="../aboutdialog.cpp" line="110"/>
<source>%1 is built on the following free software libraries:</source> <source>%1 is built on the following free software libraries:</source>
<translation>%1 采用了下列自由软件程序库进行构建:</translation> <translation>%1 采用了下列自由软件程序库进行构建:</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="129"/> <location filename="../aboutdialog.cpp" line="129"/>
<source>&amp;Help</source> <source>&amp;Help</source>
<translation>帮助(&amp;H)</translation> <translation>帮助(&amp;H)</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="130"/> <location filename="../aboutdialog.cpp" line="130"/>
<source>&amp;About</source> <source>&amp;About</source>
<translation>关于(&amp;A)</translation> <translation>关于(&amp;A)</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="132"/> <location filename="../aboutdialog.cpp" line="132"/>
<source>&amp;License</source> <source>&amp;License</source>
<translation>软件许可证(&amp;L)</translation> <translation>软件许可证(&amp;L)</translation>
</message> </message>
@@ -162,7 +162,7 @@
<context> <context>
<name>GraphicsScene</name> <name>GraphicsScene</name>
<message> <message>
<location filename="../app/graphicsscene.cpp" line="16"/> <location filename="../graphicsscene.cpp" line="16"/>
<source>Drag image here</source> <source>Drag image here</source>
<translation>拖放图片至此</translation> <translation>拖放图片至此</translation>
</message> </message>
@@ -170,28 +170,22 @@
<context> <context>
<name>GraphicsView</name> <name>GraphicsView</name>
<message> <message>
<location filename="../app/graphicsview.cpp" line="261"/> <location filename="../graphicsview.cpp" line="254"/>
<source>File url list is empty</source> <source>File url list is empty</source>
<translation>文件 URL 列表为空</translation> <translation>文件 URL 列表为空</translation>
</message> </message>
<message> <message>
<location filename="../app/graphicsview.cpp" line="53"/> <location filename="../graphicsview.cpp" line="53"/>
<source>File is not a valid image</source> <source>File is not a valid image</source>
<translation>文件不是有效的图片文件</translation> <translation>文件不是有效的图片文件</translation>
</message> </message>
<message> <message>
<location filename="../app/graphicsview.cpp" line="55"/> <location filename="../graphicsview.cpp" line="262"/>
<location filename="../app/graphicsview.cpp" line="59"/>
<source>Image data is invalid or currently unsupported</source>
<translation>图像数据无效或暂未支持</translation>
</message>
<message>
<location filename="../app/graphicsview.cpp" line="269"/>
<source>Image data is invalid</source> <source>Image data is invalid</source>
<translation>图片数据无效</translation> <translation>图片数据无效</translation>
</message> </message>
<message> <message>
<location filename="../app/graphicsview.cpp" line="276"/> <location filename="../graphicsview.cpp" line="269"/>
<source>Not supported mimedata: %1</source> <source>Not supported mimedata: %1</source>
<translation>不受支持的 MimeData 格式:%1</translation> <translation>不受支持的 MimeData 格式:%1</translation>
</message> </message>
@@ -199,210 +193,87 @@
<context> <context>
<name>MainWindow</name> <name>MainWindow</name>
<message> <message>
<location filename="../app/mainwindow.cpp" line="178"/> <location filename="../mainwindow.cpp" line="175"/>
<source>File url list is empty</source> <source>File url list is empty</source>
<translation>文件 URL 列表为空</translation> <translation>文件 URL 列表为空</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="417"/> <location filename="../mainwindow.cpp" line="408"/>
<source>&amp;Copy</source> <source>&amp;Copy</source>
<translation>复制(&amp;C)</translation> <translation>复制(&amp;C)</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="438"/> <location filename="../mainwindow.cpp" line="429"/>
<source>Copy P&amp;ixmap</source> <source>Copy P&amp;ixmap</source>
<translation>复制位图(&amp;I)</translation> <translation>复制位图(&amp;I)</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="443"/> <location filename="../mainwindow.cpp" line="434"/>
<source>Copy &amp;File Path</source> <source>Copy &amp;File Path</source>
<translation>复制文件路径(&amp;F)</translation> <translation>复制文件路径(&amp;F)</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="453"/> <location filename="../mainwindow.cpp" line="444"/>
<source>&amp;Paste Image</source> <source>&amp;Paste Image</source>
<translation>粘贴图像(&amp;P)</translation> <translation>粘贴图像(&amp;P)</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="459"/> <location filename="../mainwindow.cpp" line="450"/>
<source>&amp;Paste Image File</source> <source>&amp;Paste Image File</source>
<translation>粘贴图像文件(&amp;P)</translation> <translation>粘贴图像文件(&amp;P)</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="492"/> <location filename="../aboutdialog.cpp" line="30"/>
<source>Properties</source> <location filename="../mainwindow.cpp" line="455"/>
<translation>属性</translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="30"/>
<location filename="../app/mainwindow.cpp" line="464"/>
<source>Stay on top</source> <source>Stay on top</source>
<translation>总在最前</translation> <translation>总在最前</translation>
</message> </message>
<message> <message>
<location filename="../app/aboutdialog.cpp" line="34"/> <location filename="../aboutdialog.cpp" line="34"/>
<location filename="../app/mainwindow.cpp" line="471"/> <location filename="../mainwindow.cpp" line="462"/>
<source>Protected mode</source> <source>Protected mode</source>
<translation>保护模式</translation> <translation>保护模式</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="478"/> <location filename="../mainwindow.cpp" line="469"/>
<source>Configure...</source> <source>Configure...</source>
<translation>设置...</translation> <translation>设置...</translation>
</message> </message>
<message> <message>
<location filename="../app/mainwindow.cpp" line="485"/> <location filename="../mainwindow.cpp" line="476"/>
<source>Help</source> <source>Help</source>
<translation>帮助</translation> <translation>帮助</translation>
</message> </message>
</context> </context>
<context>
<name>MetadataDialog</name>
<message>
<location filename="../app/metadatadialog.cpp" line="75"/>
<source>Image Metadata</source>
<translation>图像元信息</translation>
</message>
</context>
<context>
<name>MetadataModel</name>
<message>
<location filename="../app/metadatamodel.cpp" line="36"/>
<source>Origin</source>
<comment>Section name.</comment>
<translation>来源</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="38"/>
<source>Image</source>
<comment>Section name.</comment>
<translation>图像</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="44"/>
<source>File</source>
<comment>Section name.</comment>
<translation>文件</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="40"/>
<source>Camera</source>
<comment>Section name.</comment>
<translation>照相机</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="27"/>
<source>%1 File</source>
<translation>%1 文件</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="35"/>
<source>Description</source>
<comment>Section name.</comment>
<translation>说明</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="41"/>
<source>Advanced photo</source>
<comment>Section name.</comment>
<translation>高级照片</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="42"/>
<source>GPS</source>
<comment>Section name.</comment>
<translation>GPS</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="47"/>
<source>Dimensions</source>
<translation>分辨率</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="49"/>
<source>Aspect Ratio</source>
<translation>纵横比</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="52"/>
<source>Name</source>
<translation>名称</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="54"/>
<source>Item type</source>
<translation>项目类型</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="56"/>
<source>Folder path</source>
<translation>文件夹路径</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="58"/>
<source>Size</source>
<translation>大小</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="60"/>
<source>Date Created</source>
<translation>创建日期</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="62"/>
<source>Date Modified</source>
<translation>修改日期</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="70"/>
<source>%1 x %2</source>
<translation>%1 x %2</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="88"/>
<source>%1 : %2</source>
<translation>%1 : %2</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="204"/>
<source>Property</source>
<translation>属性</translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="204"/>
<source>Value</source>
<translation>值</translation>
</message>
</context>
<context> <context>
<name>SettingsDialog</name> <name>SettingsDialog</name>
<message> <message>
<location filename="../app/settingsdialog.cpp" line="15"/> <location filename="../settingsdialog.cpp" line="15"/>
<source>Settings</source> <source>Settings</source>
<translation>设定</translation> <translation>设定</translation>
</message> </message>
<message> <message>
<location filename="../app/settingsdialog.cpp" line="20"/> <location filename="../settingsdialog.cpp" line="20"/>
<source>Do nothing</source> <source>Do nothing</source>
<translation>什么也不做</translation> <translation>什么也不做</translation>
</message> </message>
<message> <message>
<location filename="../app/settingsdialog.cpp" line="21"/> <location filename="../settingsdialog.cpp" line="21"/>
<source>Close the window</source> <source>Close the window</source>
<translation>关闭窗口</translation> <translation>关闭窗口</translation>
</message> </message>
<message> <message>
<location filename="../app/settingsdialog.cpp" line="22"/> <location filename="../settingsdialog.cpp" line="22"/>
<source>Toggle maximize</source> <source>Toggle maximize</source>
<translation>最大化窗口</translation> <translation>最大化窗口</translation>
</message> </message>
<message> <message>
<location filename="../app/settingsdialog.cpp" line="30"/> <location filename="../settingsdialog.cpp" line="30"/>
<source>Stay on top when start-up</source> <source>Stay on top when start-up</source>
<translation>启动时保持窗口总在最前</translation> <translation>启动时保持窗口总在最前</translation>
</message> </message>
<message> <message>
<location filename="../app/settingsdialog.cpp" line="31"/> <location filename="../settingsdialog.cpp" line="31"/>
<source>Double-click behavior</source> <source>Double-click behavior</source>
<translation>双击时的行为</translation> <translation>双击时的行为</translation>
</message> </message>
@@ -410,12 +281,12 @@
<context> <context>
<name>main</name> <name>main</name>
<message> <message>
<location filename="../app/main.cpp" line="27"/> <location filename="../main.cpp" line="27"/>
<source>Pineapple Pictures</source> <source>Pineapple Pictures</source>
<translation>菠萝看图</translation> <translation>菠萝看图</translation>
</message> </message>
<message> <message>
<location filename="../app/main.cpp" line="31"/> <location filename="../main.cpp" line="31"/>
<source>File list.</source> <source>File list.</source>
<translation>文件列表。</translation> <translation>文件列表。</translation>
</message> </message>
View File
File renamed without changes.
+1 -8
View File
@@ -8,8 +8,8 @@
#include "graphicsscene.h" #include "graphicsscene.h"
#include "settingsdialog.h" #include "settingsdialog.h"
#include "aboutdialog.h" #include "aboutdialog.h"
#include "metadatamodel.h"
#include "metadatadialog.h" #include "metadatadialog.h"
#include "metadatamodel.h"
#include <QMouseEvent> #include <QMouseEvent>
#include <QMovie> #include <QMovie>
@@ -24,7 +24,6 @@
#include <QCollator> #include <QCollator>
#include <QClipboard> #include <QClipboard>
#include <QMimeData> #include <QMimeData>
#include <QWindow>
#ifdef _WIN32 #ifdef _WIN32
#include <windows.h> #include <windows.h>
@@ -342,13 +341,7 @@ void MainWindow::mousePressEvent(QMouseEvent *event)
void MainWindow::mouseMoveEvent(QMouseEvent *event) void MainWindow::mouseMoveEvent(QMouseEvent *event)
{ {
if (event->buttons() & Qt::LeftButton && m_clickedOnWindow && !isMaximized()) { 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); move(event->globalPos() - m_oldMousePos);
}
#else
move(event->globalPos() - m_oldMousePos);
#endif // QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
event->accept(); event->accept();
} }
View File
File renamed without changes.
+81
View File
@@ -0,0 +1,81 @@
#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
View File
@@ -0,0 +1,66 @@
#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
+41
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);
}
File renamed without changes.
+267
View File
@@ -0,0 +1,267 @@
#include "metadatamodel.h"
#include <QFileInfo>
#include <QDateTime>
#include <QLocale>
#include <QSize>
#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
{
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)
{
QFileInfo fileInfo(path);
const QString sizeString = QLocale().formattedDataSize(fileInfo.size());
const QString timeString = QLocale().toString(fileInfo.lastModified(), QLocale::LongFormat);
// FIXME: this implementation is very dirty!
QImageReader imgReader(path);
setImageSize(imgReader.size());
setSectionEntryValue(GeneralSection, QStringLiteral("General.Name"), fileInfo.fileName());
setSectionEntryValue(GeneralSection, QStringLiteral("General.Size"), sizeString);
setSectionEntryValue(GeneralSection, QStringLiteral("General.Time"), timeString);
}
void MetadataModel::setImageSize(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('-');
}
setSectionEntryValue(GeneralSection, QStringLiteral("General.ImageSize"), imageSize);
}
QModelIndex MetadataModel::index(int row, int col, const QModelIndex &parent) const
{
if (col < 0 || col > 1) {
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); // ????????
} 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));
}
}
QModelIndex MetadataModel::parent(const QModelIndex & index) const
{
if (!index.isValid()) {
return QModelIndex();
}
if (index.internalId() == 2 || index.internalId() == 3) {
return QModelIndex();
} else {
return createIndex(static_cast<int>(index.internalId()), 0, 2);
}
}
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;
}
}
int MetadataModel::columnCount(const QModelIndex &) const
{
return 2;
}
QVariant MetadataModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}
switch (role) {
case Qt::DisplayRole:
return displayData(index);
default:
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());
} else {
return group->valueAt(index.row());
}
}
+36
View File
@@ -0,0 +1,36 @@
#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;
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;
private:
QList<MetadataSection *> m_sections; // associated pointers free at destructor function.
QMap<Sections, MetadataSection *> m_sectionEnumIndexMap; // pointer shared with m_sections
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;
};
#endif // METADATAMODEL_H
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+35 -27
View File
@@ -1,3 +1,9 @@
#-------------------------------------------------
#
# Project created by QtCreator 2019-09-26T23:36:07
#
#-------------------------------------------------
QT += core widgets gui svg QT += core widgets gui svg
TARGET = ppic TARGET = ppic
@@ -17,37 +23,39 @@ DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += c++11 lrelease embed_translations CONFIG += c++11 lrelease embed_translations
SOURCES += \ SOURCES += \
app/aboutdialog.cpp \ aboutdialog.cpp \
app/main.cpp \ main.cpp \
app/mainwindow.cpp \ mainwindow.cpp \
app/graphicsview.cpp \ graphicsview.cpp \
app/bottombuttongroup.cpp \ bottombuttongroup.cpp \
app/graphicsscene.cpp \ graphicsscene.cpp \
app/navigatorview.cpp \ metadata.cpp \
app/opacityhelper.cpp \ metadatadialog.cpp \
app/toolbutton.cpp \ metadatamodel.cpp \
app/settings.cpp \ navigatorview.cpp \
app/settingsdialog.cpp \ opacityhelper.cpp \
app/metadatamodel.cpp \ toolbutton.cpp \
app/metadatadialog.cpp settings.cpp \
settingsdialog.cpp
HEADERS += \ HEADERS += \
app/aboutdialog.h \ aboutdialog.h \
app/mainwindow.h \ mainwindow.h \
app/graphicsview.h \ graphicsview.h \
app/bottombuttongroup.h \ bottombuttongroup.h \
app/graphicsscene.h \ graphicsscene.h \
app/navigatorview.h \ metadata.h \
app/opacityhelper.h \ metadatadialog.h \
app/toolbutton.h \ metadatamodel.h \
app/settings.h \ navigatorview.h \
app/settingsdialog.h \ opacityhelper.h \
app/metadatamodel.h \ toolbutton.h \
app/metadatadialog.h settings.h \
settingsdialog.h
TRANSLATIONS = \ TRANSLATIONS = \
translations/PineapplePictures.ts \ languages/PineapplePictures.ts \
translations/PineapplePictures_zh_CN.ts languages/PineapplePictures_zh_CN.ts
# Default rules for deployment. # Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin qnx: target.path = /tmp/$${TARGET}/bin
View File
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
-423
View File
@@ -1,423 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>AboutDialog</name>
<message>
<location filename="../app/aboutdialog.cpp" line="22"/>
<source>About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="25"/>
<source>Launch application with image file path as argument to load the file.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="26"/>
<source>Drag and drop image file onto the window is also supported.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="27"/>
<source>Context menu option explanation:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="31"/>
<source>Make window stay on top of all other windows.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="35"/>
<source>Avoid close window accidentally. (eg. by double clicking the window)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="44"/>
<source>Version: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="47"/>
<source>Copyright (c) 2020 %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="49"/>
<source>Logo designed by %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="51"/>
<source>Built with Qt %1 (%2)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="52"/>
<source>Source code</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="58"/>
<source>Contributors</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="60"/>
<source>List of contributors on GitHub</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="61"/>
<source>Thanks to all people who contributed to this project.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="65"/>
<source>Translators</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="66"/>
<source>I would like to thank the following people who volunteered to translate this application.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="131"/>
<source>&amp;Special Thanks</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="133"/>
<source>&amp;Third-party Libraries</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="72"/>
<source>Your Rights</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="74"/>
<source>%1 is released under the MIT License.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="75"/>
<source>This license grants people a number of freedoms:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="76"/>
<source>You are free to use %1, for any purpose</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="77"/>
<source>You are free to distribute %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="78"/>
<source>You can study how %1 works and change it</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="79"/>
<source>You can distribute changed versions of %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="81"/>
<source>The MIT license guarantees you this freedom. Nobody is ever permitted to take it away.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="109"/>
<source>Third-party Libraries used by %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="110"/>
<source>%1 is built on the following free software libraries:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="129"/>
<source>&amp;Help</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="130"/>
<source>&amp;About</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="132"/>
<source>&amp;License</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GraphicsScene</name>
<message>
<location filename="../app/graphicsscene.cpp" line="16"/>
<source>Drag image here</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GraphicsView</name>
<message>
<location filename="../app/graphicsview.cpp" line="261"/>
<source>File url list is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/graphicsview.cpp" line="53"/>
<source>File is not a valid image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/graphicsview.cpp" line="55"/>
<location filename="../app/graphicsview.cpp" line="59"/>
<source>Image data is invalid or currently unsupported</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/graphicsview.cpp" line="269"/>
<source>Image data is invalid</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/graphicsview.cpp" line="276"/>
<source>Not supported mimedata: %1</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../app/mainwindow.cpp" line="178"/>
<source>File url list is empty</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="417"/>
<source>&amp;Copy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="438"/>
<source>Copy P&amp;ixmap</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="443"/>
<source>Copy &amp;File Path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="453"/>
<source>&amp;Paste Image</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="459"/>
<source>&amp;Paste Image File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="492"/>
<source>Properties</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="30"/>
<location filename="../app/mainwindow.cpp" line="464"/>
<source>Stay on top</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/aboutdialog.cpp" line="34"/>
<location filename="../app/mainwindow.cpp" line="471"/>
<source>Protected mode</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="478"/>
<source>Configure...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/mainwindow.cpp" line="485"/>
<source>Help</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MetadataDialog</name>
<message>
<location filename="../app/metadatadialog.cpp" line="75"/>
<source>Image Metadata</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MetadataModel</name>
<message>
<location filename="../app/metadatamodel.cpp" line="36"/>
<source>Origin</source>
<comment>Section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="38"/>
<source>Image</source>
<comment>Section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="44"/>
<source>File</source>
<comment>Section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="40"/>
<source>Camera</source>
<comment>Section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="27"/>
<source>%1 File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="35"/>
<source>Description</source>
<comment>Section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="41"/>
<source>Advanced photo</source>
<comment>Section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="42"/>
<source>GPS</source>
<comment>Section name.</comment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="47"/>
<source>Dimensions</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="49"/>
<source>Aspect Ratio</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="52"/>
<source>Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="54"/>
<source>Item type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="56"/>
<source>Folder path</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="58"/>
<source>Size</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="60"/>
<source>Date Created</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="62"/>
<source>Date Modified</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="70"/>
<source>%1 x %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="88"/>
<source>%1 : %2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="204"/>
<source>Property</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/metadatamodel.cpp" line="204"/>
<source>Value</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsDialog</name>
<message>
<location filename="../app/settingsdialog.cpp" line="15"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/settingsdialog.cpp" line="20"/>
<source>Do nothing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/settingsdialog.cpp" line="21"/>
<source>Close the window</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/settingsdialog.cpp" line="22"/>
<source>Toggle maximize</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/settingsdialog.cpp" line="30"/>
<source>Stay on top when start-up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/settingsdialog.cpp" line="31"/>
<source>Double-click behavior</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../app/main.cpp" line="27"/>
<source>Pineapple Pictures</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../app/main.cpp" line="31"/>
<source>File list.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>