QElectroTech  0.70
templateview.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 "templateview.h"
19 #include "templatevisualcell.h"
20 #include "gridlayoutanimation.h"
21 #include "helpercell.h"
22 #include "splittedhelpercell.h"
23 #include "templatecommands.h"
24 #include "templatecellsset.h"
25 #include "dimensionwidget.h"
26 #include "qeticons.h"
27 #define ROW_OFFSET 2
28 #define COL_OFFSET 1
29 #define DEFAULT_PREVIEW_WIDTH 600
30 #define DEFAULT_PREVIEW_HELPER_CELL_HEIGHT 15
31 #define DEFAULT_COLS_HELPER_CELLS_HEIGHT 15
32 #define DEFAULT_ROWS_HELPER_CELLS_WIDTH 50
33 
34 
35 
41  QGraphicsView(parent),
42  tbtemplate_(nullptr),
43  tbgrid_(nullptr),
44  form_(nullptr),
45  preview_width_(DEFAULT_PREVIEW_WIDTH),
46  apply_columns_widths_count_(0),
47  apply_rows_heights_count_(0),
48  first_activation_(true),
49  read_only_(false)
50 {
51  init();
52 }
53 
58 TitleBlockTemplateView::TitleBlockTemplateView(QGraphicsScene *scene, QWidget *parent) :
59  QGraphicsView(scene, parent),
60  tbtemplate_(nullptr),
61  tbgrid_(nullptr),
62  preview_width_(DEFAULT_PREVIEW_WIDTH),
63  apply_columns_widths_count_(0),
64  apply_rows_heights_count_(0),
65  first_activation_(true),
66  read_only_(false)
67 {
68  init();
69 }
70 
75 }
76 
82  loadTemplate(tbtemplate);
83  zoomFit();
84 }
85 
90  return(tbtemplate_);
91 }
92 
98 }
99 
105  scale(zoomFactor(), zoomFactor());
106 }
107 
113  qreal zoom_factor = 1.0/zoomFactor();
114  scale(zoom_factor, zoom_factor);
115 }
116 
121  adjustSceneRect();
122  fitInView(scene() -> sceneRect(), Qt::KeepAspectRatio);
123 }
124 
129  adjustSceneRect();
130  resetMatrix();
131 }
132 
138 QList<TitleBlockCell *> TitleBlockTemplateView::cut() {
139  if (!tbtemplate_) return(QList<TitleBlockCell *>());
140  QList<TitleBlockCell *> copied_cells = copy();
141 
142  if (!copied_cells.isEmpty()) {
144  cut_command -> setCutCells(copied_cells);
145  requestGridModification(cut_command);
146  }
147  return(copied_cells);
148 }
149 
154 QList<TitleBlockCell *> TitleBlockTemplateView::copy() {
155  if (!tbtemplate_) return(QList<TitleBlockCell *>());
156  QList<TitleBlockCell *> copied_cells = selectedCells();
157 
158  QDomDocument xml_export;
159  QDomElement tbtpartial = xml_export.createElement("titleblocktemplate-partial");
160  xml_export.appendChild(tbtpartial);
161  foreach (TitleBlockCell *cell, copied_cells) {
162  tbtemplate_ -> exportCellToXml(cell, tbtpartial);
163  tbtpartial.setAttribute("row", cell -> num_row);
164  tbtpartial.setAttribute("col", cell -> num_col);
165  tbtpartial.setAttribute("row_span", cell -> row_span);
166  tbtpartial.setAttribute("col_span", cell -> col_span);
167  }
168 
169  QClipboard *clipboard = QApplication::clipboard();
170  clipboard -> setText(xml_export.toString());
171 
172  return(copied_cells);
173 }
174 
179  // retrieve the clipboard content
180  QClipboard *clipboard = QApplication::clipboard();
181  return(clipboard -> text().contains("<titleblocktemplate-partial"));
182 }
183 
187 QList<TitleBlockCell> TitleBlockTemplateView::pastedCells() {
188  QList<TitleBlockCell> pasted_cells;
189 
190  // retrieve the clipboard content and parse it as XML
191  QClipboard *clipboard = QApplication::clipboard();
192  QDomDocument xml_import;
193 
194  if (!xml_import.setContent(clipboard -> text().trimmed())) {
195  return(pasted_cells);
196  }
197 
198  // ensure the XML document describes cells that can be pasted
199  if (xml_import.documentElement().tagName() != "titleblocktemplate-partial") {
200  return(pasted_cells);
201  }
202 
203  // load pasted cells
204  QDomElement paste_root = xml_import.documentElement();
205  for (QDomElement e = paste_root.firstChildElement() ; !e.isNull() ; e = e.nextSiblingElement()) {
206  if (e.tagName() == "empty" || e.tagName() == "field" || e.tagName() == "logo") {
207  TitleBlockCell cell;
208  cell.loadContentFromXml(e);
209  int row_num = -1, col_num = -1, row_span = -1, col_span = -1;
210  if (!QET::attributeIsAnInteger(e, "row", &row_num) || row_num < 0) {
211  continue;
212  }
213  if (!QET::attributeIsAnInteger(e, "col", &col_num) || col_num < 0) {
214  continue;
215  }
216  cell.num_row = row_num;
217  cell.num_col = col_num;
218 
219  // parse the rowspan and colspan attributes
220  if (QET::attributeIsAnInteger(e, "rowspan", &row_span) && row_span > 0) {
221  cell.row_span = row_span;
222  }
223 
224  if (QET::attributeIsAnInteger(e, "colspan", &col_span) && col_span > 0) {
225  cell.col_span = col_span;
226  }
227  pasted_cells << cell;
228  }
229  }
230  return(pasted_cells);
231 }
232 
237  if (!tbtemplate_) return;
238  QList<TitleBlockCell> pasted_cells = pastedCells();
239  if (!pasted_cells.count()) return;
240 
241  // the top left cell among the selected ones will be used to position the pasted cells
243  if (!selected_cell) return;
244  TitleBlockCell *erased_cell = selected_cell -> cell();
245  if (!erased_cell) return;
246 
247  // change num_row and num_col attributes of pasted cells so they get positionned relatively to selected_cell
248  normalizeCells(pasted_cells, erased_cell -> num_row, erased_cell -> num_col);
249 
251  foreach (TitleBlockCell cell, pasted_cells) {
252  TitleBlockCell *erased_cell = tbtemplate_ -> cell(cell.num_row, cell.num_col);
253  if (!erased_cell) continue;
254  paste_command -> addCell(erased_cell, *erased_cell, cell);
255  }
256 
257  requestGridModification(paste_command);
258 }
259 
264  if (read_only_) return;
266 }
267 
272  if (read_only_) return;
274 }
275 
281  if (read_only_) return;
282  int index = lastContextMenuCellIndex();
283  if (index == -1) return;
285 }
286 
292  if (read_only_) return;
293  int index = lastContextMenuCellIndex();
294  if (index == -1) return;
296 }
297 
303  if (read_only_) return;
304  int index = lastContextMenuCellIndex();
305  if (index == -1) return;
307 }
308 
314  if (read_only_) return;
315  int index = lastContextMenuCellIndex();
316  if (index == -1) return;
318 }
319 
326  int index = cell ? cell -> index : lastContextMenuCellIndex();
327  if (index == -1) return;
328 
329  TitleBlockDimension dimension_before = tbtemplate_ -> columnDimension(index);
330  TitleBlockDimensionWidget dialog(true, this);
331  dialog.setReadOnly(read_only_);
332  dialog.setWindowTitle(tr("Changer la largeur de la colonne", "window title when changing a column with"));
333  dialog.label() -> setText(tr("Largeur :", "text before the spinbox to change a column width"));
334  dialog.setValue(dimension_before);
335  int user_answer = dialog.exec();
336  if (!read_only_ && user_answer == QDialog::Accepted) {
338  command -> setType(false);
339  command -> setIndex(index);
340  command -> setDimensionBefore(dimension_before);
341  command -> setDimensionAfter(dialog.value());
342  requestGridModification(command);
343  }
344 }
345 
352  int index = cell ? cell -> index : lastContextMenuCellIndex();
353  if (index == -1) return;
354 
355  TitleBlockDimension dimension_before = TitleBlockDimension(tbtemplate_ -> rowDimension(index));
356  TitleBlockDimensionWidget dialog(false, this);
357  dialog.setReadOnly(read_only_);
358  dialog.setWindowTitle(tr("Changer la hauteur de la ligne", "window title when changing a row height"));
359  dialog.label() -> setText(tr("Hauteur :", "text before the spinbox to change a row height"));
360  dialog.setValue(dimension_before);
361  int user_answer = dialog.exec();
362  if (!read_only_ && user_answer == QDialog::Accepted) {
364  command -> setType(true);
365  command -> setIndex(index);
366  command -> setDimensionBefore(dimension_before);
367  command -> setDimensionAfter(dialog.value());
368  requestGridModification(command);
369  }
370 }
371 
376  int index = lastContextMenuCellIndex();
377  if (index == -1) return;
379 }
380 
385  int index = lastContextMenuCellIndex();
386  if (index == -1) return;
388 }
389 
394  // retrieve the selected cells
395  TitleBlockTemplateCellsSet selected_cells = selectedCellsSet();
396 
397  MergeCellsCommand *merge_command = new MergeCellsCommand(selected_cells, tbtemplate_);
398  if (merge_command -> isValid()) requestGridModification(merge_command);
399 }
400 
405  // retrieve the selected cells
406  TitleBlockTemplateCellsSet selected_cells = selectedCellsSet();
407 
408  SplitCellsCommand *split_command = new SplitCellsCommand(selected_cells, tbtemplate_);
409  if (split_command -> isValid()) requestGridModification(split_command);
410 }
411 
416 void TitleBlockTemplateView::drawBackground(QPainter *painter, const QRectF &rect) {
417  QGraphicsView::drawBackground(painter, rect);
418  if (!tbtemplate_) return; // TODO shouldn't we draw a large uniform rect?
419 }
420 
424 QList<TitleBlockCell *> TitleBlockTemplateView::selectedCells() const {
425  return(selectedCellsSet().cells(false).toList());
426 }
427 
432  return(makeCellsSetFromGraphicsItems(scene() -> selectedItems()));
433 }
434 
441  QPolygonF mapped_rect(form_ -> mapToScene(rect));
442  QList<QGraphicsItem *> items = scene() -> items(mapped_rect, Qt::IntersectsItemShape);
443  return(makeCellsSetFromGraphicsItems(items));
444 }
445 
451 void TitleBlockTemplateView::analyzeSelectedCells(bool *can_merge, bool *can_split, int *count) {
452  if (!can_merge && !can_split) return;
453 
454  if (!tbtemplate_) {
455  if (can_merge) *can_merge = false;
456  if (can_split) *can_split = false;
457  return;
458  }
459 
460  // retrieve the selected cells
461  TitleBlockTemplateCellsSet selected_cells = selectedCellsSet();
462 
463  if (can_merge) {
464  *can_merge = MergeCellsCommand::canMerge(selected_cells, tbtemplate_);
465  }
466  if (can_split) {
467  *can_split = SplitCellsCommand::canSplit(selected_cells, tbtemplate_);
468  }
469  if (count) {
470  *count = selectedCellsSet().count();
471  }
472 }
473 
478  return(QSizeF(templateWidth(), templateHeight()));
479 }
480 
485  if (!tbtemplate_) return(0);
486 
487  qreal width = DEFAULT_ROWS_HELPER_CELLS_WIDTH;
488  // the rendered width may exceed the initially planned preview width
489  width += qMax<int>(preview_width_, tbtemplate_ -> width(preview_width_));
490 
491  return(width);
492 }
493 
498  if (!tbtemplate_) return(0);
499 
500  qreal height = DEFAULT_PREVIEW_HELPER_CELL_HEIGHT;
502  height += tbtemplate_ -> height();
503 
504  return(height);
505 }
506 
512  // si la touche Ctrl est enfoncee, on zoome / dezoome
513  if (e -> modifiers() & Qt::ControlModifier) {
514  if (e -> delta() > 0) {
515  zoomIn();
516  } else {
517  zoomOut();
518  }
519  } else {
520  QAbstractScrollArea::wheelEvent(e);
521  }
522 }
523 
528  return(1.1);
529 }
530 
535  add_column_before_ = new QAction(QET::Icons::EditTableInsertColumnLeft, tr("Ajouter une colonne (avant)", "context menu"), this);
536  add_row_before_ = new QAction(QET::Icons::EditTableInsertRowAbove, tr("Ajouter une ligne (avant)", "context menu"), this);
537  add_column_after_ = new QAction(QET::Icons::EditTableInsertColumnRight, tr("Ajouter une colonne (après)", "context menu"), this);
538  add_row_after_ = new QAction(QET::Icons::EditTableInsertRowUnder, tr("Ajouter une ligne (après)", "context menu"), this);
539  edit_column_dim_ = new QAction( tr("Modifier les dimensions de cette colonne", "context menu"), this);
540  edit_row_dim_ = new QAction( tr("Modifier les dimensions de cette ligne", "context menu"), this);
541  delete_column_ = new QAction(QET::Icons::EditTableDeleteColumn, tr("Supprimer cette colonne", "context menu"), this);
542  delete_row_ = new QAction(QET::Icons::EditTableDeleteRow, tr("Supprimer cette ligne", "context menu"), this);
543  change_preview_width_ = new QAction( tr("Modifier la largeur de cet aperçu", "context menu"), this);
544 
545  connect(add_column_before_, SIGNAL(triggered()), this, SLOT(addColumnBefore()));
546  connect(add_row_before_, SIGNAL(triggered()), this, SLOT(addRowBefore()));
547  connect(add_column_after_, SIGNAL(triggered()), this, SLOT(addColumnAfter()));
548  connect(add_row_after_, SIGNAL(triggered()), this, SLOT(addRowAfter()));
549  connect(edit_column_dim_, SIGNAL(triggered()), this, SLOT(editColumn()));
550  connect(edit_row_dim_, SIGNAL(triggered()), this, SLOT(editRow()));
551  connect(delete_column_, SIGNAL(triggered()), this, SLOT(deleteColumn()));
552  connect(delete_row_, SIGNAL(triggered()), this, SLOT(deleteRow()));
553  connect(change_preview_width_, SIGNAL(triggered()), this, SLOT(changePreviewWidth()));
554 
555  setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
556  setBackgroundBrush(QBrush(QColor(248, 255, 160)));
557 
558  connect(scene(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
559 }
560 
567  // the first column is dedicated to helper cells showing the rows height
568  tbgrid_ -> setColumnFixedWidth(0, DEFAULT_ROWS_HELPER_CELLS_WIDTH);
569  tbgrid_ -> setColumnSpacing(0, 0);
570 
571  // we apply the other columns width based on the title block template data
572  QList<int> widths = tbtemplate_ -> columnsWidth(preview_width_);
573  int total_applied_width = 0;
574  for (int i = 0 ; i < widths.count() ; ++ i) {
575  int applied_width = qMax(0, widths.at(i));
576  tbgrid_ -> setColumnSpacing(COL_OFFSET + i, 0);
577  if (!animate) {
578  // no animation on first call
579  tbgrid_ -> setColumnFixedWidth(COL_OFFSET + i, widths.at(i));
580  } else {
582  animation -> setIndex(COL_OFFSET + i);
583  animation -> setActsOnRows(false);
584  animation -> setStartValue(QVariant(tbgrid_ -> columnMinimumWidth(COL_OFFSET + i)));
585  animation -> setEndValue(QVariant(1.0 * applied_width));
586  animation -> setDuration(500);
587  connect(animation, SIGNAL(finished()), this, SLOT(updateColumnsHelperCells()));
588  animation -> start(QAbstractAnimation::DeleteWhenStopped);
589  }
590  total_applied_width += applied_width;
591  }
592  if (!animate) updateColumnsHelperCells();
594 
595  // we systematically parameter some cells
596  total_width_helper_cell_ -> split_size = 0;
597  tbgrid_ -> addItem(total_width_helper_cell_, 0, COL_OFFSET, 1, widths.count());
599 
600  if (total_applied_width < preview_width_) {
601  // preview_width is greater than the sum of cells widths
602  // we add an extra column with a helper cell
603  tbgrid_ -> addItem(extra_cells_width_helper_cell_, ROW_OFFSET - 1, COL_OFFSET + widths.count(), tbtemplate_ -> rowsCount() + 1, 1);
604  tbgrid_ -> addItem(total_width_helper_cell_, 0, COL_OFFSET, 1, widths.count() + 1);
605  tbgrid_ -> setColumnFixedWidth(COL_OFFSET + widths.count(), preview_width_ - total_applied_width);
606  extra_cells_width_helper_cell_ -> setLabel(
607  QString(
608  tr("[%1px]","content of the extra cell added when the total width of cells is less than the preview width")
609  ).arg(preview_width_ - total_applied_width)
610  );
611  } else if (total_applied_width > preview_width_) {
612  // preview width is smaller than the sum of cells widths
613  // we draw an extra header within th "preview width" cell.
614  tbgrid_ -> addItem(total_width_helper_cell_, 0, COL_OFFSET, 1, widths.count());
615  total_width_helper_cell_ -> split_background_color = QColor(Qt::red);
616  total_width_helper_cell_ -> split_foreground_color = QColor(Qt::black);
617  total_width_helper_cell_ -> split_label = QString(
618  tr("[%1px]", "content of the extra helper cell added when the total width of cells is greather than the preview width")
619  ).arg(total_applied_width - preview_width_);
620  total_width_helper_cell_ -> split_size = total_applied_width - preview_width_;
621  }
622 
624 }
625 
632  // the first row is dedicated to a helper cell showing the total width
633  tbgrid_ -> setRowFixedHeight(0, DEFAULT_PREVIEW_HELPER_CELL_HEIGHT);
634  tbgrid_ -> setRowSpacing(0, 0);
635  // the second row is dedicated to helper cells showing the columns width
636  tbgrid_ -> setRowFixedHeight(1, DEFAULT_COLS_HELPER_CELLS_HEIGHT);
637  tbgrid_ -> setRowSpacing(1, 0);
638 
639  QList<int> heights = tbtemplate_ -> rowsHeights();
640  for (int i = 0 ; i < heights.count() ; ++ i) {
641  tbgrid_ -> setRowSpacing(ROW_OFFSET + i, 0);
642  if (!animate) {
643  // no animation on first call
644  tbgrid_ -> setRowFixedHeight(ROW_OFFSET + i, heights.at(i));
645  } else {
647  animation -> setIndex(ROW_OFFSET + i);
648  animation -> setActsOnRows(true);
649  animation -> setStartValue(QVariant(tbgrid_ -> rowMinimumHeight(ROW_OFFSET + i)));
650  animation -> setEndValue(QVariant(1.0 * heights.at(i)));
651  animation -> setDuration(500);
652  connect(animation, SIGNAL(finished()), this, SLOT(updateRowsHelperCells()));
653  animation -> start(QAbstractAnimation::DeleteWhenStopped);
654  }
655 
656  }
657  if (!animate) updateRowsHelperCells();
659 }
660 
665  int row_count = tbtemplate_ -> rowsCount();
666  QList<int> heights = tbtemplate_ -> rowsHeights();
667  for (int i = 0 ; i < row_count ; ++ i) {
668  HelperCell *current_row_cell = static_cast<HelperCell *>(tbgrid_ -> itemAt(ROW_OFFSET + i, 0));
669  if (current_row_cell) {
670  current_row_cell -> setType(QET::Absolute); // rows always have absolute heights
671  current_row_cell -> setLabel(QString(tr("%1px", "format displayed in rows helper cells")).arg(heights.at(i)));
672  }
673  }
674 }
675 
680  int col_count = tbtemplate_ -> columnsCount();
681  for (int i = 0 ; i < col_count ; ++ i) {
682  TitleBlockDimension current_col_dim = tbtemplate_ -> columnDimension(i);
683  HelperCell *current_col_cell = static_cast<HelperCell *>(tbgrid_ -> itemAt(1, COL_OFFSET + i));
684  if (current_col_cell) {
685  current_col_cell -> setType(current_col_dim.type);
686  current_col_cell -> setLabel(current_col_dim.toString());
687  }
688  }
689 }
690 
696  int col_count = tbtemplate_ -> columnsCount();
697  int row_count = tbtemplate_ -> rowsCount();
698 
699  // we add a big cell to show the total width
703  total_width_helper_cell_ -> orientation = Qt::Horizontal;
704  total_width_helper_cell_ -> setActions(QList<QAction *>() << change_preview_width_);
705  connect(total_width_helper_cell_, SIGNAL(contextMenuTriggered(HelperCell *)), this, SLOT(updateLastContextMenuCell(HelperCell *)));
706  connect(total_width_helper_cell_, SIGNAL(doubleClicked(HelperCell*)), this, SLOT(changePreviewWidth()));
707  tbgrid_ -> addItem(total_width_helper_cell_, 0, COL_OFFSET, 1, col_count);
708 
709  // we also initialize an extra helper cells that shows the preview width is
710  // too long for the current cells widths
712  extra_cells_width_helper_cell_ -> background_color = QColor(Qt::red);
713 
714  // we add one cell per column to show their respective width
715  for (int i = 0 ; i < col_count ; ++ i) {
716  TitleBlockDimension current_col_dim = tbtemplate_ -> columnDimension(i);
717  HelperCell *current_col_cell = new HelperCell();
718  current_col_cell -> setType(current_col_dim.type);
719  current_col_cell -> setLabel(current_col_dim.toString());
720  current_col_cell -> setActions(columnsActions());
721  current_col_cell -> orientation = Qt::Horizontal;
722  current_col_cell -> index = i;
723  connect(current_col_cell, SIGNAL(contextMenuTriggered(HelperCell *)), this, SLOT(updateLastContextMenuCell(HelperCell *)));
724  connect(current_col_cell, SIGNAL(doubleClicked(HelperCell*)), this, SLOT(editColumn(HelperCell *)));
725  tbgrid_ -> addItem(current_col_cell, 1, COL_OFFSET + i, 1, 1);
726  }
727 
728  // we add one cell per row to show their respective height
729  QList<int> heights = tbtemplate_ -> rowsHeights();
730  for (int i = 0 ; i < row_count ; ++ i) {
731  HelperCell *current_row_cell = new HelperCell();
732  current_row_cell -> setType(QET::Absolute); // rows always have absolute heights
733  current_row_cell -> setLabel(QString(tr("%1px")).arg(heights.at(i)));
734  current_row_cell -> orientation = Qt::Vertical;
735  current_row_cell -> index = i;
736  current_row_cell -> setActions(rowsActions());
737  connect(current_row_cell, SIGNAL(contextMenuTriggered(HelperCell *)), this, SLOT(updateLastContextMenuCell(HelperCell *)));
738  connect(current_row_cell, SIGNAL(doubleClicked(HelperCell*)), this, SLOT(editRow(HelperCell *)));
739  tbgrid_ -> addItem(current_row_cell, ROW_OFFSET + i, 0, 1, 1);
740  }
741 
742  // eventually we add the cells composing the titleblock template
743  for (int i = 0 ; i < col_count ; ++ i) {
744  for (int j = 0 ; j < row_count ; ++ j) {
745  TitleBlockCell *cell = tbtemplate_ -> cell(j, i);
746  if (cell -> spanner_cell) continue;
748  cell_item -> setTemplateCell(tbtemplate_, cell);
749 
750  int row_span = 0, col_span = 0;
751  if (cell -> span_state != TitleBlockCell::Disabled) {
752  row_span = cell -> applied_row_span;
753  col_span = cell -> applied_col_span;
754  }
755  tbgrid_ -> addItem(cell_item, ROW_OFFSET + j, COL_OFFSET + i, row_span + 1, col_span + 1);
756  }
757  }
758 }
759 
764  int col_count = tbtemplate_ -> columnsCount();
765  int row_count = tbtemplate_ -> rowsCount();
766  if (row_count < 1 || col_count < 1) return;
767 
768  for (int i = 0 ; i < col_count ; ++ i) {
769  for (int j = 0 ; j < row_count ; ++ j) {
770  if (QGraphicsLayoutItem *item = tbgrid_ -> itemAt(ROW_OFFSET + j, COL_OFFSET + i)) {
771  if (QGraphicsItem *qgi = dynamic_cast<QGraphicsItem *>(item)) {
772  qgi -> update();
773  }
774  }
775  }
776  }
777 }
778 
783  TitleBlockDimensionWidget dialog(false, this);
784  dialog.setWindowTitle(tr("Changer la largeur de l'aperçu"));
785  dialog.label() -> setText(tr("Largeur de l'aperçu :"));
787  if (dialog.exec() == QDialog::Accepted) {
788  setPreviewWidth(dialog.value().value);
789  }
790 }
791 
796  int col_count = tbtemplate_ -> columnsCount();
797  int row_count = tbtemplate_ -> rowsCount();
798  if (row_count < 1 || col_count < 1) return;
799 
800  for (int i = 0 ; i < col_count ; ++ i) {
801  for (int j = 0 ; j < row_count ; ++ j) {
802  if (tbgrid_ -> itemAt(ROW_OFFSET + j, COL_OFFSET + i)) continue;
804  if (TitleBlockCell *target_cell = tbtemplate_ -> cell(j, i)) {
805  qDebug() << Q_FUNC_INFO << "target_cell" << target_cell;
806  cell_item -> setTemplateCell(tbtemplate_, target_cell);
807  }
808  tbgrid_ -> addItem(cell_item, ROW_OFFSET + j, COL_OFFSET + i);
809  }
810  }
811 }
812 
816 bool TitleBlockTemplateView::event(QEvent *event) {
817  if (first_activation_ && event -> type() == QEvent::WindowActivate) {
818  QTimer::singleShot(250, this, SLOT(zoomFit()));
819  first_activation_ = false;
820  }
821  return(QGraphicsView::event(event));
822 }
823 
828 void TitleBlockTemplateView::normalizeCells(QList<TitleBlockCell> &cells, int x, int y) const {
829  if (!cells.count()) return;
830 
831  int min_row = cells.at(0).num_row;
832  int min_col = cells.at(0).num_col;
833  for (int i = 1 ; i < cells.count() ; ++ i) {
834  if (cells.at(i).num_row < min_row) min_row = cells.at(i).num_row;
835  if (cells.at(i).num_col < min_col) min_col = cells.at(i).num_col;
836  }
837  for (int i = 0 ; i < cells.count() ; ++ i) {
838  cells[i].num_row = cells[i].num_row - min_row + x;
839  cells[i].num_col = cells[i].num_col - min_col + y;
840  }
841 }
842 
849  if (tbgrid_) {
850  scene() -> removeItem(form_);
851  // also deletes TemplateCellPreview because, according to the
852  // documentation, QGraphicsGridLayout takes ownership of the items.
853  form_ -> deleteLater();
854  }
855  if (tbtemplate_ && tbtemplate_ != tbt) {
856  delete tbtemplate_;
857  }
858 
859  tbtemplate_ = tbt;
860 
861  // initialize a grid layout with no margin
862  tbgrid_ = new QGraphicsGridLayout();
863  tbgrid_ -> setContentsMargins(0, 0, 0, 0);
864  // add cells defined by the title block template in this layout
865  addCells();
866  // fill potential holes in the grid with empty cells
868  // apply rows and columns dimensions
869  applyColumnsWidths(false);
870  applyRowsHeights(false);
871 
872  // assign the layout to a basic QGraphicsWidget
873  form_ = new QGraphicsWidget();
874  // enforce the layout direction to avoid reversing the template rendering
875  form_ -> setLayoutDirection(Qt::LeftToRight);
876  form_ -> setLayout(tbgrid_);
877  scene() -> addItem(form_);
878  adjustSceneRect();
879 }
880 
884 QList<QAction *> TitleBlockTemplateView::rowsActions() const {
885  return QList<QAction *>() << add_row_before_<< edit_row_dim_ << add_row_after_ << delete_row_;
886 }
887 
891 QList<QAction *> TitleBlockTemplateView::columnsActions() const {
892  return QList<QAction *>() << add_column_before_ << edit_column_dim_ << add_column_after_ << delete_column_;
893 }
894 
901  // TODO we should try to update the grid instead of deleting-and-reloading it
903 }
904 
911 }
912 
919 }
920 
926  if (!tbtemplate_) return;
927  int min_width = tbtemplate_ -> minimumWidth();
928  int max_width = tbtemplate_ -> maximumWidth();
929 
930  QString min_max_width_sentence;
931  if (max_width != -1) {
932  min_max_width_sentence = QString(
933  tr(
934  "Longueur minimale : %1px\nLongueur maximale : %2px\n",
935  "tooltip showing the minimum and/or maximum width of the edited template"
936  )
937  ).arg(min_width).arg(max_width);
938  } else {
939  min_max_width_sentence = QString(
940  tr(
941  "Longueur minimale : %1px\n",
942  "tooltip showing the minimum width of the edited template"
943  )
944  ).arg(min_width);
945  }
946 
947  // the tooltip may also display the split label for readability purpose
948  if (total_width_helper_cell_ -> split_size) {
949  min_max_width_sentence += "---\n";
950  min_max_width_sentence += total_width_helper_cell_ -> split_label;
951  }
952 
953  total_width_helper_cell_ -> setToolTip(makePrettyToolTip(min_max_width_sentence));
954 }
955 
961  if (read_only_ == read_only) return;
962 
963  read_only_ = read_only;
964  add_column_before_ -> setEnabled(!read_only_);
965  add_row_before_ -> setEnabled(!read_only_);
966  add_column_after_ -> setEnabled(!read_only_);
967  add_row_after_ -> setEnabled(!read_only_);
968  delete_column_ -> setEnabled(!read_only_);
969  delete_row_ -> setEnabled(!read_only_);
970 }
971 
977  if (preview_width_ == width) return;
978  int former_preview_width = preview_width_;
979  preview_width_ = width;
980  if (tbgrid_) {
983  //adjustSceneRect();
984  centerOn(form_);
985  }
986  emit(previewWidthChanged(former_preview_width, preview_width_));
987 }
988 
993  if (!total_width_helper_cell_) return;
994  total_width_helper_cell_ -> label = QString(
995  tr(
996  "Largeur totale pour cet aperçu : %1px",
997  "displayed at the top of the preview when editing a title block template"
998  )
999  ).arg(preview_width_);
1000 }
1001 
1009  if (!command) return;
1010  command -> setView(this);
1011  emit(gridModificationRequested(command));
1012 }
1013 
1020  return(last_context_menu_cell_ -> index);
1021  }
1022  return(-1);
1023 }
1024 
1029 int TitleBlockTemplateView::indexOf(QGraphicsLayoutItem *item) {
1030  for (int i = 0 ; i < tbgrid_ -> count() ; ++i) {
1031  if (item == tbgrid_ -> itemAt(i)) return(i);
1032  }
1033  return(-1);
1034 }
1035 
1040 void TitleBlockTemplateView::removeItem(QGraphicsLayoutItem *item) {
1041  int index = indexOf(item);
1042  if (index != -1) {
1043  tbgrid_ -> removeAt(index);
1044  // trick: we also have to remove the item from the scene
1045  if (QGraphicsScene *current_scene = scene()) {
1046  if (QGraphicsItem *qgi = item -> graphicsItem()) {
1047  current_scene -> removeItem(qgi);
1048  }
1049  }
1050  }
1051 }
1052 
1058  TitleBlockTemplateCellsSet set(this);
1059  foreach (QGraphicsItem *item, items) {
1060  if (TitleBlockTemplateVisualCell *cell_view = dynamic_cast<TitleBlockTemplateVisualCell *>(item)) {
1061  if (cell_view -> cell() && cell_view -> cell() -> num_row != -1) {
1062  set << cell_view;
1063  }
1064  }
1065  }
1066  return(set);
1067 }
1068 
1069 /*
1070  @param a text string
1071  @return an HTML string that can be passed to setToolTip()
1072 */
1073 QString TitleBlockTemplateView::makePrettyToolTip(const QString &string) {
1074  QString css_style = QString("white-space: pre;");
1075 
1076  QString final_tooltip_content = QString(
1077  "<div style=\"%1\">%2</div>"
1078  ).arg(css_style).arg(string);
1079 
1080  return(final_tooltip_content);
1081 }
1082 
1088  last_context_menu_cell_ = last_context_menu_cell;
1089 }
1090 
1095  QRectF old_scene_rect = scene() -> sceneRect();
1096 
1097  // rectangle including everything on the scene
1098  QRectF bounding_rect(QPointF(0, 0), templateSize());
1099  scene() -> setSceneRect(bounding_rect);
1100 
1101  // met a jour la scene
1102  scene() -> update(old_scene_rect.united(bounding_rect));
1103 }
1104 
virtual qreal templateHeight() const
void updateLastContextMenuCell(HelperCell *)
bool attributeIsAnInteger(const QDomElement &, const QString &, int *=nullptr)
Definition: qet.cpp:200
~TitleBlockTemplateView() override
virtual qreal templateWidth() const
virtual void normalizeCells(QList< TitleBlockCell > &, int x=0, int y=0) const
bool read_only_
Boolean stating whether this view allows template edition.
Definition: templateview.h:141
int indexOf(QGraphicsLayoutItem *)
QIcon EditTableInsertRowAbove
Definition: qeticons.cpp:79
QIcon EditTableDeleteColumn
Definition: qeticons.cpp:75
QIcon EditTableDeleteRow
Definition: qeticons.cpp:76
QString makePrettyToolTip(const QString &)
HelperCell * last_context_menu_cell_
Definition: templateview.h:137
virtual TitleBlockTemplateCellsSet cells(const QRectF &) const
the length is absolute and should be applied as is
Definition: qet.h:144
#define COL_OFFSET
int num_col
x coordinate of the cell within its parent title block template grid
virtual void fillWithEmptyCells()
void selectedCellsChanged(QList< TitleBlockCell *>)
QAction * add_column_before_
Definition: templateview.h:132
QIcon EditTableInsertColumnRight
Definition: qeticons.cpp:78
HelperCell * extra_cells_width_helper_cell_
Definition: templateview.h:131
#define DEFAULT_PREVIEW_HELPER_CELL_HEIGHT
TitleBlockTemplate * tbtemplate_
Definition: templateview.h:126
int value
Numeric value.
Definition: dimension.h:34
#define ROW_OFFSET
SplittedHelperCell * total_width_helper_cell_
Definition: templateview.h:130
void previewWidthChanged(int, int)
static bool canMerge(const TitleBlockTemplateCellsSet &, TitleBlockTemplate *)
TitleBlockTemplateView(QWidget *=nullptr)
virtual void updateRowsHelperCells()
TitleBlockDimension value() const
void setTitleBlockTemplate(TitleBlockTemplate *)
virtual void applyRowsHeights(bool=true)
static bool canSplit(const TitleBlockTemplateCellsSet &splitted_cells, TitleBlockTemplate *tbtemplate)
int row_span
number of extra rows spanned by this cell
virtual void analyzeSelectedCells(bool *, bool *, int *)
QIcon EditTableInsertRowUnder
Definition: qeticons.cpp:80
#define DEFAULT_PREVIEW_WIDTH
virtual void updateColumnsHelperCells()
virtual void applyColumnsWidths(bool=true)
TitleBlockTemplateCellsSet makeCellsSetFromGraphicsItems(const QList< QGraphicsItem *> &) const
void drawBackground(QPainter *, const QRectF &) override
void wheelEvent(QWheelEvent *) override
Vertical segment.
Definition: qet.h:88
void setValue(const TitleBlockDimension &)
int lastContextMenuCellIndex() const
void gridModificationRequested(TitleBlockTemplateCommand *)
TitleBlockTemplate * titleBlockTemplate() const
QIcon tr
Definition: qeticons.cpp:204
void removeItem(QGraphicsLayoutItem *)
TitleBlockTemplateVisualCell * topLeftCell() const
QList< TitleBlockCell * > cut()
QAction * change_preview_width_
Definition: templateview.h:136
virtual qreal zoomFactor() const
QGraphicsGridLayout * tbgrid_
Definition: templateview.h:127
static ModifyTemplateGridCommand * deleteRow(TitleBlockTemplate *, int=-1)
void editColumn(HelperCell *=nullptr)
QList< QAction * > columnsActions() const
QString toString() const
Definition: dimension.cpp:34
QList< TitleBlockCell * > copy()
static ModifyTemplateGridCommand * addRow(TitleBlockTemplate *, int=-1)
virtual void loadTemplate(TitleBlockTemplate *)
virtual TitleBlockTemplateCellsSet selectedCellsSet() const
the cell span parameters should not applied at all
#define DEFAULT_COLS_HELPER_CELLS_HEIGHT
static ModifyTemplateGridCommand * deleteColumn(TitleBlockTemplate *, int=-1)
static ModifyTemplateGridCommand * addColumn(TitleBlockTemplate *, int=-1)
QGraphicsWidget * form_
Definition: templateview.h:128
virtual QList< TitleBlockCell * > selectedCells() const
bool first_activation_
Boolean used to detect the first display of this widget.
Definition: templateview.h:140
void editRow(HelperCell *=nullptr)
void loadContentFromXml(const QDomElement &)
virtual QSizeF templateSize() const
QIcon EditTableInsertColumnLeft
Definition: qeticons.cpp:77
QList< QAction * > rowsActions() const
void requestGridModification(TitleBlockTemplateCommand *)
bool event(QEvent *) override
QList< TitleBlockCell > pastedCells()
Horizontal segment.
Definition: qet.h:87
#define DEFAULT_ROWS_HELPER_CELLS_WIDTH
int col_span
number of extra columns spanned by this cell
int num_row
y coordinate of the cell within its parent title block template grid
QET::TitleBlockColumnLength type
Kind of length.
Definition: dimension.h:33
virtual void addCells()