exportwindow.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. Zint Barcode Generator - the open source barcode generator
  3. Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. /* SPDX-License-Identifier: GPL-3.0-or-later */
  17. //#include <QDebug>
  18. #include <QFileDialog>
  19. #include <QMessageBox>
  20. #include <QSettings>
  21. #include <QStringBuilder>
  22. #include <QUiLoader>
  23. #include "exportwindow.h"
  24. // Shorthand
  25. #define QSL QStringLiteral
  26. #define QSEmpty QLatin1String("")
  27. ExportWindow::ExportWindow(BarcodeItem *bc, const QString& output_data)
  28. : m_bc(bc), m_output_data(output_data), m_lines(0)
  29. {
  30. setupUi(this);
  31. if (m_bc->bc.noPng()) {
  32. cmbFileType->removeItem(0); // PNG
  33. }
  34. QSettings settings;
  35. #if QT_VERSION < 0x60000
  36. settings.setIniCodec("UTF-8");
  37. #endif
  38. QByteArray geometry = settings.value(QSL("studio/export/window_geometry")).toByteArray();
  39. restoreGeometry(geometry);
  40. linDestPath->setText(settings.value(QSL("studio/export/destination"),
  41. QDir::toNativeSeparators(QDir::homePath())).toString());
  42. linPrefix->setText(settings.value(QSL("studio/export/file_prefix"), QSL("bcs_")).toString());
  43. linPostfix->setText(settings.value(QSL("studio/export/file_postfix"), QSEmpty).toString());
  44. cmbFileName->setCurrentIndex(settings.value(QSL("studio/export/name_format"), 0).toInt());
  45. cmbFileType->setCurrentIndex(std::min(settings.value(QSL("studio/export/filetype"), 0).toInt(),
  46. cmbFileType->count() - 1));
  47. QIcon closeIcon(QIcon::fromTheme(QSL("window-close"), QIcon(QSL(":res/x.svg"))));
  48. btnCancel->setIcon(closeIcon);
  49. QIcon folderIcon(QIcon::fromTheme(QSL("folder"), QIcon(QSL(":res/folder.svg"))));
  50. btnDestPath->setIcon(folderIcon);
  51. connect(btnCancel, SIGNAL(clicked(bool)), SLOT(close()));
  52. connect(btnOK, SIGNAL(clicked(bool)), SLOT(process()));
  53. connect(btnDestPath, SIGNAL(clicked(bool)), SLOT(get_directory()));
  54. m_dataList = m_output_data.split('\n');
  55. m_lines = m_dataList.size();
  56. if (m_lines && m_dataList[m_lines - 1].isEmpty()) {
  57. m_lines--;
  58. }
  59. /*: %1 is number of sequences */
  60. lblFeedback->setText(tr("Export Results (%1):").arg(m_lines));
  61. }
  62. ExportWindow::~ExportWindow()
  63. {
  64. QSettings settings;
  65. #if QT_VERSION < 0x60000
  66. settings.setIniCodec("UTF-8");
  67. #endif
  68. settings.setValue(QSL("studio/export/window_geometry"), saveGeometry());
  69. settings.setValue(QSL("studio/export/destination"), linDestPath->text());
  70. settings.setValue(QSL("studio/export/file_prefix"), linPrefix->text());
  71. settings.setValue(QSL("studio/export/file_postfix"), linPostfix->text());
  72. settings.setValue(QSL("studio/export/name_format"), cmbFileName->currentIndex());
  73. settings.setValue(QSL("studio/export/filetype"), cmbFileType->currentIndex());
  74. }
  75. void ExportWindow::get_directory()
  76. {
  77. QSettings settings;
  78. #if QT_VERSION < 0x60000
  79. settings.setIniCodec("UTF-8");
  80. #endif
  81. QString directory;
  82. QFileDialog fdialog;
  83. fdialog.setFileMode(QFileDialog::Directory);
  84. fdialog.setDirectory(settings.value(QSL("studio/default_dir"),
  85. QDir::toNativeSeparators(QDir::homePath())).toString());
  86. if (fdialog.exec()) {
  87. directory = fdialog.selectedFiles().at(0);
  88. } else {
  89. return;
  90. }
  91. linDestPath->setText(QDir::toNativeSeparators(directory));
  92. settings.setValue(QSL("studio/default_dir"), directory);
  93. }
  94. void ExportWindow::process()
  95. {
  96. const QRegularExpression urlRE(QSL("[\\/:*?\"<>|%]"));
  97. txtFeedback->setPlainText(tr("Processing..."));
  98. txtFeedback->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
  99. QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
  100. QString biggest;
  101. bool needUrlEscape = false;
  102. const int fileNameIdx = cmbFileName->currentIndex();
  103. if (fileNameIdx == 1) {
  104. biggest = QString::number(m_lines + 1);
  105. } else {
  106. needUrlEscape = m_output_data.contains(urlRE);
  107. }
  108. QString suffix;
  109. int suffixIdx = cmbFileType->currentText().lastIndexOf(QSL("(*."));
  110. if (suffixIdx == -1) {
  111. suffix = m_bc->bc.noPng() ? QSL(".gif") : QSL(".png");
  112. } else {
  113. suffix = cmbFileType->currentText().mid(suffixIdx + 2, 4);
  114. }
  115. QString filePathPrefix = linDestPath->text() % QDir::separator() % linPrefix->text();
  116. QString postfix = linPostfix->text();
  117. QStringList Feedback;
  118. int successCount = 0, errorCount = 0;
  119. for (int i = 0; i < m_lines; i++) {
  120. const QString &dataString = m_dataList[i];
  121. QString fileName;
  122. switch (fileNameIdx) {
  123. case 0: /* Same as Data (URL Escaped) */
  124. if (needUrlEscape) {
  125. QString url_escaped;
  126. for (int m = 0; m < dataString.length(); m++) {
  127. QChar name_qchar = dataString[m];
  128. char name_char = name_qchar.toLatin1();
  129. switch (name_char) {
  130. case '\\': url_escaped += QSL("%5C"); break;
  131. case '/': url_escaped += QSL("%2F"); break;
  132. case ':': url_escaped += QSL("%3A"); break;
  133. case '*': url_escaped += QSL("%2A"); break;
  134. case '?': url_escaped += QSL("%3F"); break;
  135. case '"': url_escaped += QSL("%22"); break;
  136. case '<': url_escaped += QSL("%3C"); break;
  137. case '>': url_escaped += QSL("%3E"); break;
  138. case '|': url_escaped += QSL("%7C"); break;
  139. case '%': url_escaped += QSL("%25"); break;
  140. default: url_escaped += name_qchar; break;
  141. }
  142. }
  143. fileName = filePathPrefix % url_escaped % postfix % suffix;
  144. } else {
  145. fileName = filePathPrefix % dataString % postfix % suffix;
  146. }
  147. break;
  148. case 1: { /* Formatted Serial Number */
  149. QString this_val, pad;
  150. this_val = QString::number(i + 1);
  151. pad.fill('0', biggest.length() - this_val.length());
  152. fileName = filePathPrefix % pad % this_val % postfix % suffix;
  153. }
  154. break;
  155. }
  156. m_bc->bc.setText(dataString);
  157. m_bc->bc.save_to_file(fileName);
  158. if (m_bc->bc.hasErrors()) {
  159. /*: %1 is line number, %2 is error message */
  160. Feedback << tr("Line %1: %2").arg(i + 1).arg(m_bc->bc.error_message());
  161. errorCount++;
  162. } else {
  163. /*: %1 is line number */
  164. Feedback << tr("Line %1: Success").arg(i + 1);
  165. successCount++;
  166. }
  167. if (i && (i % 100 == 0)) {
  168. txtFeedback->appendPlainText(Feedback.join('\n'));
  169. txtFeedback->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
  170. QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
  171. Feedback.clear();
  172. }
  173. }
  174. QString summary;
  175. if (errorCount && successCount) {
  176. /*: %1 is total no. of items processed, %2 is no. of failures, %3 is no. of successes */
  177. summary = tr("Total %1, %2 failed, %3 succeeded.").arg(errorCount + successCount).arg(errorCount)
  178. .arg(successCount);
  179. } else if (errorCount) {
  180. /*: %1 is no. of failures */
  181. summary = tr("All %1 failed.").arg(errorCount);
  182. } else if (successCount) {
  183. /*: %1 is no. of successes */
  184. summary = tr("All %1 succeeded.").arg(successCount);
  185. } else {
  186. summary = tr("No items.");
  187. }
  188. if (Feedback.size()) {
  189. txtFeedback->appendPlainText(Feedback.join('\n') + '\n' + summary + '\n');
  190. } else {
  191. txtFeedback->appendPlainText(summary + '\n');
  192. }
  193. txtFeedback->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
  194. }
  195. /* vim: set ts=4 sw=4 et : */