diff --git a/sources/titleblock/templatecommands.cpp b/sources/titleblock/templatecommands.cpp index d7d49b078..bcea567b8 100644 --- a/sources/titleblock/templatecommands.cpp +++ b/sources/titleblock/templatecommands.cpp @@ -608,6 +608,9 @@ MergeCellsCommand::MergeCellsCommand(const TitleBlockTemplateCellsSet &merged_ce // store the former values of the row_span and col_span attributes of the spanning cell row_span_before_ = spanning_cell_ -> row_span; col_span_before_ = spanning_cell_ -> col_span; + applied_row_span_before_ = spanning_cell_ -> applied_row_span; + applied_col_span_before_ = spanning_cell_ -> applied_col_span; + span_state_before_ = spanning_cell_ -> span_state; // calculate their new values after the merge operation TitleBlockCell *bottom_right_cell = getBottomRightCell(merged_cells); @@ -671,9 +674,12 @@ void MergeCellsCommand::undo() { cell -> spanner_cell = spanner_cells_before_merge_[cell]; } - // restore the row_span and col_span attributes of the spanning cell + // restore the span-related attributes of the spanning cell spanning_cell_ -> row_span = row_span_before_; spanning_cell_ -> col_span = col_span_before_; + spanning_cell_ -> applied_row_span = applied_row_span_before_; + spanning_cell_ -> applied_col_span = applied_col_span_before_; + spanning_cell_ -> span_state = span_state_before_; if (view_) view_ -> updateLayout(); } @@ -693,6 +699,9 @@ void MergeCellsCommand::redo() { // set the new values of the row_span and col_span attributes spanning_cell_ -> row_span = row_span_after_; spanning_cell_ -> col_span = col_span_after_; + spanning_cell_ -> applied_row_span = row_span_after_; + spanning_cell_ -> applied_col_span = col_span_after_; + spanning_cell_ -> span_state = TitleBlockCell::Enabled; if (view_) view_ -> updateLayout(); } @@ -745,6 +754,9 @@ SplitCellsCommand::SplitCellsCommand(const TitleBlockTemplateCellsSet &splitted_ spanned_cells_ = tbtemplate_ -> spannedCells(spanning_cell_); row_span_before_ = spanning_cell_ -> row_span; col_span_before_ = spanning_cell_ -> col_span; + applied_row_span_before_ = spanning_cell_ -> row_span; + applied_col_span_before_ = spanning_cell_ -> col_span; + span_state_before_ = spanning_cell_ -> span_state; setText( QString( @@ -805,6 +817,9 @@ void SplitCellsCommand::undo() { // the spanning cell span again spanning_cell_ -> row_span = row_span_before_; spanning_cell_ -> col_span = col_span_before_; + spanning_cell_ -> applied_row_span = applied_row_span_before_; + spanning_cell_ -> applied_col_span = applied_col_span_before_; + spanning_cell_ -> span_state = span_state_before_; if (view_) view_ -> updateLayout(); } @@ -823,6 +838,7 @@ void SplitCellsCommand::redo() { // the spanning cell does not span anymore spanning_cell_ -> row_span = 0; spanning_cell_ -> col_span = 0; + tbtemplate_ -> checkCellSpan(spanning_cell_); if (view_) view_ -> updateLayout(); } @@ -989,13 +1005,14 @@ void PasteTemplateCellsCommand::redo() { if ((pasted_cell.row_span != cell -> row_span) || (pasted_cell.col_span != cell -> col_span)) { tbtemplate_ -> forgetSpanning(cell); + // Note: the code below is similar to TitleBlockTemplate::checkCell() but is more aggressive (spans deletion). // set the new/pasted span parameters cell -> row_span = qBound(0, pasted_cell.row_span, tbtemplate_ -> rowsCount() - 1 - cell -> num_row); cell -> col_span = qBound(0, pasted_cell.col_span, tbtemplate_ -> columnsCount() - 1 - cell -> num_col); if (cell -> row_span || cell -> col_span) { // browse newly spanned cells... - foreach (TitleBlockCell *spanned_cell, tbtemplate_ -> spannedCells(cell)) { + foreach (TitleBlockCell *spanned_cell, tbtemplate_ -> spannedCells(cell, true)) { // ... to ensure they are not already spanned by other cells if (spanned_cell -> spanner_cell && spanned_cell -> spanner_cell != cell) { // if so, simply cancel the whole spanning diff --git a/sources/titleblock/templatecommands.h b/sources/titleblock/templatecommands.h index f9c1e2371..56364b290 100644 --- a/sources/titleblock/templatecommands.h +++ b/sources/titleblock/templatecommands.h @@ -198,6 +198,9 @@ class MergeCellsCommand : public TitleBlockTemplateCommand { QHash spanner_cells_before_merge_; int row_span_before_; ///< the row_span attribute of the spanning cell before the merge int col_span_before_; ///< the col_span attribute of the spanning cell before the merge + int applied_row_span_before_; ///< the applied_row_span attribute of the spanning cell before the merge + int applied_col_span_before_; ///< the applied_col_span attribute of the spanning cell before the merge + int span_state_before_; ///< the span_state attribute of the spanning cell before the merge int row_span_after_; ///< the row_span attribute of the spanning cell after the merge int col_span_after_; ///< the col_span attribute of the spanning cell after the merge }; @@ -222,8 +225,11 @@ class SplitCellsCommand : public TitleBlockTemplateCommand { private: TitleBlockCell *spanning_cell_; ///< the cell spanning over the other ones QSet spanned_cells_; ///< the spanned cells - int row_span_before_; ///< the row_span attribute of the spanning cell after the merge - int col_span_before_; ///< the col_span attribute of the spanning cell after the merge + int row_span_before_; ///< the row_span attribute of the spanning cell before splitting + int col_span_before_; ///< the col_span attribute of the spanning cell before splitting + int applied_row_span_before_; ///< the applied_row_span attribute of the spanning cell before splitting + int applied_col_span_before_; ///< the applied_col_span attribute of the spanning cell before splitting + int span_state_before_; ///< the span_state attribute of the spanning cell before splitting }; /** diff --git a/sources/titleblock/templateview.cpp b/sources/titleblock/templateview.cpp index 76e9eac2d..1a603d48c 100644 --- a/sources/titleblock/templateview.cpp +++ b/sources/titleblock/templateview.cpp @@ -648,8 +648,10 @@ void TitleBlockTemplateView::updateRowsHelperCells() { QList heights = tbtemplate_ -> rowsHeights(); for (int i = 0 ; i < row_count ; ++ i) { HelperCell *current_row_cell = static_cast(tbgrid_ -> itemAt(ROW_OFFSET + i, 0)); - current_row_cell -> setType(QET::Absolute); // rows always have absolute heights - current_row_cell -> label = QString(tr("%1px", "format displayed in rows helper cells")).arg(heights.at(i)); + if (current_row_cell) { + current_row_cell -> setType(QET::Absolute); // rows always have absolute heights + current_row_cell -> label = QString(tr("%1px", "format displayed in rows helper cells")).arg(heights.at(i)); + } } } @@ -661,8 +663,10 @@ void TitleBlockTemplateView::updateColumnsHelperCells() { for (int i = 0 ; i < col_count ; ++ i) { TitleBlockDimension current_col_dim = tbtemplate_ -> columnDimension(i); HelperCell *current_col_cell = static_cast(tbgrid_ -> itemAt(1, COL_OFFSET + i)); - current_col_cell -> setType(current_col_dim.type); - current_col_cell -> label = current_col_dim.toString(); + if (current_col_cell) { + current_col_cell -> setType(current_col_dim.type); + current_col_cell -> label = current_col_dim.toString(); + } } } @@ -673,7 +677,6 @@ void TitleBlockTemplateView::updateColumnsHelperCells() { void TitleBlockTemplateView::addCells() { int col_count = tbtemplate_ -> columnsCount(); int row_count = tbtemplate_ -> rowsCount(); - if (row_count < 1 || col_count < 1) return; // we add a big cell to show the total width total_width_helper_cell_ = new SplittedHelperCell(); @@ -725,7 +728,13 @@ void TitleBlockTemplateView::addCells() { if (cell -> spanner_cell) continue; TitleBlockTemplateVisualCell *cell_item = new TitleBlockTemplateVisualCell(); cell_item -> setTemplateCell(tbtemplate_, cell); - tbgrid_ -> addItem(cell_item, ROW_OFFSET + j, COL_OFFSET + i, cell -> row_span + 1, cell -> col_span + 1); + + int row_span = 0, col_span = 0; + if (cell -> span_state != TitleBlockCell::Disabled) { + row_span = cell -> applied_row_span; + col_span = cell -> applied_col_span; + } + tbgrid_ -> addItem(cell_item, ROW_OFFSET + j, COL_OFFSET + i, row_span + 1, col_span + 1); } } } @@ -773,7 +782,6 @@ void TitleBlockTemplateView::fillWithEmptyCells() { for (int i = 0 ; i < col_count ; ++ i) { for (int j = 0 ; j < row_count ; ++ j) { if (tbgrid_ -> itemAt(ROW_OFFSET + j, COL_OFFSET + i)) continue; - qDebug() << Q_FUNC_INFO << "looks like there is nothing there (" << j << "," << i << ")"; TitleBlockTemplateVisualCell *cell_item = new TitleBlockTemplateVisualCell(); if (TitleBlockCell *target_cell = tbtemplate_ -> cell(j, i)) { qDebug() << Q_FUNC_INFO << "target_cell" << target_cell; diff --git a/sources/titleblockcell.cpp b/sources/titleblockcell.cpp index 3f19b63ff..e74fe601b 100644 --- a/sources/titleblockcell.cpp +++ b/sources/titleblockcell.cpp @@ -7,6 +7,8 @@ TitleBlockCell::TitleBlockCell() { cell_type = TitleBlockCell::EmptyCell; num_row = num_col = -1; row_span = col_span = 0; + applied_row_span = applied_col_span = 0; + span_state = TitleBlockCell::Enabled; spanner_cell = 0; display_label = true; alignment = Qt::AlignCenter | Qt::AlignVCenter; diff --git a/sources/titleblockcell.h b/sources/titleblockcell.h index 21f45eb0e..066784f83 100644 --- a/sources/titleblockcell.h +++ b/sources/titleblockcell.h @@ -30,6 +30,11 @@ class TitleBlockCell { TextCell, LogoCell }; + enum TemplateCellSpanState { + Disabled, ///< the cell span parameters should not applied at all + Enabled, ///< the cell span parameters should be applied without restriction + Restricted ///< the cell span parameters should be applied with some restrictions + }; // Constructor, destructor public: @@ -58,6 +63,9 @@ class TitleBlockCell { int num_col; ///< x coordinate of the cell within its parent title block template grid int row_span; ///< number of extra rows spanned by this cell int col_span; ///< number of extra columns spanned by this cell + int span_state; ///< how should row_span and col_span be applied given other cells in the parent template + int applied_row_span; ///< Actually applied row span + int applied_col_span; ///< Actually applied column span TitleBlockCell *spanner_cell; ///< Cell spanning this cell, if any QString value_name; ///< name of the cell; not displayed when the title block template is rendered NamesList value; ///< Text displayed by the cell diff --git a/sources/titleblocktemplate.cpp b/sources/titleblocktemplate.cpp index b4e3fef49..b5ec6c15b 100644 --- a/sources/titleblocktemplate.cpp +++ b/sources/titleblocktemplate.cpp @@ -154,8 +154,8 @@ bool TitleBlockTemplate::saveToXmlFile(const QString &filepath) { @return true if the export succeeds, false otherwise */ bool TitleBlockTemplate::saveToXmlElement(QDomElement &xml_element) const { - // we are supposed to have at least one row/column and a name - if (!columnsCount() || !rowsCount() || name_.isEmpty()) return(false); + // we are supposed to have at least a name + if (name_.isEmpty()) return(false); xml_element.setTagName("titleblocktemplate"); xml_element.setAttribute("name", name_); @@ -538,8 +538,6 @@ bool TitleBlockTemplate::checkCell(const QDomElement &xml_element, TitleBlockCel #endif int row_num, col_num, row_span, col_span; - bool has_row_span = false; - bool has_col_span = false; row_num = col_num = -1; row_span = col_span = 0; @@ -565,28 +563,15 @@ bool TitleBlockTemplate::checkCell(const QDomElement &xml_element, TitleBlockCel // parse the rowspan and colspan attributes if (QET::attributeIsAnInteger(xml_element, "rowspan", &row_span) && row_span > 0) { - if (row_num + row_span >= row_count) row_span = row_count - 1 - row_num; - has_row_span = true; + cell_ptr -> row_span = row_span; } if (QET::attributeIsAnInteger(xml_element, "colspan", &col_span) && col_span > 0) { - if (col_num + col_span >= col_count) col_span = col_count - 1 - col_num; - has_col_span = true; + cell_ptr -> col_span = col_span; } + // these attributes are stored "as is" -- whether they can be applied directly or must be restricted will be checked later - // check if we can span on the required area - //if (!checkCellSpan(cell_ptr)) return(false); - - // at this point, the cell is ok - we fill the adequate cells in the matrix -#ifdef TITLEBLOCK_TEMPLATE_DEBUG - qDebug() << Q_FUNC_INFO << "cell writing"; -#endif - if (has_row_span) cell_ptr -> row_span = row_span; - if (has_col_span) cell_ptr -> col_span = col_span; if (titleblock_cell_ptr) *titleblock_cell_ptr = cell_ptr; - - //applyCellSpan(cell_ptr); - return(true); } @@ -1004,15 +989,23 @@ TitleBlockCell *TitleBlockTemplate::cell(int row, int col) const { /** @param cell A cell belonging to this title block template + @param ignore_span_state (Optional, defaults to false) If true, will consider + cells theoretically spanned (i.e. row_span and col_span attributes). + Otherwise, will take span_state attribute into account. @return the set of cells spanned by the provided cell Note the returned set does not include the spanning, provided cell */ -QSet TitleBlockTemplate::spannedCells(const TitleBlockCell *given_cell) const { +QSet TitleBlockTemplate::spannedCells(const TitleBlockCell *given_cell, bool ignore_span_state) const { QSet set; - if (!given_cell || !given_cell -> spans()) return(set); + if (!given_cell) return(set); + if (!ignore_span_state && given_cell -> span_state == TitleBlockCell::Disabled) return(set); - for (int i = given_cell -> num_col ; i <= given_cell -> num_col + given_cell -> col_span ; ++ i) { - for (int j = given_cell -> num_row ; j <= given_cell -> num_row + given_cell -> row_span ; ++ j) { + int final_row_span = ignore_span_state ? given_cell -> row_span : given_cell -> applied_row_span; + int final_col_span = ignore_span_state ? given_cell -> col_span : given_cell -> applied_col_span; + if (!final_row_span && !final_col_span) return(set); + + for (int i = given_cell -> num_col ; i <= given_cell -> num_col + final_col_span ; ++ i) { + for (int j = given_cell -> num_row ; j <= given_cell -> num_row + final_row_span ; ++ j) { if (i == given_cell -> num_col && j == given_cell -> num_row) continue; TitleBlockCell *current_cell = cell(j, i); if (current_cell) set << current_cell; @@ -1241,8 +1234,14 @@ void TitleBlockTemplate::render(QPainter &painter, const DiagramContext &diagram // calculate the border rect of the current cell int x = lengthRange(0, cells_[i][j] -> num_col, widths); int y = lengthRange(0, cells_[i][j] -> num_row, rows_heights_); - int w = lengthRange(cells_[i][j] -> num_col, cells_[i][j] -> num_col + 1 + cells_[i][j] -> col_span, widths); - int h = lengthRange(cells_[i][j] -> num_row, cells_[i][j] -> num_row + 1 + cells_[i][j] -> row_span, rows_heights_); + + int row_span = 0, col_span = 0; + if (cells_[i][j] -> span_state != TitleBlockCell::Disabled) { + row_span = cells_[i][j] -> applied_row_span; + col_span = cells_[i][j] -> applied_col_span; + } + int w = lengthRange(cells_[i][j] -> num_col, cells_[i][j] -> num_col + 1 + col_span, widths); + int h = lengthRange(cells_[i][j] -> num_row, cells_[i][j] -> num_row + 1 + row_span, rows_heights_); QRect cell_rect(x, y, w, h); renderCell(painter, *cells_[i][j], diagram_context, cell_rect); @@ -1374,6 +1373,9 @@ void TitleBlockTemplate::forgetSpanning(TitleBlockCell *spanning_cell, bool modi if (modify_cell) { spanning_cell -> row_span = 0; spanning_cell -> col_span = 0; + spanning_cell -> applied_row_span = 0; + spanning_cell -> applied_col_span = 0; + spanning_cell -> span_state = TitleBlockCell::Enabled; } } @@ -1385,39 +1387,54 @@ void TitleBlockTemplate::applyCellSpans() { forgetSpanning(); for (int i = 0 ; i < columns_width_.count() ; ++ i) { for (int j = 0 ; j < rows_heights_.count() ; ++ j) { - if (checkCellSpan(cells_[i][j])) { - applyCellSpan(cells_[i][j]); - } + checkCellSpan(cells_[i][j]); + applyCellSpan(cells_[i][j]); } } } /** - Check whether a given cell can be spanned according to its row_span and col_span attributes + Check whether a given cell can be spanned according to its row_span and + col_span attributes. the following attributes of \a cell are updated + according to what is really possible: + * applied_col_span + * applied_row_span + * span_state @param cell Cell we want to check - @return true if the spanned + @return false if no check could be performed, true otherwise */ -bool TitleBlockTemplate::checkCellSpan(TitleBlockCell *cell/*, int policy = TitleBlockTemplate::???*/) { +bool TitleBlockTemplate::checkCellSpan(TitleBlockCell *cell) { if (!cell) return(false); - if (!cell -> row_span && !cell -> col_span) return(true); + + cell -> span_state = TitleBlockCell::Enabled; + cell -> applied_row_span = cell -> row_span; + cell -> applied_col_span = cell -> col_span; // ensure the cell can span as far as required - if (cell -> num_col + cell -> col_span >= columnsCount()) return(false); - if (cell -> num_row + cell -> row_span >= rowsCount()) return(false); + if (cell -> num_col + cell -> col_span >= columnsCount()) { + cell -> applied_col_span = columnsCount() - 1 - cell -> num_col; + cell -> span_state = TitleBlockCell::Restricted; + } + if (cell -> num_row + cell -> row_span >= rowsCount()) { + cell -> applied_row_span = rowsCount() - 1 - cell -> num_row; + cell -> span_state = TitleBlockCell::Restricted; + } - // ensure cells that will be spanned are free/empty - for (int i = cell -> num_col ; i <= cell -> num_col + cell -> col_span ; ++ i) { - for (int j = cell -> num_row ; j <= cell -> num_row + cell -> row_span ; ++ j) { + // ensure cells that will be spanned are either empty or free + for (int i = cell -> num_col ; i <= cell -> num_col + cell -> applied_col_span ; ++ i) { + for (int j = cell -> num_row ; j <= cell -> num_row + cell -> applied_row_span ; ++ j) { if (i == cell -> num_col && j == cell -> num_row) continue; #ifdef TITLEBLOCK_TEMPLATE_DEBUG qDebug() << Q_FUNC_INFO << "span check" << i << j; #endif TitleBlockCell *current_cell = cells_[i][j]; if (current_cell -> cell_type != TitleBlockCell::EmptyCell || (current_cell -> spanner_cell && current_cell -> spanner_cell != cell)) { - return(false); + cell -> span_state = TitleBlockCell::Disabled; + return(true); } } } + return(true); } @@ -1428,10 +1445,11 @@ bool TitleBlockTemplate::checkCellSpan(TitleBlockCell *cell/*, int policy = Titl */ void TitleBlockTemplate::applyCellSpan(TitleBlockCell *cell) { if (!cell || (!cell -> row_span && !cell -> col_span)) return; + if (cell -> span_state == TitleBlockCell::Disabled) return; // goes through every spanned cell - for (int i = cell -> num_col ; i <= cell -> num_col + cell -> col_span ; ++ i) { - for (int j = cell -> num_row ; j <= cell -> num_row + cell -> row_span ; ++ j) { + for (int i = cell -> num_col ; i <= cell -> num_col + cell -> applied_col_span ; ++ i) { + for (int j = cell -> num_row ; j <= cell -> num_row + cell -> applied_row_span ; ++ j) { // avoid the spanning cell itself if (i == cell -> num_col && j == cell -> num_row) continue; #ifdef TITLEBLOCK_TEMPLATE_DEBUG diff --git a/sources/titleblocktemplate.h b/sources/titleblocktemplate.h index 548eb8c54..0f215c3a7 100644 --- a/sources/titleblocktemplate.h +++ b/sources/titleblocktemplate.h @@ -82,7 +82,7 @@ class TitleBlockTemplate : public QObject { QList createColumn(); TitleBlockCell *cell(int, int) const; - QSet spannedCells(const TitleBlockCell *) const; + QSet spannedCells(const TitleBlockCell *, bool = false) const; QHash > getAllSpans() const; void setAllSpans(const QHash > &); bool addLogo(const QString &, QByteArray *, const QString & = "svg", const QString & = "xml");