QElectroTech  0.70
diagramprintdialog.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2006-2019 The QElectroTech Team
3  This file is part of QElectroTech.
4 
5  QElectroTech is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 2 of the License, or
8  (at your option) any later version.
9 
10  QElectroTech is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "diagramprintdialog.h"
19 #include "qetprintpreviewdialog.h"
20 #include <math.h>
21 #include "diagramschooser.h"
22 #include "exportproperties.h"
23 #include "qeticons.h"
24 #include "qetmessagebox.h"
25 
26 #include <QPrinter>
27 #include <QPrintDialog>
28 
35  QWidget(parent),
36  project_(project),
37  dialog_(nullptr)
38 {
39  // initialise l'imprimante
40  printer_ = new QPrinter();
41 
42  // orientation paysage par defaut
43  printer_ -> setOrientation(QPrinter::Landscape);
45  Diagram::background_color = Qt::white;
46 }
47 
52  delete dialog_;
53  delete printer_;
55 }
56 
60 void DiagramPrintDialog::setFileName(const QString &name) {
61  file_name_ = name;
62 }
63 
68  return(file_name_);
69 }
70 
74 void DiagramPrintDialog::setDocName(const QString &name) {
75  doc_name_ = name;
76 }
77 
81 QString DiagramPrintDialog::docName() const {
82  return(doc_name_);
83 }
84 
91 QRect DiagramPrintDialog::diagramRect(Diagram *diagram, const ExportProperties &options) const {
92  if (!diagram) return(QRect());
93 
94  QRectF diagram_rect = diagram -> border_and_titleblock.borderAndTitleBlockRect();
95  if (!options.draw_titleblock) {
96  qreal titleblock_height = diagram -> border_and_titleblock.titleBlockRect().height();
97  diagram_rect.setHeight(diagram_rect.height() - titleblock_height);
98  }
99 
100  // ajuste la bordure du schema d'un pixel (epaisseur du trait)
101  diagram_rect = diagram_rect.adjusted(0.0, 0.0, 1.0, 1.0);
102 
103  return(diagram_rect.toAlignedRect());
104 }
105 
110 
111  // prise en compte du nom du document
112  if (!doc_name_.isEmpty()) printer_ -> setDocName(doc_name_);
113  printer_ -> setCreator(QString("QElectroTech %1").arg(QET::displayedVersion));
114 
115  // affichage d'un premier dialogue demandant a l'utilisateur le type
116  // d'impression qu'il souhaite effectuer
118  if (dialog_ -> exec() == QDialog::Rejected) return;
119 
120  // parametrage de l'imprimante en fonction du type d'impression choisi
121  if (printer_choice_ -> isChecked()) {
122  // affichage du dialogue d'impression standard pour parametrer l'imprimante
123  QPrintDialog print_dialog(printer_, parentWidget());
124 #ifdef Q_OS_MAC
125  print_dialog.setWindowFlags(Qt::Sheet);
126 #endif
127  print_dialog.setWindowTitle(tr("Options d'impression", "window title"));
128  print_dialog.setEnabledOptions(QAbstractPrintDialog::PrintShowPageSize);
129  if (print_dialog.exec() == QDialog::Rejected) return;
130  }
131  else
132  {
133  printer_ -> setOutputFormat(QPrinter::PdfFormat);
134  printer_ -> setOutputFileName(filepath_field_ -> text());
135  }
136 
138 
139  //Preview before print
140 #if defined Q_OS_LINUX
141  //Due to some bug with xfwm, we display this dialog has a windows on linux os (X11)
142  //@TODO see if we must this line with graphic server wayland
143  QETPrintPreviewDialog preview_dialog(project_, printer_, parentWidget(), Qt::Window);
144 #else
145  QETPrintPreviewDialog preview_dialog(project_, printer_, parentWidget());
146 #endif
147  connect(
148  &preview_dialog,
149  SIGNAL(paintRequested(const QList<Diagram *> &, bool, const ExportProperties, QPrinter *)),
150  this,
151  SLOT(print(const QList<Diagram *> &, bool, const ExportProperties))
152  );
153  DiagramsChooser *dc = preview_dialog.diagramsChooser();
154  dc -> setSelectedAllDiagrams();
155  if (preview_dialog.exec() == QDialog::Rejected) return;
156 
158 
159  // effectue l'impression en elle-meme
160  print(
161  dc -> selectedDiagrams(),
162  preview_dialog.fitDiagramsToPages(),
163  preview_dialog.exportProperties()
164  );
165 }
166 
174 int DiagramPrintDialog::pagesCount(Diagram *diagram, const ExportProperties &options, bool fullpage) const {
175  return(horizontalPagesCount(diagram, options, fullpage) * verticalPagesCount(diagram, options, fullpage));
176 }
177 
185 int DiagramPrintDialog::horizontalPagesCount(Diagram *diagram, const ExportProperties &options, bool fullpage) const {
186  // note : pageRect et Paper Rect tiennent compte de l'orientation du papier
187  QRect printable_area = fullpage ? printer_ -> paperRect() : printer_ -> pageRect();
188  QRect diagram_rect = diagramRect(diagram, options);
189 
190  int h_pages_count = int(ceil(qreal(diagram_rect.width()) / qreal(printable_area.width())));
191  return(h_pages_count);
192 }
193 
201 int DiagramPrintDialog::verticalPagesCount(Diagram *diagram, const ExportProperties &options, bool fullpage) const {
202  // note : pageRect et Paper Rect tiennent compte de l'orientation du papier
203  QRect printable_area = fullpage ? printer_ -> paperRect() : printer_ -> pageRect();
204  QRect diagram_rect = diagramRect(diagram, options);
205 
206  int v_pages_count = int(ceil(qreal(diagram_rect.height()) / qreal(printable_area.height())));
207  return(v_pages_count);
208 }
209 
215  // initialisation des widgets
216  dialog_ = new QDialog(parentWidget());
217 #ifdef Q_OS_MAC
218  dialog_ -> setWindowFlags(Qt::Sheet);
219 #endif
220 
221  printtype_label_ = new QLabel(tr("Quel type d'impression désirez-vous effectuer ?"));
222  printer_icon_ = new QLabel();
223  pdf_icon_ = new QLabel();
224 
225  printtype_choice_ = new QButtonGroup();
226  printer_choice_ = new QRadioButton(tr("Impression sur une imprimante physique", "Print type choice"));
227  pdf_choice_ = new QRadioButton(tr("Impression vers un fichier au format PDF", "Print type choice"));
228 
229  filepath_field_ = new QLineEdit();
230  browse_button_ = new QPushButton("...");
231  buttons_ = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
232 
233  dialog_ -> setWindowTitle(tr("Choix du type d'impression"));
234  printer_icon_ -> setPixmap(QET::Icons::Printer.pixmap(32, 32));
235  pdf_icon_ -> setPixmap(QET::Icons::PDF.pixmap(32, 32));
236 
237  printtype_choice_ -> addButton(printer_choice_);
238  printtype_choice_ -> addButton(pdf_choice_);
239 
240  printer_choice_ -> setChecked(true);
241  if (!file_name_.isEmpty()) filepath_field_ -> setText(file_name_ + ".pdf");
242 
243  // connexions signaux / slots
244  connect(printer_choice_, SIGNAL(toggled(bool)), this, SLOT(updatePrintTypeDialog()));
245  connect(pdf_choice_, SIGNAL(toggled(bool)), this, SLOT(updatePrintTypeDialog()));
246  connect(browse_button_, SIGNAL(clicked(bool)), this, SLOT(browseFilePrintTypeDialog()));
247  connect(buttons_, SIGNAL(accepted()), this, SLOT(acceptPrintTypeDialog()));
248  connect(buttons_, SIGNAL(rejected()), dialog_, SLOT(reject()));
249 
250  // organisation graphique
251  glayout0_ = new QGridLayout();
252  hlayout0_ = new QHBoxLayout();
253  vlayout0_ = new QVBoxLayout();
254 
255  hlayout0_ -> addWidget(filepath_field_);
256  hlayout0_ -> addWidget(browse_button_);
257  glayout0_ -> addWidget(printer_icon_, 0, 0);
258  glayout0_ -> addWidget(printer_choice_, 0, 1);
259  glayout0_ -> addWidget(pdf_icon_, 1, 0);
260  glayout0_ -> addWidget(pdf_choice_, 1, 1);
261  glayout0_ -> addLayout(hlayout0_, 3, 1);
262 
263  vlayout0_ -> addWidget(printtype_label_);
264  vlayout0_ -> addLayout(glayout0_);
265  vlayout0_ -> addWidget(buttons_);
266 
267  dialog_ -> setLayout(vlayout0_);
268 
270 }
271 
276  // imprime-t-on vers un fichier ?
277  bool file_print = !(printer_choice_ -> isChecked());
278 
279  // on n'active le champ fichier que pour les impressions vers un fichier
280  filepath_field_ -> setEnabled(file_print);
281  browse_button_ -> setEnabled(file_print);
282 
283  // on corrige eventuellement l'extension du fichier deja selectionne
284  if (file_print)
285  {
286  QString filepath = filepath_field_ -> text();
287  if (!filepath.isEmpty())
288  {
289  if (pdf_choice_ -> isChecked() && filepath.endsWith(".ps"))
290  {
291  QRegExp re("\\.ps$", Qt::CaseInsensitive);
292  filepath.replace(re, ".pdf");
293  filepath_field_ -> setText(filepath);
294  }
295  }
296  }
297 }
298 
304  bool file_print = !(printer_choice_ -> isChecked());
305  if (file_print) {
306  // un fichier doit avoir ete entre
307  if (filepath_field_ -> text().isEmpty()) {
309  parentWidget(),
310  tr("Fichier manquant", "message box title"),
311  tr("Vous devez indiquer le chemin du fichier PDF/PS à créer.", "message box content")
312  );
313  } else dialog_ -> accept();
314  } else {
315  // une imprimante doit avoir ete selectionnee
317  dialog_ -> accept();
318  }
319 }
320 
325  QString extension;
326  QString filter;
327  if (printer_choice_ -> isChecked()) return;
328  else if (pdf_choice_ -> isChecked())
329  {
330  extension = ".pdf";
331  filter = tr("Fichiers PDF (*.pdf)", "file filter");
332  }
333 
334  QString filepath = QFileDialog::getSaveFileName(
335  parentWidget(),
336  QString(),
337  filepath_field_ -> text(),
338  filter
339  );
340 
341  if (!filepath.isEmpty()) {
342  if (!filepath.endsWith(extension)) filepath += extension;
343  filepath = QDir::toNativeSeparators(QDir::cleanPath(filepath));
344  filepath_field_ -> setText(filepath);
345  }
346 }
347 
355 void DiagramPrintDialog::print(const QList<Diagram *> &diagrams, bool fit_page, const ExportProperties& options) {
356  //qDebug() << "Demande d'impression de " << diagrams.count() << "schemas.";
357 #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
358  #ifdef Q_OS_WIN
359  #ifdef QT_DEBUG
360  qDebug() << "--";
361  qDebug() << "DiagramPrintDialog::print printer_->resolution() before " << printer_->resolution();
362  qDebug() << "DiagramPrintDialog::print screennumber " << QApplication::desktop()->screenNumber();
363  #endif
364 
365  QScreen *srn = QApplication::screens().at(QApplication::desktop()->screenNumber());
366  qreal dotsPerInch = (qreal)srn->logicalDotsPerInch();
367  printer_->setResolution(dotsPerInch);
368 
369  #ifdef QT_DEBUG
370  qDebug() << "DiagramPrintDialog::print dotsPerInch " << dotsPerInch;
371  qDebug() << "DiagramPrintDialog::print printer_->resolution() after" << printer_->resolution();
372  qDebug() << "--";
373  #endif
374  #endif
375 #endif
376  // QPainter utiliser pour effectuer le rendu
377  QPainter qp(printer_);
378 
379  // cas special : il n'y a aucun schema a imprimer
380  if (!diagrams.count()) {
381  qp.end();
382  return;
383  }
384 
385  // imprime les schemas
386  for (int i = 0 ; i < diagrams.count() ; ++ i) {
387  printDiagram(diagrams[i], fit_page, options, &qp, printer_);
388  if (i != diagrams.count() - 1) {
389  printer_ -> newPage();
390  }
391  }
392 }
393 
402 void DiagramPrintDialog::printDiagram(Diagram *diagram, bool fit_page, const ExportProperties &options, QPainter *qp, QPrinter *printer) {
403  //qDebug() << printer -> paperSize() << printer -> paperRect() << diagram -> title();
404  // l'imprimante utilise-t-elle toute la feuille ?
405  bool full_page = printer -> fullPage();
406 
407  // impression physique (!= fichier PDF)
408  if (printer -> outputFileName().isEmpty()) {
409  // utiliser cette condition pour agir differemment en cas d'impression physique
410  }
411 
412  saveReloadDiagramParameters(diagram, options, true);
413 
414  // deselectionne tous les elements
415  QList<QGraphicsItem *> selected_elmts = diagram -> selectedItems();
416  foreach (QGraphicsItem *qgi, selected_elmts) qgi -> setSelected(false);
417 
418  // enleve le flag focusable de tous les elements concernes pour eviter toute reprise de focus par un champ de texte editable
419  QList<QGraphicsItem *> focusable_items;
420  foreach (QGraphicsItem *qgi, diagram -> items()) {
421  if (qgi -> flags() & QGraphicsItem::ItemIsFocusable) {
422  focusable_items << qgi;
423  qgi -> setFlag(QGraphicsItem::ItemIsFocusable, false);
424  }
425  }
426 
427  // evite toute autre forme d'interaction
428  foreach (QGraphicsView *view, diagram -> views()) {
429  view -> setInteractive(false);
430  }
431 
432  QRect diagram_rect = diagramRect(diagram, options);
433  if (fit_page) {
434  // impression adaptee sur une seule page
435  diagram -> render(qp, QRectF(), diagram_rect, Qt::KeepAspectRatio);
436  } else {
437  // impression sur une ou plusieurs pages
438  QRect printed_area = full_page ? printer -> paperRect() : printer -> pageRect();
439  //qDebug() << "impression sur une ou plusieurs pages";
440  //qDebug() << " schema :" << diagram_rect;
441  //qDebug() << " page :" << printed_area;
442 
443  int used_width = printed_area.width();
444  int used_height = printed_area.height();
445  int h_pages_count = horizontalPagesCount(diagram, options, full_page);
446  int v_pages_count = verticalPagesCount(diagram, options, full_page);
447 
448  QVector< QVector< QRect > > pages_grid;
449  // le schema est imprime sur une matrice de feuilles
450  // parcourt les lignes de la matrice
451  int y_offset = 0;
452  for (int i = 0 ; i < v_pages_count ; ++ i) {
453  pages_grid << QVector< QRect >();
454 
455  // parcourt les feuilles de la ligne
456  int x_offset = 0;
457  for (int j = 0 ; j < h_pages_count ; ++ j) {
458  pages_grid.last() << QRect(
459  QPoint(x_offset, y_offset),
460  QSize(
461  qMin(used_width, diagram_rect.width() - x_offset),
462  qMin(used_height, diagram_rect.height() - y_offset)
463  )
464  );
465  x_offset += used_width;
466  }
467 
468  y_offset += used_height;
469  }
470 
471  // ne retient que les pages a imprimer
472  QVector<QRect> pages_to_print;
473  for (int i = 0 ; i < v_pages_count ; ++ i) {
474  for (int j = 0 ; j < h_pages_count ; ++ j) {
475  pages_to_print << pages_grid.at(i).at(j);
476  }
477  }
478  //qDebug() << " " << pages_to_print.count() << " pages a imprimer :";
479 
480  // parcourt les pages pour impression
481  for (int i = 0 ; i < pages_to_print.count() ; ++ i) {
482  QRect current_rect(pages_to_print.at(i));
483  //qDebug() << " " << current_rect;
484  diagram -> render(
485  qp,
486  QRect(QPoint(0,0), current_rect.size()),
487  current_rect.translated(diagram_rect.topLeft()),
488  Qt::KeepAspectRatio
489  );
490  if (i != pages_to_print.count() - 1) {
491  printer -> newPage();
492  }
493  }
494  }
495 
496  // remet en place les interactions
497  foreach (QGraphicsView *view, diagram -> views()) {
498  view -> setInteractive(true);
499  }
500 
501  // restaure les flags focusable
502  foreach (QGraphicsItem *qgi, focusable_items) {
503  qgi -> setFlag(QGraphicsItem::ItemIsFocusable, true);
504  }
505 
506  // restaure les elements selectionnes
507  foreach (QGraphicsItem *qgi, selected_elmts) qgi -> setSelected(true);
508 
509  saveReloadDiagramParameters(diagram, options, false);
510 }
511 
520  static ExportProperties state_exportProperties;
521 
522  if (save) {
523  // memorise les parametres relatifs au schema tout en appliquant les nouveaux
524  state_exportProperties = diagram -> applyProperties(options);
525  } else {
526  // restaure les parametres relatifs au schema
527  diagram -> applyProperties(state_exportProperties);
528  }
529 }
530 
537 {
538  QSettings settings;
539  QString printer_section = settingsSectionName(printer_);
540 
541  while (!settings.group().isEmpty()) settings.endGroup();
542  settings.beginGroup("printers");
543  settings.beginGroup(printer_section);
544 
545  settings.setValue("orientation", printer_ -> orientation() == QPrinter::Portrait ? "portrait" : "landscape");
546  settings.setValue("papersize", int(printer_ -> paperSize()));
547  if (printer_ -> paperSize() == QPrinter::Custom) {
548  QSizeF size = printer_ -> paperSize(QPrinter::Millimeter);
549  settings.setValue("customwidthmm", size.width());
550  settings.setValue("customheightmm", size.height());
551  } else {
552  settings.remove("customwidthmm");
553  settings.remove("customheightmm");
554  }
555  qreal left, top, right, bottom;
556  printer_ -> getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter);
557  settings.setValue("marginleft", left);
558  settings.setValue("margintop", top);
559  settings.setValue("marginright", right);
560  settings.setValue("marginbottom", bottom);
561  settings.setValue("fullpage", printer_ -> fullPage() ? "true" : "false");
562  settings.endGroup();
563  settings.endGroup();
564  settings.sync();
565 }
566 
567 
573 {
574  QSettings settings;
575  QString printer_section = settingsSectionName(printer_);
576 
577  while (!settings.group().isEmpty()) settings.endGroup();
578  settings.beginGroup("printers");
579  if (!settings.childGroups().contains(printer_section)) {
580  settings.endGroup();
581  return;
582  }
583 
584  settings.beginGroup(printer_section);
585  if (settings.contains("orientation")) {
586  QString value = settings.value("orientation", "landscape").toString();
587  printer_ -> setOrientation(value == "landscape" ? QPrinter::Landscape : QPrinter::Portrait);
588  }
589  if (settings.contains("papersize")) {
590  int value = settings.value("papersize", QPrinter::A4).toInt();
591  if (value == QPrinter::Custom) {
592  bool w_ok, h_ok;
593  int w = settings.value("customwidthmm", -1).toInt(&w_ok);
594  int h = settings.value("customheightmm", -1).toInt(&h_ok);
595  if (w_ok && h_ok && w != -1 && h != -1) {
596  printer_ -> setPaperSize(QSizeF(w, h), QPrinter::Millimeter);
597  }
598  } else if (value < QPrinter::Custom) {
599  printer_ -> setPaperSize(static_cast<QPrinter::PaperSize>(value));
600  }
601  }
602 
603  qreal margins[4];
604  printer_ -> getPageMargins(&margins[0], &margins[1], &margins[2], &margins[3], QPrinter::Millimeter);
605  QStringList margins_names(QStringList() << "left" << "top" << "right" << "bottom");
606  for (int i = 0 ; i < 4 ; ++ i) {
607  bool conv_ok;
608  qreal value = settings.value("margin" + margins_names.at(i), -1.0).toReal(&conv_ok);
609  if (conv_ok && value != -1.0) margins[i] = value;
610  }
611  printer_ -> setPageMargins(margins[0], margins[1], margins[2], margins[3], QPrinter::Millimeter);
612  printer_ -> setFullPage(settings.value("fullpage", "false").toString() == "true");
613 
614  settings.endGroup();
615  settings.endGroup();
616 }
617 
622 QString DiagramPrintDialog::settingsSectionName(const QPrinter *printer) {
623  QPrinter::OutputFormat printer_format = printer -> outputFormat();
624  if (printer_format == QPrinter::NativeFormat) {
625  return(printer -> printerName().replace(" ", "_"));
626  } else if (printer_format == QPrinter::PdfFormat) {
627  return("QET_PDF_Printing");
628  }
629  return(QString());
630 }
ExportProperties exportProperties() const
DiagramPrintDialog(QETProject *, QWidget *=nullptr)
QColor backup_diagram_background_color
From user collection.
Definition: qet.h:152
DiagramsChooser * diagramsChooser()
void printDiagram(Diagram *, bool, const ExportProperties &, QPainter *, QPrinter *=nullptr)
QString settingsSectionName(const QPrinter *)
QDialogButtonBox * buttons_
const QString displayedVersion
QElectroTech displayed version.
Definition: qet.h:32
void saveReloadDiagramParameters(Diagram *, const ExportProperties &, bool)
QRadioButton * pdf_choice_
void print(const QList< Diagram *> &, bool, const ExportProperties &)
int horizontalPagesCount(Diagram *, const ExportProperties &, bool=false) const
QIcon Printer
Definition: qeticons.cpp:139
QRect diagramRect(Diagram *, const ExportProperties &) const
QPushButton * browse_button_
int pagesCount(Diagram *, const ExportProperties &, bool=false) const
QIcon tr
Definition: qeticons.cpp:204
QRadioButton * printer_choice_
bool draw_titleblock
Whether to render the title block.
QIcon PDF
Definition: qeticons.cpp:136
static QColor background_color
background color of diagram
Definition: diagram.h:91
QString docName() const
QGridLayout * glayout0_
QButtonGroup * printtype_choice_
int verticalPagesCount(Diagram *, const ExportProperties &, bool=false) const
QIcon Cancel
Definition: qeticons.cpp:34
QString fileName() const
QMessageBox::StandardButton information(QWidget *, const QString &, const QString &, QMessageBox::StandardButtons=QMessageBox::Ok, QMessageBox::StandardButton=QMessageBox::NoButton)
QHBoxLayout * hlayout0_
QVBoxLayout * vlayout0_
QLineEdit * filepath_field_
void setFileName(const QString &)
void setDocName(const QString &)