The title block template editor now supports pasting multiple cells.

git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/branches/0.3@1597 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
xavier 2012-03-25 16:34:53 +00:00
parent e31a8a375e
commit 8b1e7904c4
6 changed files with 181 additions and 18 deletions

View File

@ -59,7 +59,6 @@ bool ModifyTitleBlockCellCommand::mergeWith(const QUndoCommand *command) {
if (other) {
if (other -> modified_cell_ == modified_cell_) {
if (other -> new_values_.keys() == new_values_.keys()) {
qDebug() << Q_FUNC_INFO << "merging";
new_values_ = other -> new_values_;
return(true);
}
@ -208,6 +207,14 @@ void TitleBlockTemplateCommand::refreshView() {
view_ -> refresh();
}
/**
Refresh the view, including layout reloading, if any.
*/
void TitleBlockTemplateCommand::refreshLayout() {
if (!view_) return;
view_ -> updateLayout();
}
/**
This static method is a convenience to create a ModifyTemplateGridCommand
that adds a row to \a tbtemplate at \a index.
@ -933,21 +940,80 @@ void PasteTemplateCellsCommand::updateText() {
Undo a paste action.
*/
void PasteTemplateCellsCommand::undo() {
bool span_management = erased_cells_.count() > 1;
foreach (TitleBlockCell *cell, erased_cells_.keys()) {
cell -> loadContentFromCell(erased_cells_.value(cell));
}
refreshView();
if (span_management) {
// restore all span parameters as they were before the paste operation.
tbtemplate_ -> setAllSpans(spans_before_);
tbtemplate_ -> applyCellSpans();
refreshLayout();
} else {
refreshView();
}
}
/**
Redo a paste action.
*/
void PasteTemplateCellsCommand::redo() {
// paste the first cell ony
foreach (TitleBlockCell *cell, erased_cells_.keys()) {
cell -> loadContentFromCell(pasted_cells_.value(cell));
// we only play with spans when pasting more than one cell.
bool span_management = erased_cells_.count() > 1;
if (span_management) {
// When pasting several cells, we may modify the span parameters of existing,
// non-erased cells. The easiest way to ensure everything can be restored at its
// initial state consists in saving the span parameters of every cell.
if (spans_before_.isEmpty()) {
spans_before_ = tbtemplate_ -> getAllSpans();
}
}
// copy data from each pasted cell into each erased cell
foreach (TitleBlockCell *cell, erased_cells_.keys()) {
if (span_management) {
// the erased cell may be spanned by another cell
if (TitleBlockCell *spanning_cell = cell -> spanner_cell) {
// for the moment, we simply cancel the whole spanning
tbtemplate_ -> forgetSpanning(spanning_cell);
}
}
// copy non-spans data
TitleBlockCell pasted_cell = pasted_cells_.value(cell);
cell -> loadContentFromCell(pasted_cell);
if (span_management) {
// copy spans data
if ((pasted_cell.row_span != cell -> row_span) || (pasted_cell.col_span != cell -> col_span)) {
tbtemplate_ -> forgetSpanning(cell);
// 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)) {
// ... 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
tbtemplate_ -> forgetSpanning(spanned_cell -> spanner_cell);
}
}
// set the spanner_cell attribute of newly spanned cells
tbtemplate_ -> applyCellSpan(cell);
}
}
}
}
if (span_management) {
refreshLayout();
} else {
refreshView();
}
refreshView();
}
/**

View File

@ -78,6 +78,7 @@ class TitleBlockTemplateCommand : public QUndoCommand {
TitleBlockTemplateView *view() const;
void setView(TitleBlockTemplateView *);
void refreshView();
void refreshLayout();
// attributes
protected:
@ -300,6 +301,8 @@ class PasteTemplateCellsCommand : public TitleBlockTemplateCommand {
// attributes
public:
/// Spans before operation
QHash<TitleBlockCell *, QPair<int, int> > spans_before_;
/// Pasted cells
QHash<TitleBlockCell *, TitleBlockCell> pasted_cells_;
/// Existing cells impacted by the paste operation

View File

@ -160,6 +160,10 @@ QList<TitleBlockCell *> TitleBlockTemplateView::copy() {
xml_export.appendChild(tbtpartial);
foreach (TitleBlockCell *cell, copied_cells) {
tbtemplate_ -> exportCellToXml(cell, tbtpartial);
tbtpartial.setAttribute("row", cell -> num_row);
tbtpartial.setAttribute("col", cell -> num_col);
tbtpartial.setAttribute("row_span", cell -> row_span);
tbtpartial.setAttribute("col_span", cell -> col_span);
}
QClipboard *clipboard = QApplication::clipboard();
@ -202,6 +206,24 @@ QList<TitleBlockCell> TitleBlockTemplateView::pastedCells() {
if (e.tagName() == "empty" || e.tagName() == "field" || e.tagName() == "logo") {
TitleBlockCell cell;
cell.loadContentFromXml(e);
int row_num = -1, col_num = -1, row_span = -1, col_span = -1;
if (!QET::attributeIsAnInteger(e, "row", &row_num) || row_num < 0) {
continue;
}
if (!QET::attributeIsAnInteger(e, "col", &col_num) || col_num < 0) {
continue;
}
cell.num_row = row_num;
cell.num_col = col_num;
// parse the rowspan and colspan attributes
if (QET::attributeIsAnInteger(e, "rowspan", &row_span) && row_span > 0) {
cell.row_span = row_span;
}
if (QET::attributeIsAnInteger(e, "colspan", &col_span) && col_span > 0) {
cell.col_span = col_span;
}
pasted_cells << cell;
}
}
@ -212,22 +234,27 @@ QList<TitleBlockCell> TitleBlockTemplateView::pastedCells() {
Import the cells described in the clipboard.
*/
void TitleBlockTemplateView::paste() {
if (!tbtemplate_) return;
QList<TitleBlockCell> pasted_cells = pastedCells();
// paste the first cell only
if (!pasted_cells.count()) return;
// onto the first selected one
// the top left cell among the selected ones will be used to position the pasted cells
TitleBlockTemplateVisualCell *selected_cell = selectedCellsSet().topLeftCell();
if (!selected_cell) return;
TitleBlockCell *erased_cell = selected_cell -> cell();
if (!erased_cell) return;
// change num_row and num_col attributes of pasted cells so they get positionned relatively to selected_cell
normalizeCells(pasted_cells, erased_cell -> num_row, erased_cell -> num_col);
PasteTemplateCellsCommand *paste_command = new PasteTemplateCellsCommand(tbtemplate_);
paste_command -> addCell(erased_cell, *erased_cell, pasted_cells.first());
foreach (TitleBlockCell cell, pasted_cells) {
TitleBlockCell *erased_cell = tbtemplate_ -> cell(cell.num_row, cell.num_col);
if (!erased_cell) continue;
paste_command -> addCell(erased_cell, *erased_cell, cell);
}
requestGridModification(paste_command);
/// TODO paste more cells, using some kind of heuristic to place them?
}
/**
@ -768,6 +795,25 @@ bool TitleBlockTemplateView::event(QEvent *event) {
return(QGraphicsView::event(event));
}
/**
Given a cells list, change their position so the top left one is at row \a x and column \a y.
@param cells Cells list
*/
void TitleBlockTemplateView::normalizeCells(QList<TitleBlockCell> &cells, int x, int y) const {
if (!cells.count()) return;
int min_row = cells.at(0).num_row;
int min_col = cells.at(0).num_col;
for (int i = 1 ; i < cells.count() ; ++ i) {
if (cells.at(i).num_row < min_row) min_row = cells.at(i).num_row;
if (cells.at(i).num_col < min_col) min_col = cells.at(i).num_col;
}
for (int i = 0 ; i < cells.count() ; ++ i) {
cells[i].num_row = cells[i].num_row - min_row + x;
cells[i].num_col = cells[i].num_col - min_col + y;
}
}
/**
Load the \a tbt title block template.
If a different template was previously loaded, it is deleted.

View File

@ -97,6 +97,7 @@ class TitleBlockTemplateView : public QGraphicsView {
virtual qreal zoomFactor() const;
virtual void fillWithEmptyCells();
virtual bool event(QEvent *);
virtual void normalizeCells(QList<TitleBlockCell> &, int x = 0, int y = 0) const;
signals:
void selectedCellsChanged(QList<TitleBlockCell *>);

View File

@ -1021,6 +1021,35 @@ QSet<TitleBlockCell *> TitleBlockTemplate::spannedCells(const TitleBlockCell *gi
return(set);
}
/**
Export the span parameters of all cell in the current grid.
*/
QHash<TitleBlockCell *, QPair<int, int> > TitleBlockTemplate::getAllSpans() const {
QHash<TitleBlockCell *, QPair<int, int> > spans;
for (int j = 0 ; j < rows_heights_.count() ; ++ j) {
for (int i = 0 ; i < columns_width_.count() ; ++ i) {
spans.insert(
cells_[i][j],
QPair<int, int>(
cells_[i][j] -> row_span,
cells_[i][j] -> col_span
)
);
}
}
return(spans);
}
/**
Restore a set of span parameters.
*/
void TitleBlockTemplate::setAllSpans(const QHash<TitleBlockCell *, QPair<int, int> > &spans) {
foreach (TitleBlockCell *cell, spans.keys()) {
cell -> row_span = spans[cell].first;
cell -> col_span = spans[cell].second;
}
}
/**
@param logo_name Logo name to be added / replaced
@param logo_data Logo data
@ -1333,6 +1362,21 @@ void TitleBlockTemplate::forgetSpanning() {
}
}
/**
Set the spanner_cell attribute of every cell spanned by \a spanning_cell to 0.
@param modify_cell (Optional, defaults to true) Whether to set row_span and col_span of \a spanning_cell to 0.
*/
void TitleBlockTemplate::forgetSpanning(TitleBlockCell *spanning_cell, bool modify_cell) {
if (!spanning_cell) return;
foreach (TitleBlockCell *spanned_cell, spannedCells(spanning_cell)) {
spanned_cell -> spanner_cell = 0;
}
if (modify_cell) {
spanning_cell -> row_span = 0;
spanning_cell -> col_span = 0;
}
}
/**
Forget any previously applied span, then apply again all spans defined
by existing cells.

View File

@ -83,6 +83,8 @@ class TitleBlockTemplate : public QObject {
TitleBlockCell *cell(int, int) const;
QSet<TitleBlockCell *> spannedCells(const TitleBlockCell *) const;
QHash<TitleBlockCell *, QPair<int, int> > getAllSpans() const;
void setAllSpans(const QHash<TitleBlockCell *, QPair<int, int> > &);
bool addLogo(const QString &, QByteArray *, const QString & = "svg", const QString & = "xml");
bool addLogoFromFile(const QString &, const QString & = QString());
bool removeLogo(const QString &);
@ -96,6 +98,13 @@ class TitleBlockTemplate : public QObject {
void render(QPainter &, const DiagramContext &, int) const;
void renderCell(QPainter &, const TitleBlockCell &, const DiagramContext &, const QRect &) const;
QString toString() const;
void applyCellSpans();
void forgetSpanning();
void forgetSpanning(TitleBlockCell *, bool = true);
bool checkCellSpan(TitleBlockCell *);
void applyCellSpan(TitleBlockCell *);
void applyRowColNums();
void rowColsChanged();
protected:
void loadInformation(const QDomElement &);
@ -121,12 +130,6 @@ class TitleBlockTemplate : public QObject {
int lengthRange(int, int, const QList<int> &) const;
QString finalTextForCell(const TitleBlockCell &, const DiagramContext &) const;
void renderTextCell(QPainter &, const QString &, const TitleBlockCell &, const QRectF &) const;
void applyCellSpans();
void forgetSpanning();
bool checkCellSpan(TitleBlockCell *);
void applyCellSpan(TitleBlockCell *);
void applyRowColNums();
void rowColsChanged();
// attributes
private: