From 4de47fbd8713b422ca66f38299dc2c0dac4d8507 Mon Sep 17 00:00:00 2001 From: Willem Ferguson Date: Sun, 19 Nov 2017 16:17:36 +0200 Subject: [PATCH 01/12] PATCH: Update the single-dive per page print template 1) Place the dive profile below the synoptic info for the dive. 2) Re-arrange the synoptic info items. 3) In the synoptic info, replace air temperature info with gas and cylinder info. 4) If any items among the the synoptic data take more than one line, the the alignment of cells in the synoptic info table is maintained. In the previous version this caused a ragged bottom edge of the synoptic info table. Signed-off-by: Willem Ferguson --- printing_templates/One Dive Simple.html | 227 ++++++++++++++++++++++++ printing_templates/One Dive.html | 218 +++++++++++++---------- 2 files changed, 349 insertions(+), 96 deletions(-) create mode 100644 printing_templates/One Dive Simple.html diff --git a/printing_templates/One Dive Simple.html b/printing_templates/One Dive Simple.html new file mode 100644 index 000000000..7f7945396 --- /dev/null +++ b/printing_templates/One Dive Simple.html @@ -0,0 +1,227 @@ + + + + + +
+{% block main_rows %} + {% for dive in dives %} +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+

Dive No.

+
+

{{ dive.number }}

+
+

Date

+
+

{{ dive.date }}

+
+

Location

+
+

{{ dive.location }}

+
+

Max. depth

+
+

{{ dive.depth }}

+
+

Duration

+
+

{{ dive.duration }}

+
+ + + + + + + + + + + + + + + + + + + + + + +
+

Time.

+
+

{{ dive.time }}

+
+

Air Temp.

+
+

{{ dive.airTemp }}

+
+

Water Temp.

+
+

{{ dive.waterTemp }}

+
+

Buddy

+
+

{{ dive.buddy }}

+
+

Divemaster

+
+

{{ dive.divemaster }}

+
+ + + + + + + + + +
+

Notes

+
+
+

{{ dive.notes|safe }}

+
+
+
+
+
+
+ {% endfor %} +{% endblock %} +
+ + diff --git a/printing_templates/One Dive.html b/printing_templates/One Dive.html index 7f7945396..7192610d4 100644 --- a/printing_templates/One Dive.html +++ b/printing_templates/One Dive.html @@ -4,19 +4,17 @@ body { {{ print_options.grayscale }}; padding: 0; - margin: 0; + margin: 0 0 0 6%; font-size: {{ template_options.font_size }}vw; line-height: {{ template_options.line_spacing }}; font-family: {{ template_options.font }}; } h1 { - float: left; font-size: {{ template_options.font_size }}vw; } p { - float: left; font-size: {{ template_options.font_size }}vw; } @@ -26,11 +24,17 @@ border-width: {{ template_options.borderwidth }}px; border-style:solid; border-color: {{ template_options.color6 }}; + border-collapse: separate; + } + + tr { + height: 4vh; } td { - padding-left: 0.5vw; - padding-right: 0.5vw; + padding: 0; + margin: 0; + padding-left: 1%; } #body_div { @@ -38,70 +42,101 @@ } .mainContainer { - width: 98%; + width: 97%; height: 100%; - margin-left: 1%; + margin-left: 0%; margin-right: 1%; margin-top: 0%; margin-bottom: 0%; - overflow: hidden; - border-width: 0; + border-width: 1px; page-break-inside: avoid; } .innerContainer { - width: 100%; + width: 99%; height: 99%; - padding-top: 1%; - overflow: hidden; + padding-top: 0%; } .diveDetails { width: 100%; - height: 98%; - float: left; + margin: 0.0%; + } + + .dataSection { + width: 100%; + margin: 0.0% 0% 0% 0%; } .diveProfile { - width: 99%; - height: 40%; - margin: 0.5%; + width: 99.5%; + height: 45%; + margin: 0.2% 0% 0.5% 0.5%; } - .dataSection { + .notesSection { width: 100%; - height: 40%; - margin: 0%; + margin: 0.0%; + min-height: 35%; } .fieldTitle { background-color: {{ template_options.color2 }}; overflow: hidden; color: {{ template_options.color4 }}; + width: 7%; + padding-left:5px; } .fieldData { background-color: {{ template_options.color3 }}; color: {{ template_options.color5 }}; + width: 13%; + padding: o$ 1% 0% 1%; } .table_class { - float: left; - margin: 0.5%; - width: 49%; + margin: 0%; + width: 100%; } + td.insert_column_inner { + border-left-style:solid; + border-left-color: {{ template_options.color6 }}; + background-color: {{ template_options.color2 }}; + color: {{ template_options.color4 }}; + border: 5px solid black; + } + + td.insert_column_outer { + background-color: {{ template_options.color2 }}; + color: {{ template_options.color4 }}; + } + .notes_table_class { overflow: hidden; - width: 99%; - margin: 0.5%; + width: 100%; + margin: 0.0% 0% 0% 0%; + max-height: 35%; } + .notes_table_class td.fieldTitle { + max-height: 0.15vh; + } + .textArea { line-height: {{ template_options.line_spacing }}; color: {{ template_options.color5 }}; - max-height: 19vh; - overflow: hidden; + font-size: {{ template_options.font_size }}vw; + padding: 1%; + } + + td.fieldTitle b { + font-size: {{ template_options.font_size }}vw; + } + + .hidden_div { + display: none; } @@ -111,14 +146,17 @@ {% for dive in dives %}
-
-
-
-
+
- + + + - - - - - - - - - - - - - - -
-

