QElectroTech  0.70
titleblocktemplate.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 "titleblocktemplate.h"
19 #include "qet.h"
20 #include "qetapp.h"
21 #include "nameslist.h"
22 #include "createdxf.h"
23 // uncomment the line below to get more debug information
24 //#define TITLEBLOCK_TEMPLATE_DEBUG
25 
31  QObject(parent)
32 {
33 }
34 
39  loadLogos(QDomElement(), true);
40  qDeleteAll(registered_cells_);
41 }
42 
50  TitleBlockCell *new_cell = existing_cell ? new TitleBlockCell(*existing_cell) : new TitleBlockCell();
51  registered_cells_ << new_cell;
52  return(new_cell);
53 }
54 
60 QList<TitleBlockCell *> TitleBlockTemplate::createCellsList(int count) {
61  QList<TitleBlockCell *> new_list;
62  for (int i = 0 ; i < count ; ++ i) new_list << createCell();
63  return(new_list);
64 }
65 
72 }
73 
79 bool TitleBlockTemplate::loadFromXmlFile(const QString &filepath) {
80  // open the file
81  QFile template_file(filepath);
82  if (!template_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
83  return(false);
84  }
85 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
86  qDebug() << Q_FUNC_INFO << filepath << "opened";
87 #endif
88 
89  // parse its content as XML
90  QDomDocument xml_doc;
91  bool xml_parsing = xml_doc.setContent(&template_file);
92  if (!xml_parsing) {
93  return(false);
94  }
95 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
96  qDebug() << Q_FUNC_INFO << filepath << "opened and parsed";
97 #endif
98  return(loadFromXmlElement(xml_doc.documentElement()));
99 }
100 
105 bool TitleBlockTemplate::loadFromXmlElement(const QDomElement &xml_element) {
106  // we expect the XML element to be an <titleblocktemplate>
107  if (xml_element.tagName() != "titleblocktemplate") {
108  return(false);
109  }
110  if (!xml_element.hasAttribute("name")) {
111  return(false);
112  }
113  name_ = xml_element.attribute("name");
114 
115  loadInformation(xml_element);
116  loadLogos(xml_element, true);
117  loadGrid(xml_element);
118 
119  return(true);
120 }
121 
127 bool TitleBlockTemplate::saveToXmlFile(const QString &filepath) {
128  if (filepath.isEmpty()) return(false);
129 
130  // generate the XML document
131  QDomDocument doc;
132  QDomElement e = doc.createElement("root");
133  bool saving = saveToXmlElement(e);
134  if (!saving) return(false);
135  doc.appendChild(e);
136 
137  return(QET::writeXmlFile(doc, filepath));
138 }
139 
145 bool TitleBlockTemplate::saveToXmlElement(QDomElement &xml_element) const {
146  // we are supposed to have at least a name
147  if (name_.isEmpty()) return(false);
148 
149  xml_element.setTagName("titleblocktemplate");
150  xml_element.setAttribute("name", name_);
151  saveInformation(xml_element);
152  saveLogos(xml_element);
153  saveGrid(xml_element);
154  return(true);
155 }
156 
161 void TitleBlockTemplate::exportCellToXml(TitleBlockCell *cell, QDomElement &xml_element) const {
162  saveCell(cell, xml_element, true);
163 }
164 
171  copy -> name_ = name_;
172  copy -> information_ = information_;
173 
174  // this does not really duplicates pixmaps, only the objects that hold a key to the implicitly shared pixmaps
175  foreach (QString logo_key, bitmap_logos_.keys()) {
176  copy -> bitmap_logos_[logo_key] = QPixmap(bitmap_logos_[logo_key]);
177 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
178  qDebug() << Q_FUNC_INFO << "copying " << bitmap_logos_[logo_key] -> cacheKey() << "to" << copy -> bitmap_logos_[logo_key] -> cacheKey();
179 #endif
180  }
181 
182  // we have to create new QSvgRenderer objects from the data (no copy constructor)
183  foreach (QString logo_key, vector_logos_.keys()) {
184  copy -> vector_logos_[logo_key] = new QSvgRenderer(data_logos_[logo_key]);
185  }
186 
187  copy -> data_logos_ = data_logos_;
188  copy -> storage_logos_ = storage_logos_;
189  copy -> type_logos_ = type_logos_;
190  copy -> rows_heights_ = rows_heights_;
191  copy -> columns_width_ = columns_width_;
192 
193  // copy cells basically
194  copy -> cells_ = cells_;
195  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
196  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
197  copy -> cells_[i][j] = copy -> createCell(cells_[i][j]);
198  }
199  }
200 
201  // ensure the copy has no spanner_cell attribute pointing to a cell from the original object
202  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
203  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
204  TitleBlockCell *current_cell = copy -> cells_[i][j];
205  if (TitleBlockCell *original_cell = current_cell -> spanner_cell) {
206  int original_cell_row = original_cell -> num_row;
207  int original_cell_col = original_cell -> num_col;
208  TitleBlockCell *copy_cell = copy -> cells_[original_cell_col][original_cell_row];
209  current_cell -> spanner_cell = copy_cell;
210  }
211  }
212  }
213 
214  return(copy);
215 }
216 
220 void TitleBlockTemplate::loadInformation(const QDomElement &xml_element) {
221  for (QDomNode n = xml_element.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
222  if (n.isElement() && n.toElement().tagName() == "information") {
223  setInformation(n.toElement().text());
224  }
225  }
226 }
227 
235 bool TitleBlockTemplate::loadLogos(const QDomElement &xml_element, bool reset) {
236  if (reset) {
237  qDeleteAll(vector_logos_.begin(), vector_logos_.end());
238  vector_logos_.clear();
239 
240  // Note: QPixmap are only a key to access the implicitly shared pixmap
241  bitmap_logos_.clear();
242 
243  data_logos_.clear();
244  storage_logos_.clear();
245  }
246 
247  // we look for //logos/logo elements
248  for (QDomNode n = xml_element.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
249  if (n.isElement() && n.toElement().tagName() == "logos") {
250  for (QDomNode p = n.firstChild() ; !p.isNull() ; p = p.nextSibling()) {
251  if (p.isElement() && p.toElement().tagName() == "logo") {
252  loadLogo(p.toElement());
253  }
254  }
255  }
256  }
257 
258  return(true);
259 }
260 
267 bool TitleBlockTemplate::loadLogo(const QDomElement &xml_element) {
268  // we require a name
269  if (!xml_element.hasAttribute("name")) {
270  return(false);
271  }
272  QString logo_name = xml_element.attribute("name");
273  QString logo_type = xml_element.attribute("type", "png");
274  QString logo_storage = xml_element.attribute("storage", "base64");
275 
276  // Both QSvgRenderer and QPixmap read their data from a QByteArray, so
277  // we convert the available data to that format.
278  QByteArray logo_data;
279  if (logo_storage == "xml") {
280  QDomNodeList svg_nodes = xml_element.elementsByTagName("svg");
281  if (svg_nodes.isEmpty()) {
282  return(false);
283  }
284  QDomElement svg_element = svg_nodes.at(0).toElement();
285  QTextStream xml_to_byte_array(&logo_data);
286  svg_element.save(xml_to_byte_array, 0);
287  } else if (logo_storage == "base64") {
288  logo_data = QByteArray::fromBase64(xml_element.text().toLatin1());
289  } else {
290  return(false);
291  }
292 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
293  qDebug() << Q_FUNC_INFO << logo_name << logo_type << logo_storage;
294 #endif
295  addLogo(logo_name, &logo_data, logo_type, logo_storage);
296 
297  return(true);
298 }
299 
305 bool TitleBlockTemplate::loadGrid(const QDomElement &xml_element) {
306  // we parse the first available "grid" XML element
307  QDomElement grid_element;
308  for (QDomNode n = xml_element.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
309  if (n.isElement() && n.toElement().tagName() == "grid") {
310  grid_element = n.toElement();
311  break;
312  }
313  }
314 
315  if (!grid_element.hasAttribute("rows") || !grid_element.hasAttribute("cols")) {
316  return(false);
317  }
318 
319  parseRows(grid_element.attribute("rows"));
320  parseColumns(grid_element.attribute("cols"));
321  initCells();
322  loadCells(grid_element);
323  applyRowColNums();
324  applyCellSpans();
325  return(true);
326 }
327 
332 void TitleBlockTemplate::parseRows(const QString &rows_string) {
333  rows_heights_.clear();
334  // parse the rows attribute: we expect a serie of absolute heights
335  QRegExp row_size_format("^([0-9]+)(?:px)?$", Qt::CaseInsensitive);
336  bool conv_ok;
337 
338  QStringList rows_descriptions = rows_string.split(QChar(';'), QString::SkipEmptyParts);
339  foreach (QString rows_description, rows_descriptions) {
340  if (row_size_format.exactMatch(rows_description)) {
341  int row_size = row_size_format.capturedTexts().at(1).toInt(&conv_ok);
342  if (conv_ok) rows_heights_ << row_size;
343  }
344  }
345 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
346  qDebug() << Q_FUNC_INFO << "Rows heights:" << rows_heights_;
347 #endif
348 }
349 
354 void TitleBlockTemplate::parseColumns(const QString &cols_string) {
355  columns_width_.clear();
356  // parse the cols attribute: we expect a serie of absolute or relative widths
357  QRegExp abs_col_size_format("^([0-9]+)(?:px)?$", Qt::CaseInsensitive);
358  QRegExp rel_col_size_format("^([rt])([0-9]+)%$", Qt::CaseInsensitive);
359  bool conv_ok;
360 
361  QStringList cols_descriptions = cols_string.split(QChar(';'), QString::SkipEmptyParts);
362  foreach (QString cols_description, cols_descriptions) {
363  if (abs_col_size_format.exactMatch(cols_description)) {
364  int col_size = abs_col_size_format.capturedTexts().at(1).toInt(&conv_ok);
365  if (conv_ok) columns_width_ << TitleBlockDimension(col_size, QET::Absolute);
366  } else if (rel_col_size_format.exactMatch(cols_description)) {
367  int col_size = rel_col_size_format.capturedTexts().at(2).toInt(&conv_ok);
368  QET::TitleBlockColumnLength col_type = rel_col_size_format.capturedTexts().at(1) == "t" ? QET::RelativeToTotalLength : QET::RelativeToRemainingLength;
369  if (conv_ok) columns_width_ << TitleBlockDimension(col_size, col_type );
370  }
371  }
372 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
373  foreach (TitleBlockColDimension icd, columns_width_) {
374  qDebug() << Q_FUNC_INFO << QString("%1 [%2]").arg(icd.value).arg(QET::titleBlockColumnLengthToString(icd.type));
375  }
376 #endif
377 }
378 
385 bool TitleBlockTemplate::loadCells(const QDomElement &xml_element) {
386  // we are interested by the "logo" and "field" elements
387  QDomElement grid_element;
388  for (QDomNode n = xml_element.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
389  if (!n.isElement()) continue;
390  QDomElement cell_element = n.toElement();
391  if (cell_element.tagName() == "field" || cell_element.tagName() == "logo") {
392  loadCell(cell_element);
393  }
394  }
395  return(true);
396 }
397 
402 void TitleBlockTemplate::loadCell(const QDomElement &cell_element) {
403  TitleBlockCell *loaded_cell;
404  if (!checkCell(cell_element, &loaded_cell)) return;
405  loaded_cell -> loadContentFromXml(cell_element);
406 }
407 
412 void TitleBlockTemplate::saveInformation(QDomElement &xml_element) const {
413  QDomNode information_text_node = xml_element.ownerDocument().createTextNode(information());
414 
415  QDomElement information_element = xml_element.ownerDocument().createElement("information");
416  information_element.appendChild(information_text_node);
417  xml_element.appendChild(information_element);
418 }
419 
424 void TitleBlockTemplate::saveLogos(QDomElement &xml_element) const {
425  QDomElement logos_element = xml_element.ownerDocument().createElement("logos");
426  foreach(QString logo_name, type_logos_.keys()) {
427  QDomElement logo_element = xml_element.ownerDocument().createElement("logo");
428  saveLogo(logo_name, logo_element);
429  logos_element.appendChild(logo_element);
430  }
431  xml_element.appendChild(logos_element);
432 }
433 
439 void TitleBlockTemplate::saveLogo(const QString &logo_name, QDomElement &xml_element) const {
440  if (!type_logos_.contains(logo_name)) return;
441 
442  xml_element.setAttribute("name", logo_name);
443  xml_element.setAttribute("type", type_logos_[logo_name]);
444  xml_element.setAttribute("storage", storage_logos_[logo_name]);
445 
446  if (storage_logos_[logo_name] == "xml" && type_logos_[logo_name] == "svg") {
447  QDomDocument svg_logo;
448  svg_logo.setContent(data_logos_[logo_name]);
449  QDomNode svg_logo_element = xml_element.ownerDocument().importNode(svg_logo.documentElement(), true);
450  xml_element.appendChild(svg_logo_element.toElement());
451  } else if (storage_logos_[logo_name] == "base64") {
452  QDomText base64_logo = xml_element.ownerDocument().createTextNode(data_logos_[logo_name].toBase64());
453  xml_element.appendChild(base64_logo);
454  }
455 }
456 
461 void TitleBlockTemplate::saveGrid(QDomElement &xml_element) const {
462  QDomElement grid_element = xml_element.ownerDocument().createElement("grid");
463 
464  QString rows_attr, cols_attr;
465  foreach(int row_height, rows_heights_) rows_attr += QString("%1;").arg(row_height);
466  foreach(TitleBlockDimension col_width, columns_width_) cols_attr += col_width.toShortString();
467  grid_element.setAttribute("rows", rows_attr);
468  grid_element.setAttribute("cols", cols_attr);
469 
470  saveCells(grid_element);
471 
472  xml_element.appendChild(grid_element);
473 }
474 
479 void TitleBlockTemplate::saveCells(QDomElement &xml_element) const {
480  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
481  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
482  if (cells_[i][j] -> cell_type != TitleBlockCell::EmptyCell) {
483  saveCell(cells_[i][j], xml_element);
484  }
485  }
486  }
487 }
488 
495 void TitleBlockTemplate::saveCell(TitleBlockCell *cell, QDomElement &xml_element, bool save_empty) const {
496  if (!cell) return;
497  if (cell -> spanner_cell) return;
498  if (!save_empty && cell -> cell_type == TitleBlockCell::EmptyCell) return;
499 
500 
501  QDomElement cell_elmt = xml_element.ownerDocument().createElement("cell");
502  xml_element.appendChild(cell_elmt);
503 
504  // save information dependent from this template
505  cell_elmt.setAttribute("row", cell -> num_row);
506  cell_elmt.setAttribute("col", cell -> num_col);
507  if (cell -> row_span) cell_elmt.setAttribute("rowspan", cell -> row_span);
508  if (cell -> col_span) cell_elmt.setAttribute("colspan", cell -> col_span);
509 
510  // save other information
511  cell -> saveContentToXml(cell_elmt);
512 }
513 
522 bool TitleBlockTemplate::checkCell(const QDomElement &xml_element, TitleBlockCell **titleblock_cell_ptr) {
523  int col_count = columns_width_.count(), row_count = rows_heights_.count();
524 
525 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
526  qDebug() << Q_FUNC_INFO << "begin" << row_count << col_count;
527 #endif
528 
529  int row_num, col_num, row_span, col_span;
530  row_num = col_num = -1;
531  row_span = col_span = 0;
532 
533  // parse the row and col attributes
534  if (!QET::attributeIsAnInteger(xml_element, "row", &row_num) || row_num < 0 || row_num >= row_count) {
535  return(false);
536  }
537  if (!QET::attributeIsAnInteger(xml_element, "col", &col_num) || col_num < 0 || col_num >= col_count) {
538  return(false);
539  }
540 
541  // check whether the target cell can be used or not
542 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
543  qDebug() << Q_FUNC_INFO << "cell access" << col_num << row_num;
544 #endif
545  TitleBlockCell *cell_ptr = cells_[col_num][row_num];
546  if (cell_ptr -> cell_type != TitleBlockCell::EmptyCell || cell_ptr -> spanner_cell) {
547  return(false);
548  }
549  // ensure the num_row and num_col attributes are alright
550  cell_ptr -> num_row = row_num;
551  cell_ptr -> num_col = col_num;
552 
553  // parse the rowspan and colspan attributes
554  if (QET::attributeIsAnInteger(xml_element, "rowspan", &row_span) && row_span > 0) {
555  cell_ptr -> row_span = row_span;
556  }
557 
558  if (QET::attributeIsAnInteger(xml_element, "colspan", &col_span) && col_span > 0) {
559  cell_ptr -> col_span = col_span;
560  }
561  // these attributes are stored "as is" -- whether they can be applied directly or must be restricted will be checked later
562 
563  if (titleblock_cell_ptr) *titleblock_cell_ptr = cell_ptr;
564  return(true);
565 }
566 
573  if (columns_width_.count() < 1 || rows_heights_.count() < 1) return;
574 
575  cells_.clear();
576  qDeleteAll(registered_cells_);
577  registered_cells_.clear();
578  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
579  cells_ << createColumn();
580  }
581 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
582  qDebug() << Q_FUNC_INFO << toString();
583 #endif
584 }
585 
589 QString TitleBlockTemplate::name() const {
590  return(name_);
591 }
592 
597  return(information_);
598 }
599 
603 void TitleBlockTemplate::setInformation(const QString &info) {
604  information_ = info;
605 }
606 
612  int index = (i == -1) ? rows_heights_.count() - 1 : i;
613  if (index >= 0 && index < rows_heights_.count()) {
614  return(rows_heights_.at(index));
615  }
616  return(-1);
617 }
618 
625  int index = (i == -1) ? rows_heights_.count() - 1 : i;
626  if (index >= 0 || index < rows_heights_.count()) {
627  rows_heights_[index] = dimension.value;
628  }
629 }
630 
636  int index = (i == -1) ? columns_width_.count() - 1 : i;
637  if (index >= 0 && index < columns_width_.count()) {
638  return(columns_width_.at(index));
639  }
640  return(TitleBlockDimension(-1));
641 }
642 
649  int index = (i == -1) ? columns_width_.count() - 1 : i;
650  if (index >= 0 || index < columns_width_.count()) {
651  columns_width_[index] = dimension;
652  }
653 }
654 
659  return(columns_width_.count());
660 }
661 
666  return(rows_heights_.count());
667 }
668 
673 QList<int> TitleBlockTemplate::columnsWidth(int total_width) const {
674  if (total_width < 0) return(QList<int>());
675 
676  // we first iter to determine the absolute and total-width-related widths
677  QVector<int> final_widths(columns_width_.count());
678  int abs_widths_sum = 0, rel_widths_sum = 0;
679  QList<int> relative_columns;
680 
681  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
683  if (icd.type == QET::Absolute) {
684  abs_widths_sum += icd.value;
685  final_widths[i] = icd.value;
686  } else if (icd.type == QET::RelativeToTotalLength) {
687  int abs_value = qRound(total_width * icd.value / 100.0);
688  relative_columns << i;
689  abs_widths_sum += abs_value;
690  final_widths[i] = abs_value;
691  }
692  }
693 
694  // we can now deduce the remaining width
695  int remaining_width = total_width - abs_widths_sum;
696 
697  // we do a second iteration to build the final widths list
698  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
701  final_widths[i] = qRound(remaining_width * icd.value / 100.0);
702  relative_columns << i;
703  rel_widths_sum += final_widths[i];
704  }
705  }
706 
707  // Have we computed widths from percentage for relative columns?
708  if (relative_columns.count()) {
709  // Due to the rounding process, we may get a slight difference between the
710  // sum of the columns widths and the total width.
711  int difference = total_width - abs_widths_sum - rel_widths_sum;
712 
713  if (difference) {
714  // We consider we should not attempt to compensate this difference if it is
715  // under relative_columns_count * 0.5 (which means that each percent-based
716  // columns can "bring" up to 0.5px of difference).
717  qreal max_acceptable_difference = relative_columns.count() * 0.5;
718 
719  int share = difference > 0 ? 1 : -1;
720  if (qAbs(difference) <= max_acceptable_difference) {
721  while (difference) {
722  foreach (int index, relative_columns) {
723  final_widths[index] += share;
724  difference -= share;
725  if (!difference) break;
726  }
727  }
728  }
729  }
730  }
731  return(final_widths.toList());
732 }
733 
738  return(rows_heights_);
739 }
740 
746  int count = 0;
747 
748  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
749  if (columns_width_.at(i).type == type) ++ count;
750  }
751 
752  return(count);
753 }
754 
760  int total = 0;
761 
762  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
763  if (columns_width_.at(i).type == type) {
764  total += columns_width_.at(i).value;
765  }
766  }
767 
768  return(total);
769 }
770 
775  // Abbreviations: ABS: absolute, RTT: relative to total, RTR: relative to
776  // remaining, TOT: total diagram/TBT width (variable).
777 
778  // Minimum size may be enforced by ABS and RTT widths:
779  // TOT >= ((sum(REL)/100)*TOT)+sum(ABS)
780  // => (1 - (sum(REL)/100))TOT >= sum(ABS)
781  // => TOT >= sum(ABS) / (1 - (sum(REL)/100))
782  // => TOT >= sum(ABS) / ((100 - sum(REL))/100))
783  return(
784  qRound(
786  /
787  ((100.0 - columnTypeTotal(QET::RelativeToTotalLength)) / 100.0)
788  )
789  );
790 }
791 
796  if (columnTypeCount(QET::Absolute) == columns_width_.count()) {
797  // The template is composed of absolute widths only,
798  // therefore it may not extend beyond their sum.
800  }
801  return(-1);
802 }
803 
808 int TitleBlockTemplate::width(int total_width) {
809  int width = 0;
810  foreach (int col_width, columnsWidth(total_width)) {
811  width += col_width;
812  }
813  return(width);
814 }
815 
820  int height = 0;
821  foreach(int row_height, rows_heights_) {
822  height += row_height;
823  }
824  return(height);
825 }
826 
832 bool TitleBlockTemplate::moveRow(int from, int to) {
833  // checks from and to
834  if (from >= rows_heights_.count()) return(false);
835  if (to >= rows_heights_.count()) return(false);
836  for (int j = 0 ; j < columns_width_.count() ; ++ j) {
837  cells_[j].move(from, to);
838  }
839  rows_heights_.move(from, to);
840  rowColsChanged();
841  return(true);
842 }
843 
849  insertRow(25, createRow(), i);
850 }
851 
857 bool TitleBlockTemplate::insertRow(int dimension, const QList<TitleBlockCell *> &row, int i) {
858  int index = (i == -1) ? rows_heights_.count() : i;
859 
860  for (int j = 0 ; j < columns_width_.count() ; ++ j) {
861  cells_[j].insert(index, row[j]);
862  }
863  rows_heights_.insert(index, dimension);
864  rowColsChanged();
865  return(true);
866 }
867 
873 QList<TitleBlockCell *> TitleBlockTemplate::takeRow(int i) {
874  QList<TitleBlockCell *> row;
875  int index = (i == -1) ? rows_heights_.count() - 1 : i;
876  if (index < 0 || index >= rows_heights_.count()) return(row);
877  for (int j = 0 ; j < columns_width_.count() ; ++ j) {
878  row << cells_[j].takeAt(index);
879  }
880  rows_heights_.removeAt(index);
881  rowColsChanged();
882  return(row);
883 }
884 
888 QList<TitleBlockCell *> TitleBlockTemplate::createRow() {
889  return(createCellsList(columns_width_.count()));
890 
891 }
892 
898 bool TitleBlockTemplate::moveColumn(int from, int to) {
899  // checks from and to
900  if (from >= columns_width_.count()) return(false);
901  if (to >= columns_width_.count()) return(false);
902  cells_.move(from, to);
903  columns_width_.move(from, to);
904  rowColsChanged();
905  return(true);
906 }
907 
914 }
915 
921 bool TitleBlockTemplate::insertColumn(const TitleBlockDimension &dimension, const QList<TitleBlockCell *> &column, int i) {
922  int index = (i == -1) ? columns_width_.count() : i;
923  cells_.insert(index, column);
924  columns_width_.insert(index, dimension);
925  rowColsChanged();
926  return(true);
927 }
928 
934 QList<TitleBlockCell *> TitleBlockTemplate::takeColumn(int i) {
935  int index = (i == -1) ? columns_width_.count() - 1 : i;
936  if (index < 0 || index >= columns_width_.count()) {
937  return(QList<TitleBlockCell *>());
938  }
939  QList<TitleBlockCell *> column = cells_.takeAt(i);
940  columns_width_.removeAt(i);
941  rowColsChanged();
942  return(column);
943 }
944 
948 QList<TitleBlockCell *> TitleBlockTemplate::createColumn() {
949  return(createCellsList(rows_heights_.count()));
950 }
951 
957 TitleBlockCell *TitleBlockTemplate::cell(int row, int col) const {
958  if (row >= rows_heights_.count()) return(nullptr);
959  if (col >= columns_width_.count()) return(nullptr);
960 
961  return(cells_[col][row]);
962 }
963 
972 QSet<TitleBlockCell *> TitleBlockTemplate::spannedCells(const TitleBlockCell *given_cell, bool ignore_span_state) const {
973  QSet<TitleBlockCell *> set;
974  if (!given_cell) return(set);
975  if (!ignore_span_state && given_cell -> span_state == TitleBlockCell::Disabled) return(set);
976 
977  int final_row_span = ignore_span_state ? given_cell -> row_span : given_cell -> applied_row_span;
978  int final_col_span = ignore_span_state ? given_cell -> col_span : given_cell -> applied_col_span;
979  if (!final_row_span && !final_col_span) return(set);
980 
981  for (int i = given_cell -> num_col ; i <= given_cell -> num_col + final_col_span ; ++ i) {
982  for (int j = given_cell -> num_row ; j <= given_cell -> num_row + final_row_span ; ++ j) {
983  if (i == given_cell -> num_col && j == given_cell -> num_row) continue;
984  TitleBlockCell *current_cell = cell(j, i);
985  if (current_cell) set << current_cell;
986  }
987  }
988  return(set);
989 }
990 
994 QHash<TitleBlockCell *, QPair<int, int> > TitleBlockTemplate::getAllSpans() const {
995  QHash<TitleBlockCell *, QPair<int, int> > spans;
996  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
997  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
998  spans.insert(
999  cells_[i][j],
1000  QPair<int, int>(
1001  cells_[i][j] -> row_span,
1002  cells_[i][j] -> col_span
1003  )
1004  );
1005  }
1006  }
1007  return(spans);
1008 }
1009 
1013 void TitleBlockTemplate::setAllSpans(const QHash<TitleBlockCell *, QPair<int, int> > &spans) {
1014  foreach (TitleBlockCell *cell, spans.keys()) {
1015  cell -> row_span = spans[cell].first;
1016  cell -> col_span = spans[cell].second;
1017  }
1018 }
1019 
1024 bool TitleBlockTemplate::addLogo(const QString &logo_name, QByteArray *logo_data, const QString &logo_type, const QString &logo_storage) {
1025  if (data_logos_.contains(logo_name)) {
1026  // we are replacing the logo
1027  removeLogo(logo_name);
1028  }
1029 
1030  // we can now create our image object from the byte array
1031  if (logo_type == "svg") {
1032  // SVG format is handled by the QSvgRenderer class
1033  QSvgRenderer *svg = new QSvgRenderer();
1034  if (!svg -> load(*logo_data)) {
1035  return(false);
1036  }
1037  vector_logos_.insert(logo_name, svg);
1038 
1039  // we also memorize the way to store them in the final XML output
1040  QString final_logo_storage = logo_storage;
1041  if (logo_storage != "xml" && logo_storage != "base64") {
1042  final_logo_storage = "xml";
1043  }
1044  storage_logos_.insert(logo_name, logo_storage);
1045  } else {
1046 
1047  // bitmap formats are handled by the QPixmap class
1048  QPixmap logo_pixmap;
1049  logo_pixmap.loadFromData(*logo_data);
1050  if (!logo_pixmap.width() || !logo_pixmap.height()) {
1051  return(false);
1052  }
1053  bitmap_logos_.insert(logo_name, logo_pixmap);
1054 
1055  // bitmap logos can only be stored using a base64 encoding
1056  storage_logos_.insert(logo_name, "base64");
1057  }
1058 
1059  // we systematically store the raw data
1060  data_logos_.insert(logo_name, *logo_data);
1061  type_logos_.insert(logo_name, logo_type);
1062 
1063  return(true);
1064 }
1065 
1072 bool TitleBlockTemplate::addLogoFromFile(const QString &filepath, const QString &name) {
1073  QFileInfo filepath_info(filepath);
1074  QString filename = name.isEmpty() ? filepath_info.fileName() : name;
1075  QString filetype = filepath_info.suffix();
1076 
1077  // we read the provided logo
1078  QFile logo_file(filepath);
1079  if (!logo_file.open(QIODevice::ReadOnly)) return(false);
1080  QByteArray file_content = logo_file.readAll();
1081 
1082  // first, we try to add it as an SVG image
1083  if (addLogo(filename, &file_content, "svg", "xml")) return(true);
1084 
1085  // we then try to add it as a bitmap image
1086  return addLogo(filename, &file_content, filepath_info.suffix(), "base64");
1087 }
1088 
1089 /*
1090  @param logo_name Name used to store the logo
1091  @param filepath Path the logo will be saved as
1092  @return true if the logo could be exported, false otherwise
1093 */
1094 bool TitleBlockTemplate::saveLogoToFile(const QString &logo_name, const QString &filepath) {
1095  if (!data_logos_.contains(logo_name)) {
1096  return(false);
1097  }
1098 
1099  QFile target_file(filepath);
1100  if (!target_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1101  return(false);
1102  }
1103 
1104  target_file.write(data_logos_[logo_name]);
1105  target_file.close();
1106  return(true);
1107 }
1108 
1113 bool TitleBlockTemplate::removeLogo(const QString &logo_name) {
1114  if (!data_logos_.contains(logo_name)) {
1115  return(false);
1116  }
1117 
1119  if (vector_logos_.contains(logo_name)) {
1120  delete vector_logos_.take(logo_name);
1121  }
1122  if (bitmap_logos_.contains(logo_name)) {
1123  bitmap_logos_.remove(logo_name);
1124  }
1125  data_logos_.remove(logo_name);
1126  storage_logos_.remove(logo_name);
1127  return(true);
1128 }
1129 
1135 bool TitleBlockTemplate::renameLogo(const QString &logo_name, const QString &new_name) {
1136  if (!data_logos_.contains(logo_name) || data_logos_.contains(new_name)) {
1137  return(false);
1138  }
1139 
1141  if (vector_logos_.contains(logo_name)) {
1142  vector_logos_.insert(new_name, vector_logos_.take(logo_name));
1143  }
1144  if (bitmap_logos_.contains(logo_name)) {
1145  bitmap_logos_.insert(new_name, bitmap_logos_.take(logo_name));
1146  }
1147  data_logos_.insert(new_name, data_logos_.take(logo_name));
1148  storage_logos_.insert(new_name, storage_logos_.take(logo_name));
1149  return(true);
1150 }
1151 
1157 void TitleBlockTemplate::setLogoStorage(const QString &logo_name, const QString &storage) {
1158  if (storage_logos_.contains(logo_name)) {
1159  storage_logos_[logo_name] = storage;
1160  }
1161 }
1162 
1166 QList<QString> TitleBlockTemplate::logos() const {
1167  return(data_logos_.keys());
1168 }
1169 
1175 QString TitleBlockTemplate::logoType(const QString &logo_name) const {
1176  if (type_logos_.contains(logo_name)) {
1177  return type_logos_[logo_name];
1178  }
1179  return(QString());
1180 }
1181 
1187 QSvgRenderer *TitleBlockTemplate::vectorLogo(const QString &logo_name) const {
1188  if (vector_logos_.contains(logo_name)) {
1189  return vector_logos_[logo_name];
1190  }
1191  return(nullptr);
1192 }
1193 
1199 QPixmap TitleBlockTemplate::bitmapLogo(const QString &logo_name) const {
1200  if (bitmap_logos_.contains(logo_name)) {
1201  return bitmap_logos_[logo_name];
1202  }
1203  return(QPixmap());
1204 }
1205 
1212 void TitleBlockTemplate::render(QPainter &painter, const DiagramContext &diagram_context, int titleblock_width) const {
1213  QList<int> widths = columnsWidth(titleblock_width);
1214  int titleblock_height = height();
1215 
1216  painter.save();
1217  //Setup the QPainter
1218  QPen pen(Qt::black);
1219  pen.setCosmetic(true);
1220  painter.setPen(pen);
1221 
1222  // draw the titleblock border
1223  painter.drawRect(QRect(0, 0, titleblock_width, titleblock_height));
1224 
1225  // run through each individual cell
1226  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
1227  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
1228  if (cells_[i][j] -> spanner_cell || cells_[i][j] -> cell_type == TitleBlockCell::EmptyCell) continue;
1229 
1230  // calculate the border rect of the current cell
1231  int x = lengthRange(0, cells_[i][j] -> num_col, widths);
1232  int y = lengthRange(0, cells_[i][j] -> num_row, rows_heights_);
1233 
1234  int row_span = 0, col_span = 0;
1235  if (cells_[i][j] -> span_state != TitleBlockCell::Disabled) {
1236  row_span = cells_[i][j] -> applied_row_span;
1237  col_span = cells_[i][j] -> applied_col_span;
1238  }
1239  int w = lengthRange(cells_[i][j] -> num_col, cells_[i][j] -> num_col + 1 + col_span, widths);
1240  int h = lengthRange(cells_[i][j] -> num_row, cells_[i][j] -> num_row + 1 + row_span, rows_heights_);
1241  QRect cell_rect(x, y, w, h);
1242 
1243  renderCell(painter, *cells_[i][j], diagram_context, cell_rect);
1244  }
1245  }
1246  painter.restore();
1247 }
1248 
1254 void TitleBlockTemplate::renderDxf(QRectF &title_block_rect, const DiagramContext &diagram_context,
1255  int titleblock_width, QString &file_path, int color) const {
1256  QList<int> widths = columnsWidth(titleblock_width);
1257 
1258  // draw the titleblock border
1259  double xCoord = title_block_rect.topLeft().x();
1260  double yCoord = Createdxf::sheetHeight - title_block_rect.bottomLeft().y()*Createdxf::yScale;
1261  double recWidth = title_block_rect.width() * Createdxf::xScale;
1262  double recHeight = title_block_rect.height() * Createdxf::yScale;
1263  Createdxf::drawRectangle(file_path, xCoord, yCoord, recWidth, recHeight, color);
1264 
1265  // run through each individual cell
1266  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
1267  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
1268  if (cells_[i][j] -> spanner_cell || cells_[i][j] -> cell_type == TitleBlockCell::EmptyCell) continue;
1269 
1270  // calculate the border rect of the current cell
1271  double x = lengthRange(0, cells_[i][j] -> num_col, widths);
1272  double y = lengthRange(0, cells_[i][j] -> num_row, rows_heights_);
1273 
1274  int row_span = 0, col_span = 0;
1275  if (cells_[i][j] -> span_state != TitleBlockCell::Disabled) {
1276  row_span = cells_[i][j] -> applied_row_span;
1277  col_span = cells_[i][j] -> applied_col_span;
1278  }
1279  double w = lengthRange(cells_[i][j] -> num_col, cells_[i][j] -> num_col + 1 + col_span, widths);
1280  double h = lengthRange(cells_[i][j] -> num_row, cells_[i][j] -> num_row + 1 + row_span, rows_heights_);
1281 
1282  x = xCoord + x*Createdxf::xScale;
1283  h *= Createdxf::yScale;
1284  y = yCoord + recHeight - h - y*Createdxf::yScale;
1285  w *= Createdxf::xScale;
1286 
1287  Createdxf::drawRectangle(file_path, x, y, w, h, color);
1288  if (cells_[i][j] -> type() == TitleBlockCell::TextCell) {
1289  QString final_text = finalTextForCell(*cells_[i][j], diagram_context);
1290  renderTextCellDxf(file_path, final_text, *cells_[i][j], x, y, w, h, color);
1291  }
1292  }
1293  }
1294 }
1295 
1296 
1297 
1304 void TitleBlockTemplate::renderCell(QPainter &painter, const TitleBlockCell &cell, const DiagramContext &diagram_context, const QRect &cell_rect) const {
1305  // draw the border rect of the current cell
1306  QPen pen(QBrush(), 0.0, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
1307  pen.setColor(Qt::black);
1308  painter.setPen(pen);
1309  painter.drawRect(cell_rect);
1310 
1311  painter.save();
1312  // render the inner content of the current cell
1313  if (cell.type() == TitleBlockCell::LogoCell) {
1314  if (!cell.logo_reference.isEmpty()) {
1315  // the current cell appears to be a logo - we first look for the
1316  // logo reference in our vector logos list, since they offer a
1317  // potentially better (or, at least, not resolution-limited) rendering
1318  if (vector_logos_.contains(cell.logo_reference)) {
1319  vector_logos_[cell.logo_reference] -> render(&painter, cell_rect);
1320  } else if (bitmap_logos_.contains(cell.logo_reference)) {
1321  painter.drawPixmap(cell_rect, bitmap_logos_[cell.logo_reference]);
1322  }
1323  }
1324  } else if (cell.type() == TitleBlockCell::TextCell) {
1325  QString final_text = finalTextForCell(cell, diagram_context);
1326  renderTextCell(painter, final_text, cell, cell_rect);
1327  }
1328  painter.restore();
1329 
1330  // draw again the border rect of the current cell, without the brush this time
1331  painter.setBrush(Qt::NoBrush);
1332  painter.drawRect(cell_rect);
1333 }
1334 
1335 
1336 
1337 
1343 QString TitleBlockTemplate::finalTextForCell(const TitleBlockCell &cell, const DiagramContext &diagram_context) const {
1344  QString cell_text = cell.value.name();
1345  QString cell_label = cell.label.name();
1346 
1347  cell_text = interpreteVariables(cell_text, diagram_context);
1348 
1349  if (cell.display_label && !cell.label.isEmpty()) {
1350  cell_label = interpreteVariables(cell_label, diagram_context);
1351  cell_text = QString(tr(" %1 : %2", "titleblock content - please let the blank space at the beginning")).arg(cell_label).arg(cell_text);
1352  } else {
1353  cell_text = QString(tr(" %1")).arg(cell_text);
1354  }
1355  return(cell_text);
1356 }
1357 
1363 QString TitleBlockTemplate::interpreteVariables(const QString &string, const DiagramContext &diagram_context) const {
1364  QString interpreted_string = string;
1365  foreach (QString key, diagram_context.keys(DiagramContext::DecreasingLength)) {
1366  interpreted_string.replace("%{" + key + "}", diagram_context[key].toString());
1367  interpreted_string.replace("%" + key, diagram_context[key].toString());
1368  }
1369  return(interpreted_string);
1370 }
1371 
1377  QStringList list;
1378  // run through each individual cell
1379  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
1380  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
1381  if (cells_[i][j] -> spanner_cell || cells_[i][j] -> cell_type == TitleBlockCell::EmptyCell) continue;
1382  // TODO: not works on all cases...
1383  list << cells_[i][j] -> value.name().replace("%","");
1384  }
1385  }
1386  qDebug() << list;
1387  return list;
1388 }
1389 
1400 void TitleBlockTemplate::renderTextCell(QPainter &painter, const QString &text, const TitleBlockCell &cell, const QRectF &cell_rect) const {
1401  if (text.isEmpty()) return;
1402  QFont text_font = TitleBlockTemplate::fontForCell(cell);
1403  painter.setFont(text_font);
1404 
1405  if (cell.hadjust) {
1406  QFontMetricsF font_metrics(text_font);
1407  QRectF font_rect = font_metrics.boundingRect(QRect(-10000, -10000, 10000, 10000), cell.alignment, text);
1408 
1409  if (font_rect.width() > cell_rect.width()) {
1410  qreal ratio = qreal(cell_rect.width()) / qreal(font_rect.width());
1411  painter.save();
1412 
1413  painter.translate(cell_rect.topLeft());
1414  qreal vertical_adjustment = cell_rect.height() * (1 - ratio) / 2.0;
1415  painter.translate(0.0, vertical_adjustment);
1416  painter.scale(ratio, ratio);
1417 
1418  QRectF new_world_cell_rect(cell_rect);
1419  new_world_cell_rect.moveTo(0, 0.0);
1420  new_world_cell_rect.setWidth(new_world_cell_rect.width() / ratio);
1421  painter.drawText(new_world_cell_rect, cell.alignment, text);
1422 
1423  painter.restore();
1424  return;
1425  }
1426  }
1427 
1428  // Still here? Let's draw the text normally
1429  painter.drawText(cell_rect, cell.alignment, text);
1430 }
1431 
1432 
1433 void TitleBlockTemplate::renderTextCellDxf(QString &file_path, const QString &text,
1434  const TitleBlockCell &cell,
1435  qreal x, qreal y, qreal w, qreal h, int color) const {
1436  if (text.isEmpty()) return;
1437  QFont text_font = TitleBlockTemplate::fontForCell(cell);
1438  double textHeight = text_font.pointSizeF();
1439  if (textHeight < 0)
1440  textHeight = text_font.pixelSize();
1441 
1442  qreal x2 = x + w;
1443 
1444  int vAlign = 0;
1445  int hAlign = 0;
1446  bool hALigned = false;
1447 
1448  if ( cell.alignment & Qt::AlignRight ) {
1449  hAlign = 2;
1450  hALigned = true;
1451  } else if ( cell.alignment & Qt::AlignHCenter ) {
1452  hAlign = 1;
1453  hALigned = true;
1454  x2 = x + w/2;
1455  } else if ( cell.alignment & Qt::AlignJustify ) {
1456  hAlign = 5;
1457  hALigned = true;
1458  }
1459 
1460  if ( cell.alignment & Qt::AlignTop ) {
1461  vAlign = 3;
1462  y += h - textHeight*Createdxf::yScale;
1463  if (!hALigned)
1464  x2 = x;
1465  } else if ( cell.alignment & Qt::AlignVCenter ) {
1466  vAlign = 2;
1467  y += h/2;
1468  if (!hALigned)
1469  x2 = x;
1470  } else if ( cell.alignment & Qt::AlignBottom ) {}
1471 
1472 
1473  //painter.setFont(text_font);
1474 
1475  if (cell.hadjust) {
1476  QFontMetricsF font_metrics(text_font);
1477  QRectF font_rect = font_metrics.boundingRect(QRect(-10000, -10000, 10000, 10000), cell.alignment, text);
1478 
1479  if (font_rect.width()*Createdxf::xScale > w) {
1480  qreal ratio = qreal(w) / qreal(font_rect.width()*Createdxf::xScale);
1481  textHeight *= ratio;
1482  }
1483  }
1484 
1485  Createdxf::drawTextAligned(file_path, text, x,
1486  y, textHeight*Createdxf::yScale, 0, 0, hAlign, vAlign, x2, color, 0);
1487 
1488 }
1489 
1490 
1495  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
1496  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
1497  cells_[i][j] -> spanner_cell = nullptr;
1498  }
1499  }
1500 }
1501 
1506 void TitleBlockTemplate::forgetSpanning(TitleBlockCell *spanning_cell, bool modify_cell) {
1507  if (!spanning_cell) return;
1508  foreach (TitleBlockCell *spanned_cell, spannedCells(spanning_cell)) {
1509  spanned_cell -> spanner_cell = nullptr;
1510  }
1511  if (modify_cell) {
1512  spanning_cell -> row_span = 0;
1513  spanning_cell -> col_span = 0;
1514  spanning_cell -> applied_row_span = 0;
1515  spanning_cell -> applied_col_span = 0;
1516  spanning_cell -> span_state = TitleBlockCell::Enabled;
1517  }
1518 }
1519 
1525  forgetSpanning();
1526  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
1527  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
1528  checkCellSpan(cells_[i][j]);
1529  applyCellSpan(cells_[i][j]);
1530  }
1531  }
1532 }
1533 
1545  if (!cell) return(false);
1546 
1547  cell -> span_state = TitleBlockCell::Enabled;
1548  cell -> applied_row_span = cell -> row_span;
1549  cell -> applied_col_span = cell -> col_span;
1550 
1551  // ensure the cell can span as far as required
1552  if (cell -> num_col + cell -> col_span >= columnsCount()) {
1553  cell -> applied_col_span = columnsCount() - 1 - cell -> num_col;
1554  cell -> span_state = TitleBlockCell::Restricted;
1555  }
1556  if (cell -> num_row + cell -> row_span >= rowsCount()) {
1557  cell -> applied_row_span = rowsCount() - 1 - cell -> num_row;
1558  cell -> span_state = TitleBlockCell::Restricted;
1559  }
1560 
1561  // ensure cells that will be spanned are either empty or free
1562  for (int i = cell -> num_col ; i <= cell -> num_col + cell -> applied_col_span ; ++ i) {
1563  for (int j = cell -> num_row ; j <= cell -> num_row + cell -> applied_row_span ; ++ j) {
1564  if (i == cell -> num_col && j == cell -> num_row) continue;
1565 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
1566  qDebug() << Q_FUNC_INFO << "span check" << i << j;
1567 #endif
1568  TitleBlockCell *current_cell = cells_[i][j];
1569  if (current_cell -> cell_type != TitleBlockCell::EmptyCell || (current_cell -> spanner_cell && current_cell -> spanner_cell != cell)) {
1570  cell -> span_state = TitleBlockCell::Disabled;
1571  return(true);
1572  }
1573  }
1574  }
1575 
1576  return(true);
1577 }
1578 
1585  if (!cell || (!cell -> row_span && !cell -> col_span)) return;
1586  if (cell -> span_state == TitleBlockCell::Disabled) return;
1587 
1588  // goes through every spanned cell
1589  for (int i = cell -> num_col ; i <= cell -> num_col + cell -> applied_col_span ; ++ i) {
1590  for (int j = cell -> num_row ; j <= cell -> num_row + cell -> applied_row_span ; ++ j) {
1591  // avoid the spanning cell itself
1592  if (i == cell -> num_col && j == cell -> num_row) continue;
1593 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
1594  qDebug() << Q_FUNC_INFO << "marking cell at" << j << i << "as spanned by cell at" << cell -> num_row << cell -> num_col;
1595 #endif
1596  // marks all spanned cells with the spanning cell
1597  cells_[i][j] -> spanner_cell = cell;
1598  }
1599  }
1600 }
1601 
1606  for (int i = 0 ; i < columns_width_.count() ; ++ i) {
1607  for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
1608  cells_[i][j] -> num_col = i;
1609  cells_[i][j] -> num_row = j;
1610  }
1611  }
1612 }
1613 
1619  applyRowColNums();
1620  applyCellSpans();
1621 }
1622 
1628 int TitleBlockTemplate::lengthRange(int start, int end, const QList<int> &lengths_list) const {
1629  if (start > end || start >= lengths_list.count() || end > lengths_list.count()) {
1630 #ifdef TITLEBLOCK_TEMPLATE_DEBUG
1631  qDebug() << Q_FUNC_INFO << "wont use" << start << "and" << end;
1632 #endif
1633  return(0);
1634  }
1635 
1636  int length = 0;
1637  for (int i = start ; i < end ; ++i) {
1638  length += lengths_list[i];
1639  }
1640  return(length);
1641 }
1642 
bool attributeIsAnInteger(const QDomElement &, const QString &, int *=nullptr)
Definition: qet.cpp:200
bool loadFromXmlFile(const QString &)
NamesList value
Text displayed by the cell.
QHash< QString, QByteArray > data_logos_
Logos raw data.
the length is just a fraction of the length that is still available when other types of lengths have ...
Definition: qet.h:146
bool loadGrid(const QDomElement &)
QList< TitleBlockCell * > createColumn()
bool addLogoFromFile(const QString &, const QString &=QString())
void parseColumns(const QString &)
QHash< QString, QPixmap > bitmap_logos_
Pixmaps for bitmap logos.
bool saveLogoToFile(const QString &, const QString &)
QList< int > rows_heights_
rows heights – simple integers
QList< TitleBlockCell * > registered_cells_
Cells objects created rattached to this template, but not mandatorily used.
int lengthRange(int, int, const QList< int > &) const
QString name_
name identifying the Title Block Template within its parent collection
int columnTypeCount(QET::TitleBlockColumnLength)
void saveGrid(QDomElement &) const
void saveCells(QDomElement &) const
QList< TitleBlockCell * > createRow()
void applyCellSpan(TitleBlockCell *)
TitleBlockTemplate * clone() const
void setColumnDimension(int, const TitleBlockDimension &)
the length is absolute and should be applied as is
Definition: qet.h:144
void renderCell(QPainter &, const TitleBlockCell &, const DiagramContext &, const QRect &) const
static void drawRectangle(const QString &filepath, double, double, double, double, const int &colorcode)
Definition: createdxf.cpp:565
QHash< QString, QSvgRenderer * > vector_logos_
Rendered objects for vector logos.
bool loadFromXmlElement(const QDomElement &)
int alignment
Where the label+text should be displayed within the visual cell.
QList< int > columnsWidth(int) const
void setAllSpans(const QHash< TitleBlockCell *, QPair< int, int > > &)
QStringList listOfVariables()
Get list of variables.
QString name(const QString &=QString()) const
Definition: nameslist.cpp:205
QList< TitleBlockDimension > columns_width_
columns widths –
TitleBlockColumnLength
enum used to specify the type of a length
Definition: qet.h:143
void saveLogos(QDomElement &) const
QString interpreteVariables(const QString &, const DiagramContext &) const
static const double sheetHeight
Definition: createdxf.h:56
QPixmap bitmapLogo(const QString &) const
bool addLogo(const QString &, QByteArray *, const QString &="svg", const QString &="xml")
void setLogoStorage(const QString &, const QString &)
void exportCellToXml(TitleBlockCell *, QDomElement &) const
void parseRows(const QString &)
int value
Numeric value.
Definition: dimension.h:34
static double yScale
Definition: createdxf.h:58
void saveLogo(const QString &, QDomElement &) const
TitleBlockDimension columnDimension(int)
void render(QPainter &, const DiagramContext &, int) const
bool loadLogos(const QDomElement &, bool=false)
QList< QString > keys(KeyOrder=None) const
QList< TitleBlockCell * > createCellsList(int)
bool display_label
Whether to display the label or not.
the cell span parameters should be applied without restriction
QList< int > rowsHeights() const
int font_size
Font size the text should be rendered with.
the cell span parameters should be applied with some restrictions
bool checkCell(const QDomElement &, TitleBlockCell **=nullptr)
bool isEmpty() const
Definition: nameslist.cpp:80
QString toShortString() const
Definition: dimension.cpp:49
bool checkCellSpan(TitleBlockCell *)
bool removeLogo(const QString &)
static double xScale
Definition: createdxf.h:57
void saveCell(TitleBlockCell *, QDomElement &, bool=false) const
void renderTextCell(QPainter &, const QString &, const TitleBlockCell &, const QRectF &) const
the length is just a fraction of the total available length
Definition: qet.h:145
QHash< TitleBlockCell *, QPair< int, int > > getAllSpans() const
void setRowDimension(int, const TitleBlockDimension &)
QIcon tr
Definition: qeticons.cpp:204
TitleBlockTemplate(QObject *=nullptr)
QList< TitleBlockCell * > takeRow(int)
bool writeXmlFile(QDomDocument &xml_doc, const QString &filepath, QString *error_message=nullptr)
Definition: qet.cpp:544
QString logoType(const QString &) const
void renderTextCellDxf(QString &, const QString &, const TitleBlockCell &, qreal, qreal, qreal, qreal, int) const
bool loadLogo(const QDomElement &)
static QFont fontForCell(const TitleBlockCell &)
NamesList label
Label displayed by the cell.
int columnTypeTotal(QET::TitleBlockColumnLength)
bool hadjust
Whether to reduce the font size if the text does not fit in the cell.
void loadInformation(const QDomElement &)
TitleBlockCell * cell(int, int) const
QList< QString > logos() const
QHash< QString, QString > storage_logos_
Logos applied storage type (e.g. "xml" or "base64")
bool saveToXmlFile(const QString &)
bool renameLogo(const QString &, const QString &)
the cell span parameters should not applied at all
void loadCell(const QDomElement &)
void renderDxf(QRectF &, const DiagramContext &, int, QString &, int) const
TitleBlockCell * createCell(const TitleBlockCell *=nullptr)
void setInformation(const QString &)
static QFont diagramTextsFont(qreal=-1.0)
QETApp::diagramTextsFont The font to use By default the font is "sans Serif" and size 9...
Definition: qetapp.cpp:910
bool insertRow(int, const QList< TitleBlockCell *> &, int=-1)
QString logo_reference
Logo displayed by this cell, it it is a logo cell.
bool saveToXmlElement(QDomElement &) const
void saveInformation(QDomElement &) const
QSet< TitleBlockCell * > spannedCells(const TitleBlockCell *, bool=false) const
QString finalTextForCell(const TitleBlockCell &, const DiagramContext &) const
static void drawTextAligned(const QString &fileName, const QString &text, double x, double y, double height, double rotation, double oblique, int hAlign, int vAlign, double xAlign, int colour, bool leftAlign=false, float scale=0)
Definition: createdxf.cpp:747
TemplateCellType type() const
bool loadCells(const QDomElement &)
QSvgRenderer * vectorLogo(const QString &) const
QHash< QString, QString > type_logos_
Logos types (e.g. "png", "jpeg", "svg")
QList< QList< TitleBlockCell * > > cells_
Cells grid.
bool insertColumn(const TitleBlockDimension &, const QList< TitleBlockCell *> &, int=-1)
QList< TitleBlockCell * > takeColumn(int)
QString information() const
QET::TitleBlockColumnLength type
Kind of length.
Definition: dimension.h:33