Dive No.

+ Date +
+

{{ dive.date }}

+
+ Dive No.

{{ dive.number }}

@@ -126,57 +164,27 @@
-

Date

-
-

{{ dive.date }}

-
-

Location

-
-

{{ dive.location }}

-
-

Max. depth

-
-

{{ dive.depth }}

-
-

Duration

-
-

{{ dive.duration }}

-
- - - - - + + + + + + -
-

Time.

+ Time

{{ dive.time }}

-

Air Temp.

+ Gases
-

{{ dive.airTemp }}

+

{{ dive.gas }}

-

Water Temp.

+ Location +
+

{{ dive.location }}

+
+ Water Temp.

{{ dive.waterTemp }}

@@ -184,7 +192,13 @@
-

Buddy

+ Max Depth +
+

{{ dive.depth }}

+
+ Buddy

{{ dive.buddy }}

@@ -192,36 +206,48 @@
-

Divemaster

+ Duration +
+

{{ dive.duration }}

+
+ Dive Master

{{ dive.divemaster }}

- - - - - - - - - -
-

Notes

-
-
-

{{ dive.notes|safe }}

-
-
-
-
-
+ +
+
+ +
+ + + + + + + + + +
+ Notes +
+

{{ dive.notes|safe }}

+
+
+ +
+ + {% endfor %} {% endblock %} - + + + From 6895c0eca5550b449ee616b7d3b3c5beb8b54ab3 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Wed, 22 Nov 2017 20:58:42 +0200 Subject: [PATCH 02/12] printing: delete `One Dive Simple.html` and cleanup The previous commit by Willem introduced a new HTML template file which is not needed, as it was decided to override the default `One Dive.html`. This patch also include small cleanup in the new version of `One Dive.html`. Signed-off-by: Lubomir I. Ivanov --- printing_templates/One Dive Simple.html | 227 ------------------------ printing_templates/One Dive.html | 12 +- 2 files changed, 5 insertions(+), 234 deletions(-) delete mode 100644 printing_templates/One Dive Simple.html diff --git a/printing_templates/One Dive Simple.html b/printing_templates/One Dive Simple.html deleted file mode 100644 index 7f7945396..000000000 --- a/printing_templates/One Dive Simple.html +++ /dev/null @@ -1,227 +0,0 @@ - - - - - -
-{% block main_rows %} - {% for dive in dives %} -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - -
-

Dive No.

-
-

{{ dive.number }}

-
-

Date

-
-

{{ dive.date }}

-
-

Location

-
-

{{ dive.location }}

-
-

Max. depth

-
-

{{ dive.depth }}

-
-

Duration

-
-

{{ dive.duration }}

-
- - - - - - - - - - - - - - - - - - - - - - -
-

Time.

-
-

{{ dive.time }}

-
-

Air Temp.

-
-

{{ dive.airTemp }}

-
-

Water Temp.

-
-

{{ dive.waterTemp }}

-
-

Buddy

-
-

{{ dive.buddy }}

-
-

Divemaster

-
-

{{ dive.divemaster }}

-
- - - - - - - - - -
-

Notes

-
-
-

{{ dive.notes|safe }}

-
-
-
-
-
-
- {% endfor %} -{% endblock %} -
- - diff --git a/printing_templates/One Dive.html b/printing_templates/One Dive.html index 7192610d4..a9ee00471 100644 --- a/printing_templates/One Dive.html +++ b/printing_templates/One Dive.html @@ -4,7 +4,7 @@ body { {{ print_options.grayscale }}; padding: 0; - margin: 0 0 0 6%; + margin: 0 0 0 6%; font-size: {{ template_options.font_size }}vw; line-height: {{ template_options.line_spacing }}; font-family: {{ template_options.font }}; @@ -239,15 +239,13 @@ - + - - + + {% endfor %} {% endblock %} - - - + From 9209382c1868045baf49da42c5700da43556a49f Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 01:59:26 +0200 Subject: [PATCH 03/12] printing: add set_bundled_templates_as_read_only() Add the function set_bundled_templates_as_read_only() in templatelayout.cpp/h. The function is used to mark the bundled template files as read-only in the user folder. It is called in mainwindow.cpp, after the files are copied from the bundle. Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/mainwindow.cpp | 1 + desktop-widgets/templatelayout.cpp | 24 ++++++++++++++++++++++++ desktop-widgets/templatelayout.h | 1 + 3 files changed, 26 insertions(+) diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp index f685a2b74..05314af1d 100644 --- a/desktop-widgets/mainwindow.cpp +++ b/desktop-widgets/mainwindow.cpp @@ -258,6 +258,7 @@ MainWindow::MainWindow() : QMainWindow(), #ifndef NO_PRINTING // copy the bundled print templates to the user path; no overwriting occurs! copyPath(getPrintingTemplatePathBundle(), getPrintingTemplatePathUser()); + set_bundled_templates_as_read_only(); find_all_templates(); #endif diff --git a/desktop-widgets/templatelayout.cpp b/desktop-widgets/templatelayout.cpp index 9f933e91c..b53f55741 100644 --- a/desktop-widgets/templatelayout.cpp +++ b/desktop-widgets/templatelayout.cpp @@ -1,4 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include #include "templatelayout.h" @@ -39,6 +40,29 @@ void find_all_templates() } } +/* find templates which are part of the bundle in the user path + * and set them as read only. + */ +void set_bundled_templates_as_read_only() +{ + QDir dir; + const QString stats("statistics"); + QStringList list, listStats; + QString pathBundle = getPrintingTemplatePathBundle(); + QString pathUser = getPrintingTemplatePathUser(); + + dir.setPath(pathBundle); + list = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); + dir.setPath(pathBundle + QDir::separator() + stats); + listStats = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); + for (int i = 0; i < listStats.length(); i++) + listStats[i] = stats + QDir::separator() + listStats.at(i); + list += listStats; + + foreach (const QString& f, list) + QFile::setPermissions(pathUser + QDir::separator() + f, QFileDevice::ReadOwner | QFileDevice::ReadUser); +} + TemplateLayout::TemplateLayout(print_options *PrintOptions, template_options *templateOptions) : m_engine(NULL) { diff --git a/desktop-widgets/templatelayout.h b/desktop-widgets/templatelayout.h index 9c24d096d..8ec4eadc7 100644 --- a/desktop-widgets/templatelayout.h +++ b/desktop-widgets/templatelayout.h @@ -12,6 +12,7 @@ int getTotalWork(print_options *printOptions); void find_all_templates(); +void set_bundled_templates_as_read_only(); extern QList grantlee_templates, grantlee_statistics_templates; From c6c9b3bd8ba41290d4484b168401976571166d70 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 02:24:29 +0200 Subject: [PATCH 04/12] printing: minor improvements to import / export 1) Always open the user path on Import / Export 2) Update the list after Export, as the user might have exported to the user path Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/printoptions.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/desktop-widgets/printoptions.cpp b/desktop-widgets/printoptions.cpp index eaeb6954b..34aac318f 100644 --- a/desktop-widgets/printoptions.cpp +++ b/desktop-widgets/printoptions.cpp @@ -128,12 +128,13 @@ void PrintOptions::on_editButton_clicked() void PrintOptions::on_importButton_clicked() { - QString filename = QFileDialog::getOpenFileName(this, tr("Import template file"), "", + QString pathUser = getPrintingTemplatePathUser(); + QString filename = QFileDialog::getOpenFileName(this, tr("Import template file"), pathUser, tr("HTML files") + " (*.html)"); if (filename.isEmpty()) return; QFileInfo fileInfo(filename); - QFile::copy(filename, getPrintingTemplatePathUser() + QDir::separator() + fileInfo.fileName()); + QFile::copy(filename, pathUser + QDir::separator() + fileInfo.fileName()); printOptions->p_template = fileInfo.fileName(); find_all_templates(); setup(); @@ -141,11 +142,14 @@ void PrintOptions::on_importButton_clicked() void PrintOptions::on_exportButton_clicked() { - QString filename = QFileDialog::getSaveFileName(this, tr("Export template files as"), "", + QString pathUser = getPrintingTemplatePathUser(); + QString filename = QFileDialog::getSaveFileName(this, tr("Export template files as"), pathUser, tr("HTML files") + " (*.html)"); if (filename.isEmpty()) return; - QFile::copy(getPrintingTemplatePathUser() + QDir::separator() + getSelectedTemplate(), filename); + QFile::copy(pathUser + QDir::separator() + getSelectedTemplate(), filename); + find_all_templates(); + setup(); } void PrintOptions::on_deleteButton_clicked() From bc6146577d0c3524a02733d79811a6bc9310d839 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 02:54:27 +0200 Subject: [PATCH 05/12] printing: improve messaging in printoptions.cpp 1) on_deleteButton_clicked() show a proper message box with icon title and also quote the file name. 2) When exporting a file, make sure that the destination is not read-only even if the source is. 3) Do not allow editing of read-only templates (e.g. the bundled ones). Instruct the user to Export first. Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/printoptions.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/desktop-widgets/printoptions.cpp b/desktop-widgets/printoptions.cpp index 34aac318f..7ed8ecb46 100644 --- a/desktop-widgets/printoptions.cpp +++ b/desktop-widgets/printoptions.cpp @@ -121,6 +121,19 @@ void PrintOptions::on_printTemplate_currentIndexChanged(int index) void PrintOptions::on_editButton_clicked() { + QString templateName = getSelectedTemplate(); + QFile f(getPrintingTemplatePathUser() + QDir::separator() + templateName); + if (!f.open(QFile::ReadWrite | QFile::Text)) { + QMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Read-only template!")); + msgBox.setText(tr("The template '%1' is read-only and connot be edited.\n" + "Please export this template to a different file.").arg(templateName)); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + return; + } else { + f.close(); + } TemplateEdit te(this, printOptions, templateOptions); te.exec(); setup(); @@ -148,6 +161,11 @@ void PrintOptions::on_exportButton_clicked() if (filename.isEmpty()) return; QFile::copy(pathUser + QDir::separator() + getSelectedTemplate(), filename); + QFile f(filename); + if (!f.open(QFile::ReadWrite | QFile::Text)) + f.setPermissions(QFileDevice::ReadUser | QFileDevice::ReadOwner | QFileDevice::WriteUser | QFileDevice::WriteOwner); + else + f.close(); find_all_templates(); setup(); } @@ -155,9 +173,9 @@ void PrintOptions::on_exportButton_clicked() void PrintOptions::on_deleteButton_clicked() { QString templateName = getSelectedTemplate(); - QMessageBox msgBox; - msgBox.setText(tr("This action cannot be undone!")); - msgBox.setInformativeText(tr("Delete template: %1?").arg(templateName)); + QMessageBox msgBox(this); + msgBox.setWindowTitle(tr("This action cannot be undone!")); + msgBox.setText(tr("Delete template '%1'?").arg(templateName)); msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); if (msgBox.exec() == QMessageBox::Ok) { From a2ec791f2fa9db99adbea0cd8820ed9c142f2349 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 16:40:05 +0200 Subject: [PATCH 06/12] printing: store the last import / export template Store the last template file name which the user imported / exported and then try to pre-select it in the combo box. Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/printoptions.cpp | 7 ++++++- desktop-widgets/printoptions.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/desktop-widgets/printoptions.cpp b/desktop-widgets/printoptions.cpp index 7ed8ecb46..10d6d9c25 100644 --- a/desktop-widgets/printoptions.cpp +++ b/desktop-widgets/printoptions.cpp @@ -60,11 +60,13 @@ void PrintOptions::setupTemplates() int current_index = 0; ui.printTemplate->clear(); Q_FOREACH(const QString& theme, currList) { - if (theme == storedTemplate) // find the stored template in the list + // find the stored template in the list + if (theme == storedTemplate || theme == lastImportExportTemplate) current_index = currList.indexOf(theme); ui.printTemplate->addItem(theme.split('.')[0], theme); } ui.printTemplate->setCurrentIndex(current_index); + lastImportExportTemplate = ""; } // print type radio buttons @@ -149,6 +151,7 @@ void PrintOptions::on_importButton_clicked() QFileInfo fileInfo(filename); QFile::copy(filename, pathUser + QDir::separator() + fileInfo.fileName()); printOptions->p_template = fileInfo.fileName(); + lastImportExportTemplate = fileInfo.fileName(); find_all_templates(); setup(); } @@ -166,6 +169,8 @@ void PrintOptions::on_exportButton_clicked() f.setPermissions(QFileDevice::ReadUser | QFileDevice::ReadOwner | QFileDevice::WriteUser | QFileDevice::WriteOwner); else f.close(); + QFileInfo fileInfo(filename); + lastImportExportTemplate = fileInfo.fileName(); find_all_templates(); setup(); } diff --git a/desktop-widgets/printoptions.h b/desktop-widgets/printoptions.h index 9aaf8de70..1db0dfe61 100644 --- a/desktop-widgets/printoptions.h +++ b/desktop-widgets/printoptions.h @@ -72,6 +72,7 @@ private: struct print_options *printOptions; struct template_options *templateOptions; bool hasSetupSlots; + QString lastImportExportTemplate; void setupTemplates(); private From c57df085a4dc9e4b679dfa5f2d834c3ecf5f8f63 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 16:42:54 +0200 Subject: [PATCH 07/12] printing: make sure that exported templates are .html Thus far the exported template did not had the .html extension. This patch makes sure that the extension is always added to the file if missing. Also handle the case where the user used ".htm" and replace that with ".html". Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/printoptions.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/desktop-widgets/printoptions.cpp b/desktop-widgets/printoptions.cpp index 10d6d9c25..4b1deabca 100644 --- a/desktop-widgets/printoptions.cpp +++ b/desktop-widgets/printoptions.cpp @@ -163,6 +163,11 @@ void PrintOptions::on_exportButton_clicked() tr("HTML files") + " (*.html)"); if (filename.isEmpty()) return; + const QString ext(".html"); + if (filename.endsWith(".htm", Qt::CaseInsensitive)) + filename += "l"; + else if (!filename.endsWith(ext, Qt::CaseInsensitive)) + filename += ext; QFile::copy(pathUser + QDir::separator() + getSelectedTemplate(), filename); QFile f(filename); if (!f.open(QFile::ReadWrite | QFile::Text)) From ba7f2a399b6c0df6805d25b37bcab266d2020acc Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 18:03:46 +0200 Subject: [PATCH 08/12] printing: handle overwriting in import / export Show an error message if trying to: 1) Import over an existing read-only template with the same name 2) Export to a read-only file with the same name 3) Delete a read-only template Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/printoptions.cpp | 46 +++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/desktop-widgets/printoptions.cpp b/desktop-widgets/printoptions.cpp index 4b1deabca..6e45bc5e1 100644 --- a/desktop-widgets/printoptions.cpp +++ b/desktop-widgets/printoptions.cpp @@ -149,7 +149,23 @@ void PrintOptions::on_importButton_clicked() if (filename.isEmpty()) return; QFileInfo fileInfo(filename); - QFile::copy(filename, pathUser + QDir::separator() + fileInfo.fileName()); + + const QString dest = pathUser + QDir::separator() + fileInfo.fileName(); + QFile f(dest); + if (!f.open(QFile::ReadWrite | QFile::Text)) { + QMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Read-only template!")); + msgBox.setText(tr("The destination template '%1' is read-only and cannot be overwritten.").arg(fileInfo.fileName())); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + return; + } else { + f.close(); + if (filename != dest) + f.remove(); + } + + QFile::copy(filename, dest); printOptions->p_template = fileInfo.fileName(); lastImportExportTemplate = fileInfo.fileName(); find_all_templates(); @@ -168,13 +184,28 @@ void PrintOptions::on_exportButton_clicked() filename += "l"; else if (!filename.endsWith(ext, Qt::CaseInsensitive)) filename += ext; - QFile::copy(pathUser + QDir::separator() + getSelectedTemplate(), filename); + QFileInfo fileInfo(filename); + const QString dest = pathUser + QDir::separator() + getSelectedTemplate(); + QFile f(filename); + if (!f.open(QFile::ReadWrite | QFile::Text)) { + QMessageBox msgBox(this); + msgBox.setWindowTitle(tr("Read-only template!")); + msgBox.setText(tr("The destination template '%1' is read-only and cannot be overwritten.").arg(fileInfo.fileName())); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + return; + } else { + f.close(); + if (dest != filename) + f.remove(); + } + + QFile::copy(dest, filename); if (!f.open(QFile::ReadWrite | QFile::Text)) f.setPermissions(QFileDevice::ReadUser | QFileDevice::ReadOwner | QFileDevice::WriteUser | QFileDevice::WriteOwner); else f.close(); - QFileInfo fileInfo(filename); lastImportExportTemplate = fileInfo.fileName(); find_all_templates(); setup(); @@ -190,6 +221,15 @@ void PrintOptions::on_deleteButton_clicked() msgBox.setDefaultButton(QMessageBox::Cancel); if (msgBox.exec() == QMessageBox::Ok) { QFile f(getPrintingTemplatePathUser() + QDir::separator() + templateName); + if (!f.open(QFile::ReadWrite | QFile::Text)) { + msgBox.setWindowTitle(tr("Read-only template!")); + msgBox.setText(tr("The template '%1' is read-only and cannot be deleted.").arg(templateName)); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + return; + } else { + f.close(); + } f.remove(); find_all_templates(); setup(); From 712697e0c24e53d32ef6087c7f2b4e24fdf8a57c Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 18:23:36 +0200 Subject: [PATCH 09/12] printing: detect a 'statistics' template when editing Prefix the path for 'statistics' templates when detecting if a template is read-only. Import / Export for statistic templates is not supported. So the user has to manually copy and chown a '/statistics' templates. Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/printoptions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/desktop-widgets/printoptions.cpp b/desktop-widgets/printoptions.cpp index 6e45bc5e1..cebb073a3 100644 --- a/desktop-widgets/printoptions.cpp +++ b/desktop-widgets/printoptions.cpp @@ -124,7 +124,8 @@ void PrintOptions::on_printTemplate_currentIndexChanged(int index) void PrintOptions::on_editButton_clicked() { QString templateName = getSelectedTemplate(); - QFile f(getPrintingTemplatePathUser() + QDir::separator() + templateName); + QString prefix = (printOptions->type == print_options::STATISTICS) ? "statistics/" : ""; + QFile f(getPrintingTemplatePathUser() + QDir::separator() + prefix + templateName); if (!f.open(QFile::ReadWrite | QFile::Text)) { QMessageBox msgBox(this); msgBox.setWindowTitle(tr("Read-only template!")); From fc48cde77c98385c69bc4d951de6867cf2f652a0 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Fri, 24 Nov 2017 20:55:16 +0200 Subject: [PATCH 10/12] printing: only load *.html files in the UI The function find_all_templates() thus far handled all files in the user template directory. This patch makes it so that only files with the .html extension are loaded. Also remove brackets for single lined `if` statement. Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/templatelayout.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/desktop-widgets/templatelayout.cpp b/desktop-widgets/templatelayout.cpp index b53f55741..ab9b3f09a 100644 --- a/desktop-widgets/templatelayout.cpp +++ b/desktop-widgets/templatelayout.cpp @@ -20,23 +20,22 @@ int getTotalWork(print_options *printOptions) void find_all_templates() { + const QString ext(".html"); grantlee_templates.clear(); grantlee_statistics_templates.clear(); QDir dir(getPrintingTemplatePathUser()); QStringList list = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); foreach (const QString& filename, list) { - if (filename.at(filename.size() - 1) != '~') { + if (filename.at(filename.size() - 1) != '~' && filename.endsWith(ext)) grantlee_templates.append(filename); - } } // find statistics templates dir.setPath(getPrintingTemplatePathUser() + QDir::separator() + "statistics"); list = dir.entryList(QDir::Files | QDir::NoDotAndDotDot); foreach (const QString& filename, list) { - if (filename.at(filename.size() - 1) != '~') { + if (filename.at(filename.size() - 1) != '~' && filename.endsWith(ext)) grantlee_statistics_templates.append(filename); - } } } From 65f0600679a72d13b64b20c575c05b5313a80635 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Fri, 24 Nov 2017 22:54:54 +0200 Subject: [PATCH 11/12] printing: update the coping of bundled templates This update includes: - Instead of copyPath() use a new specialized function: copy_bundled_templates() - The new function supports overwriting of templates in the user path, but only if a template file is read-only - If the file is RW create a backup of the file in the form of: -User.html - Collect backup files and store them in a QStringList which is then shown in a QMessageBox from MainWindow to notifying the user about the backup This change allows moving the maintenance of the bundled templates back to the application developers and contributors as currently the only one who can edit the templates in the user path was the user. Suggested-by: Dirk Hohndel Signed-off-by: Lubomir I. Ivanov --- desktop-widgets/mainwindow.cpp | 19 +++++++++++++++++-- desktop-widgets/templatelayout.cpp | 29 +++++++++++++++++++++++++++++ desktop-widgets/templatelayout.h | 2 ++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp index 05314af1d..e5739bd47 100644 --- a/desktop-widgets/mainwindow.cpp +++ b/desktop-widgets/mainwindow.cpp @@ -256,8 +256,23 @@ MainWindow::MainWindow() : QMainWindow(), connect(geoLookup, SIGNAL(started()),information(), SLOT(disableGeoLookupEdition())); connect(geoLookup, SIGNAL(finished()), information(), SLOT(enableGeoLookupEdition())); #ifndef NO_PRINTING - // copy the bundled print templates to the user path; no overwriting occurs! - copyPath(getPrintingTemplatePathBundle(), getPrintingTemplatePathUser()); + // copy the bundled print templates to the user path + QStringList templateBackupList; + QString templatePathUser(getPrintingTemplatePathUser()); + copy_bundled_templates(getPrintingTemplatePathBundle(), templatePathUser, &templateBackupList); + if (templateBackupList.length()) { + QMessageBox msgBox(this); + templatePathUser.replace("\\", "/"); + templateBackupList.replaceInStrings(templatePathUser + "/", ""); + msgBox.setWindowTitle(tr("Template backup created")); + msgBox.setText(tr("The following backup printing templates were created:\n\n%1\n\n" + "Location:\n%2\n\n" + "Please note that as of this version of Subsurface the default templates\n" + "are read-only and should not be edited directly, since the application\n" + "can overwrite them on startup.").arg(templateBackupList.join("\n")).arg(templatePathUser)); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + } set_bundled_templates_as_read_only(); find_all_templates(); #endif diff --git a/desktop-widgets/templatelayout.cpp b/desktop-widgets/templatelayout.cpp index ab9b3f09a..f3f3c8be2 100644 --- a/desktop-widgets/templatelayout.cpp +++ b/desktop-widgets/templatelayout.cpp @@ -62,6 +62,35 @@ void set_bundled_templates_as_read_only() QFile::setPermissions(pathUser + QDir::separator() + f, QFileDevice::ReadOwner | QFileDevice::ReadUser); } +void copy_bundled_templates(QString src, QString dst, QStringList *templateBackupList) +{ + QDir dir(src); + if (!dir.exists()) + return; + foreach (QString d, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + QString dst_path = dst + QDir::separator() + d; + dir.mkpath(dst_path); + copy_bundled_templates(src + QDir::separator() + d, dst_path, templateBackupList); + } + foreach (QString f, dir.entryList(QDir::Files)) { + QFile fileSrc(src + QDir::separator() + f); + QFile fileDest(dst + QDir::separator() + f); + if (fileDest.exists()) { + // if open() fails the file is either locked or r/o. try to remove it and then overwrite + if (!fileDest.open(QFile::ReadWrite | QFile::Text)) { + fileDest.setPermissions(QFileDevice::WriteOwner | QFileDevice::WriteUser); + fileDest.remove(); + } else { // if the file is not read-only create a backup + fileDest.close(); + const QString targetFile = fileDest.fileName().replace(".html", "-User.html"); + fileDest.copy(targetFile); + *templateBackupList << targetFile; + } + } + fileSrc.copy(fileDest.fileName()); // in all cases copy the file + } +} + TemplateLayout::TemplateLayout(print_options *PrintOptions, template_options *templateOptions) : m_engine(NULL) { diff --git a/desktop-widgets/templatelayout.h b/desktop-widgets/templatelayout.h index 8ec4eadc7..cb60cc03d 100644 --- a/desktop-widgets/templatelayout.h +++ b/desktop-widgets/templatelayout.h @@ -2,6 +2,7 @@ #ifndef TEMPLATELAYOUT_H #define TEMPLATELAYOUT_H +#include #include #include "mainwindow.h" #include "printoptions.h" @@ -13,6 +14,7 @@ int getTotalWork(print_options *printOptions); void find_all_templates(); void set_bundled_templates_as_read_only(); +void copy_bundled_templates(QString src, QString dst, QStringList *templateBackupList); extern QList grantlee_templates, grantlee_statistics_templates; From 4a870ff6b3478725629116ddf48df345619b3d64 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 23 Nov 2017 18:43:19 +0200 Subject: [PATCH 12/12] printing: add release note about the recent template changes refs #847 Signed-off-by: Lubomir I. Ivanov --- ReleaseNotes/ReleaseNotes.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ReleaseNotes/ReleaseNotes.txt b/ReleaseNotes/ReleaseNotes.txt index f0c2361dc..c37e2955d 100644 --- a/ReleaseNotes/ReleaseNotes.txt +++ b/ReleaseNotes/ReleaseNotes.txt @@ -14,6 +14,9 @@ Some of the changes since _Subsurface_ 4.7.4 - Allow user defined cylinders as default in preferences (#821) - mobile: fix black/white switch in splash screen (#531) - UI: tag editing. Comma entry shows all tags (again) (#605) +- Printing: the bundled templates are now read-only and are always overwritten + by the application. The first time the user runs this update, backup files + of the previous templates would be created. (#847). Some of the changes since _Subsurface_ 4.7.2