/* Copyright 2006-2020 The QElectroTech Team This file is part of QElectroTech. QElectroTech is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. QElectroTech is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with QElectroTech. If not, see . */ #include "dynamicelementtextmodel.h" #include "dynamicelementtextitem.h" #include #include #include #include #include #include #include "QPropertyUndoCommand/qpropertyundocommand.h" #include "qetapp.h" #include "element.h" #include "compositetexteditdialog.h" #include "terminal.h" #include "conductor.h" #include "elementtextitemgroup.h" #include "qeticons.h" #include "diagram.h" #include "addelementtextcommand.h" #include "alignmenttextdialog.h" static int src_txt_row = 0; static int usr_txt_row = 1; static int info_txt_row = 2; static int compo_txt_row = 3; static int size_txt_row = 4; static int font_txt_row = 5; static int color_txt_row = 6; static int frame_txt_row = 7; static int width_txt_row = 8; static int x_txt_row = 9; static int y_txt_row = 10; static int rot_txt_row = 11; static int align_txt_row = 12; static int align_grp_row = 0; static int x_grp_row = 1; static int y_grp_row = 2; static int rot_grp_row = 3; static int adjust_grp_row = 4; static int frame_grp_row = 5; static int hold_to_bottom_grp_row = 6; DynamicElementTextModel::DynamicElementTextModel(Element *element, QObject *parent) : QStandardItemModel(parent), m_element(element) { setColumnCount(2); setHeaderData(0, Qt::Horizontal, tr("Propriété"), Qt::DisplayRole); setHeaderData(1, Qt::Horizontal, tr("Valeur"), Qt::DisplayRole); connect(this, &DynamicElementTextModel::itemChanged, this, &DynamicElementTextModel::itemDataChanged); connect(m_element.data(), &Element::textsGroupAdded, this, &DynamicElementTextModel::addGroup, Qt::DirectConnection); connect(m_element.data(), &Element::textsGroupAboutToBeRemoved, this, &DynamicElementTextModel::removeGroup, Qt::DirectConnection); connect(m_element.data(), &Element::textRemoved, this, &DynamicElementTextModel::removeText, Qt::DirectConnection); connect(m_element.data(), &Element::textRemovedFromGroup, this, &DynamicElementTextModel::removeTextFromGroup, Qt::DirectConnection); connect(m_element.data(), &Element::textAdded, this, &DynamicElementTextModel::addText, Qt::DirectConnection); connect(m_element.data(), &Element::textAddedToGroup, this, &DynamicElementTextModel::addTextToGroup, Qt::DirectConnection); for (ElementTextItemGroup *grp : m_element.data()->textGroups()) addGroup(grp); for (DynamicElementTextItem *deti : m_element.data()->dynamicTextItems()) this->appendRow(itemsForText(deti)); } DynamicElementTextModel::~DynamicElementTextModel() { //Connection is not destroy automaticaly, //because was not connected to a slot, but a lambda for(DynamicElementTextItem *deti : m_hash_text_connect.keys()) setConnection(deti, false); for(ElementTextItemGroup *group : m_hash_group_connect.keys()) setConnection(group, false); } /** @brief DynamicElementTextModel::indexIsInGroup @param index @return True if the index represent a group or an item in a group */ bool DynamicElementTextModel::indexIsInGroup(const QModelIndex &index) const { QStandardItem *item = itemFromIndex(index); if(item) { while (item->parent()) item = item->parent(); if(m_groups_list.values().contains(item)) return true; else return false; } return false; } /** @brief DynamicElementTextModel::itemsForText @param deti @return The items for the text deti, if the text deti is already managed by this model the returned list is empty The returned items haven't got the same number of childs if the text is in a group or not. */ QList DynamicElementTextModel::itemsForText( DynamicElementTextItem *deti) { QList qsi_list; if(m_texts_list.keys().contains(deti)) return qsi_list; QStandardItem *qsi = new QStandardItem(deti->toPlainText()); qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled |Qt::ItemIsDragEnabled); qsi->setIcon(QET::Icons::PartText); //Source of text QStandardItem *src = new QStandardItem(tr("Source du texte")); src->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QString title; if (deti->textFrom() == DynamicElementTextItem::UserText) title = tr("Texte utilisateur"); else if (deti->textFrom() == DynamicElementTextItem::ElementInfo) title = tr("Information de l'élément"); else title = tr("Texte composé"); QStandardItem *srca = new QStandardItem(title); srca->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); srca->setData(textFrom, Qt::UserRole+1); qsi_list << src << srca; qsi->appendRow(qsi_list); //User text QStandardItem *usr = new QStandardItem(tr("Texte")); usr->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *usra = new QStandardItem(deti->toPlainText()); usra->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); usra->setData(DynamicElementTextModel::userText, Qt::UserRole+1); qsi_list.clear(); qsi_list << usr << usra; qsi->appendRow(qsi_list); //Info text QStandardItem *info = new QStandardItem(tr("Information")); info->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *infoa = new QStandardItem( QETApp::elementTranslatedInfoKey( deti->infoName())); infoa->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); //Use to know the edited thing infoa->setData(DynamicElementTextModel::infoText, Qt::UserRole+1); //Use to know to element info name infoa->setData(deti->infoName(), Qt::UserRole+2); qsi_list.clear(); qsi_list << info << infoa; qsi->appendRow(qsi_list); //Composite text QStandardItem *composite = new QStandardItem(tr("Texte composé")); composite->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); DiagramContext dc; if(deti->elementUseForInfo()) dc = deti->elementUseForInfo()->elementInformations(); QStandardItem *compositea = new QStandardItem(deti->compositeText().isEmpty() ? tr("Mon texte composé") : autonum::AssignVariables::replaceVariable( deti->compositeText(), dc)); compositea->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); //Use to know the edited thing compositea->setData(DynamicElementTextModel::compositeText, Qt::UserRole+1); //Use to know to element composite formula compositea->setData(deti->compositeText(), Qt::UserRole+2); qsi_list.clear(); qsi_list << composite << compositea; qsi->appendRow(qsi_list); //Size QStandardItem *size = new QStandardItem(tr("Taille")); size->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *siza = new QStandardItem(); siza->setData(deti->font().pointSize(), Qt::EditRole); siza->setData(DynamicElementTextModel::size, Qt::UserRole+1); siza->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << size << siza; qsi->appendRow(qsi_list); //Font QStandardItem *font = new QStandardItem(tr("Police")); font->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *fonta = new QStandardItem(); fonta->setData(deti->font().family(), Qt::EditRole); fonta->setData(DynamicElementTextModel::font, Qt::UserRole+1); fonta->setData(deti->font(), Qt::UserRole+2); fonta->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << font << fonta; qsi->appendRow(qsi_list); //Color QStandardItem *color = new QStandardItem(tr("Couleur")); color->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *colora = new QStandardItem; colora->setData(deti->color(), Qt::ForegroundRole); colora->setData(deti->color(), Qt::EditRole); colora->setData(DynamicElementTextModel::color, Qt::UserRole+1); colora->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << color << colora; qsi->appendRow(qsi_list); //Frame QStandardItem *frame = new QStandardItem(tr("Cadre")); frame->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *frame_a = new QStandardItem; frame_a->setCheckable(true); frame_a->setCheckState(deti->frame()? Qt::Checked : Qt::Unchecked); frame_a->setData(DynamicElementTextModel::frame, Qt::UserRole+1); frame_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); qsi_list.clear(); qsi_list << frame << frame_a; qsi->appendRow(qsi_list); //Width QStandardItem *width = new QStandardItem(tr("Largeur")); width->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *width_a = new QStandardItem; width_a->setData(deti->textWidth(), Qt::EditRole); width_a->setData(DynamicElementTextModel::textWidth, Qt::UserRole+1); width_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << width << width_a; qsi->appendRow(qsi_list); if(deti->parentGroup() == nullptr) { //X pos QStandardItem *x_pos = new QStandardItem(tr("Position X")); x_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *x_pos_a = new QStandardItem; x_pos_a->setData(deti->pos().x(), Qt::EditRole); x_pos_a->setData(DynamicElementTextModel::pos, Qt::UserRole+1); x_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << x_pos << x_pos_a; qsi->appendRow(qsi_list); //Y pos QStandardItem *y_pos = new QStandardItem(tr("Position Y")); y_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *y_pos_a = new QStandardItem; y_pos_a->setData(deti->pos().y(), Qt::EditRole); y_pos_a->setData(DynamicElementTextModel::pos, Qt::UserRole+1); y_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << y_pos << y_pos_a; qsi->appendRow(qsi_list); //Rotation QStandardItem *rot = new QStandardItem(tr("Rotation")); rot->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *rot_a = new QStandardItem; rot_a->setData(deti->rotation(), Qt::EditRole); rot_a->setData(DynamicElementTextModel::rotation, Qt::UserRole+1); rot_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear();; qsi_list << rot << rot_a; qsi->appendRow(qsi_list); //Alignment QStandardItem *alignment = new QStandardItem(tr("Alignement")); alignment->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *alignmenta = new QStandardItem(tr("Éditer")); alignmenta->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); alignmenta->setData(DynamicElementTextModel::txtAlignment, Qt::UserRole+1); alignmenta->setData(QVariant::fromValue(deti->alignment()), Qt::UserRole+2); qsi_list.clear(); qsi_list << alignment << alignmenta; qsi->appendRow(qsi_list); } qsi_list.clear(); QStandardItem *empty_qsi = new QStandardItem(0); empty_qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); qsi_list << qsi << empty_qsi; m_texts_list.insert(deti, qsi); blockSignals(true); enableSourceText(deti, deti->textFrom()); blockSignals(false); setConnection(deti, true); return qsi_list; } /** @brief DynamicElementTextModel::addText @param deti */ void DynamicElementTextModel::addText(DynamicElementTextItem *deti) { this->appendRow(itemsForText(deti)); } /** @brief DynamicElementTextModel::removeText @param deti */ void DynamicElementTextModel::removeText(DynamicElementTextItem *deti) { if (!m_texts_list.contains(deti)) return; QModelIndex text_index = m_texts_list.value(deti)->index(); this->removeRow(text_index.row(), text_index.parent()); m_texts_list.remove(deti); setConnection(deti, false); } /** @brief DynamicElementTextModel::textFromIndex @param index @return the text associated with index. Returned value can be nullptr Index can be a child of an index associated with a text and can be the column 0 or 1. */ DynamicElementTextItem *DynamicElementTextModel::textFromIndex( const QModelIndex &index) const { if(!index.isValid()) return nullptr; if (QStandardItem *item = itemFromIndex(index)) return textFromItem(item); else return nullptr; } /** @brief DynamicElementTextModel::textFromItem @param item @return the text associated with item. Return value can be nullptr item can be a child of an item associated with a text and can be the column 0 or 1. Note can return nullptr */ DynamicElementTextItem *DynamicElementTextModel::textFromItem( QStandardItem *item) const { //Get the item of the column 0 if(item->column() == 1) { if(item->parent()) item = item->parent()->child(item->row(), 0); else item = itemFromIndex(index(item->row(),0)); } //Item haven't got parent, so they can be only a text or a group if(!item->parent()) { if(m_texts_list.values().contains(item)) return m_texts_list.key(item); else return nullptr; } QStandardItem *text_item = item; while (text_item->parent()) text_item = text_item->parent(); if (m_texts_list.values().contains(text_item)) //The item is a text return m_texts_list.key(text_item); else if (m_groups_list.values().contains(text_item)) //The item is a group { QStandardItem *previous = item; QStandardItem *top = item; //At the end of the while, previous must be the text //and top the group while(top->parent()) { previous = top; top = top->parent(); } if(m_texts_list.values().contains(previous)) return m_texts_list.key(previous); else return nullptr; } else return nullptr; } /** @brief DynamicElementTextModel::indexFromText @param text @return the QModelIndex for text, or a default QModelIndex if not match */ QModelIndex DynamicElementTextModel::indexFromText( DynamicElementTextItem *text) const { if(m_texts_list.contains(text)) return m_texts_list.value(text)->index(); else return QModelIndex(); } /** @brief DynamicElementTextModel::undoForEditedText @param deti @return A QUndoCommand that describe all changes made for deti. Each change made for deti is append as a child of the returned QUndoCommand. In other word, if the returned QUndoCommand have no child, that mean there is no change. */ QUndoCommand *DynamicElementTextModel::undoForEditedText( DynamicElementTextItem *deti, QUndoCommand *parent_undo) const { QUndoCommand *undo = nullptr; if(parent_undo) undo = parent_undo; else undo = new QUndoCommand(tr("Éditer un texte d'élément")); if (!m_texts_list.contains(deti)) return undo; QStandardItem *text_qsi = m_texts_list.value(deti); QString from = text_qsi->child(src_txt_row,1)->data(Qt::DisplayRole).toString(); if ((from == tr("Texte utilisateur")) && (deti->textFrom() != DynamicElementTextItem::UserText)) new QPropertyUndoCommand(deti, "textFrom", QVariant(deti->textFrom()), QVariant(DynamicElementTextItem::UserText), undo); else if ((from == tr("Information de l'élément")) && (deti->textFrom() != DynamicElementTextItem::ElementInfo)) new QPropertyUndoCommand(deti, "textFrom", QVariant(deti->textFrom()), QVariant(DynamicElementTextItem::ElementInfo), undo); else if ((from == tr("Texte composé")) && (deti->textFrom() != DynamicElementTextItem::CompositeText)) new QPropertyUndoCommand(deti, "textFrom", QVariant(deti->textFrom()), QVariant(DynamicElementTextItem::CompositeText), undo); if(from == tr("Texte utilisateur")) { QString text = text_qsi->child(usr_txt_row,1)->data(Qt::DisplayRole).toString(); if (text != deti->text()) new QPropertyUndoCommand(deti, "text", QVariant(deti->text()), QVariant(text), undo); } else if (from == tr("Information de l'élément")) { QString info_name = text_qsi->child(info_txt_row,1)->data(Qt::UserRole+2).toString(); if(info_name != deti->infoName()) new QPropertyUndoCommand(deti, "infoName", QVariant(deti->infoName()), QVariant(info_name), undo); } else if (from == tr("Texte composé")) { QString composite_text = text_qsi->child(compo_txt_row,1)->data(Qt::UserRole+2).toString(); if(composite_text != deti->compositeText()) new QPropertyUndoCommand(deti, "compositeText", QVariant(deti->compositeText()), QVariant(composite_text), undo); } int fs = text_qsi->child(size_txt_row,1)->data(Qt::EditRole).toInt(); if (fs != deti->font().pointSize()) { QFont font = deti->font(); font.setPointSize(fs); QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "font", QVariant(deti->font()), QVariant(font), undo); quc->setText(tr("Modifier la taille d'un texte d'élément")); } QFont font = text_qsi->child(font_txt_row, 1)->data(Qt::UserRole+2).value(); if (font != deti->font()) { QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "font", QVariant(deti->font()), QVariant(font), undo); quc->setText(tr("Modifier la police d'un texte d'élément")); } QColor color = text_qsi->child(color_txt_row,1)->data(Qt::EditRole).value(); if(color != deti->color()) { QUndoCommand *quc = new QPropertyUndoCommand(deti, "color", QVariant(deti->color()), QVariant(color), undo); quc->setText(tr("Modifier la couleur d'un texte d'élément")); } bool frame = text_qsi->child(frame_txt_row,1)->checkState() == Qt::Checked? true : false; if(frame != deti->frame()) { QUndoCommand *quc = new QPropertyUndoCommand(deti, "frame", QVariant(deti->frame()), QVariant(frame), undo); quc->setText(tr("Modifier le cadre d'un texte d'élément")); } qreal text_width = text_qsi->child(width_txt_row, 1)->data(Qt::EditRole).toDouble(); if(text_width != deti->textWidth()) { QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "textWidth", QVariant(deti->textWidth()), QVariant(text_width), undo); quc->setAnimated(true, false); quc->setText(tr("Modifier la largeur d'un texte d'élément")); } //When text is in a group, they're isn't item for position of the text if(text_qsi->child(x_txt_row,1) && text_qsi->child(y_txt_row,1)) { QPointF p(text_qsi->child(x_txt_row,1)->data(Qt::EditRole).toDouble(), text_qsi->child(y_txt_row,1)->data(Qt::EditRole).toDouble()); if(p != deti->pos()) { QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "pos", QVariant(deti->pos()), QVariant(p), undo); quc->setAnimated(true, false); quc->setText(tr("Déplacer un texte d'élément")); } } //When text is in a group, they're isn't item for the rotation of the text if(text_qsi->child(rot_txt_row,1)) { qreal rot = text_qsi->child(rot_txt_row,1)->data(Qt::EditRole).toDouble(); rot = QET::correctAngle(rot); if(rot != deti->rotation()) { QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "rotation", QVariant(deti->rotation()), QVariant(rot), undo); quc->setAnimated(true, false); quc->setText(tr("Pivoter un texte d'élément")); } } //When text is in a groupe, they're isn't item for alignment of the text if(text_qsi->child(align_txt_row, 1)) { Qt::Alignment alignment = text_qsi->child(align_txt_row, 1)->data(Qt::UserRole+2).value(); if (alignment != deti->alignment()) { QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "alignment", QVariant(deti->alignment()), QVariant(alignment), undo); quc->setText(tr("Modifier l'alignement d'un texte d'élément")); } } return undo; } /** @brief DynamicElementTextModel::undoForEditedGroup @param group @param parent_undo @return A QUndoCommand that describe all changes made for group. Each change made for group is append as a child of the returned QUndoCommand. In other word, if the returned QUndoCommand have no child, that mean there is no change. */ QUndoCommand *DynamicElementTextModel::undoForEditedGroup( ElementTextItemGroup *group, QUndoCommand *parent_undo) const { QUndoCommand *undo = nullptr; if(parent_undo) undo = parent_undo; else undo = new QUndoCommand(tr("Éditer un groupe de textes")); if (!m_groups_list.contains(group)) return undo; QStandardItem *group_qsi = m_groups_list.value(group); QString alignment = group_qsi->child(align_grp_row,1)->data(Qt::DisplayRole).toString(); if((alignment == tr("Gauche")) && (group->alignment() != Qt::AlignLeft)) new QPropertyUndoCommand(group, "alignment", QVariant(group->alignment()), QVariant(Qt::AlignLeft), undo); else if((alignment == tr("Droite")) && (group->alignment() != Qt::AlignRight)) new QPropertyUndoCommand(group, "alignment", QVariant(group->alignment()), QVariant(Qt::AlignRight), undo); else if((alignment == tr("Centre")) && (group->alignment() != Qt::AlignVCenter)) new QPropertyUndoCommand(group, "alignment", QVariant(group->alignment()), QVariant(Qt::AlignVCenter), undo); if (group_qsi->child(hold_to_bottom_grp_row, 1)->checkState() == Qt::Unchecked) { QPointF pos(group_qsi->child(x_grp_row,1)->data(Qt::EditRole).toDouble(), group_qsi->child(y_grp_row,1)->data(Qt::EditRole).toDouble()); if(group->pos() != pos) { QPropertyUndoCommand *qpuc = new QPropertyUndoCommand(group, "pos", QVariant(group->pos()), QVariant(pos), undo); qpuc->setAnimated(true, false); } qreal rotation = group_qsi->child(rot_grp_row,1)->data(Qt::EditRole).toDouble(); if(group->rotation() != rotation) { QPropertyUndoCommand *qpuc = new QPropertyUndoCommand(group, "rotation", QVariant(group->rotation()), QVariant(rotation), undo); qpuc->setAnimated(true, false); } } int v_adjustment = group_qsi->child(adjust_grp_row,1)->data(Qt::EditRole).toInt(); if(group->verticalAdjustment() != v_adjustment) new QPropertyUndoCommand(group, "verticalAdjustment", QVariant(group->verticalAdjustment()), QVariant(v_adjustment), undo); QString name = group_qsi->data(Qt::DisplayRole).toString(); if(group->name() != name) new QPropertyUndoCommand(group, "name", QVariant(group->name()), QVariant(name), undo); bool hold_to_bottom = group_qsi->child(hold_to_bottom_grp_row, 1)->checkState() == Qt::Checked? true : false; if(group->holdToBottomPage() != hold_to_bottom) new QPropertyUndoCommand(group, "holdToBottomPage", QVariant(group->holdToBottomPage()), QVariant(hold_to_bottom), undo); bool frame_ = group_qsi->child(frame_grp_row, 1)->checkState() == Qt::Checked? true : false; if(group->frame() != frame_) new QPropertyUndoCommand(group, "frame", QVariant(group->frame()), QVariant(frame_), undo); return undo; } /** @brief DynamicElementTextModel::AddGroup Add a text item group to this model @param group */ void DynamicElementTextModel::addGroup(ElementTextItemGroup *group) { if(m_groups_list.keys().contains(group)) return; //Group QStandardItem *grp = new QStandardItem(group->name()); grp->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable); grp->setIcon(QET::Icons::textGroup); QStandardItem *empty_qsi = new QStandardItem(0); empty_qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QList qsi_list; qsi_list << grp << empty_qsi; this->insertRow(0, qsi_list); m_groups_list.insert(group, grp); //Alignment QStandardItem *alignment = new QStandardItem(tr("Alignement")); alignment->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QString text; switch (group->alignment()) { case Qt::AlignLeft: text = tr("Gauche"); break; case Qt::AlignRight: text = tr("Droite"); break; case Qt::AlignVCenter: text = tr("Centre"); break; default: break;} QStandardItem *alignment_a = new QStandardItem(text); alignment_a->setData(DynamicElementTextModel::grpAlignment, Qt::UserRole+1); alignment_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << alignment << alignment_a; grp->appendRow(qsi_list); //X pos QStandardItem *x_pos = new QStandardItem(tr("Position X")); x_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *x_pos_a = new QStandardItem; x_pos_a->setData(group->pos().x(), Qt::EditRole); x_pos_a->setData(DynamicElementTextModel::grpPos, Qt::UserRole+1); x_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << x_pos << x_pos_a; grp->appendRow(qsi_list); //Y pos QStandardItem *y_pos = new QStandardItem(tr("Position Y")); y_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *y_pos_a = new QStandardItem; y_pos_a->setData(group->pos().y(), Qt::EditRole); y_pos_a->setData(DynamicElementTextModel::grpPos, Qt::UserRole+1); y_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << y_pos << y_pos_a; grp->appendRow(qsi_list); //Rotation QStandardItem *rot = new QStandardItem(tr("Rotation")); rot->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); QStandardItem *rot_a = new QStandardItem; rot_a->setData(group->rotation(), Qt::EditRole); rot_a->setData(DynamicElementTextModel::grpRotation, Qt::UserRole+1); rot_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << rot << rot_a; grp->appendRow(qsi_list); //Vertical adjustment QStandardItem *v_adj = new QStandardItem(tr("Ajustement vertical")); v_adj->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); QStandardItem *v_adj_a = new QStandardItem; v_adj_a->setData(group->verticalAdjustment(), Qt::EditRole); v_adj_a->setData(DynamicElementTextModel::grpVAdjust, Qt::UserRole+1); v_adj_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi_list.clear(); qsi_list << v_adj << v_adj_a; grp->appendRow(qsi_list); //Frame QStandardItem *frame_ = new QStandardItem(tr("Cadre")); frame_->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); QStandardItem *frame_a = new QStandardItem; frame_a->setCheckable(true); frame_a->setCheckState(group->frame()? Qt::Checked : Qt::Unchecked); frame_a->setData(DynamicElementTextModel::grpFrame, Qt::UserRole+1); frame_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); qsi_list.clear(); qsi_list << frame_ << frame_a; grp->appendRow(qsi_list); //Hold to the bottom of the page QStandardItem *hold_bottom = new QStandardItem(tr("Maintenir en bas de page")); hold_bottom->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); QStandardItem *hold_bottom_a = new QStandardItem(); hold_bottom_a->setCheckable(true); hold_bottom_a->setCheckState(group->holdToBottomPage() ? Qt::Checked : Qt::Unchecked); hold_bottom_a->setData(DynamicElementTextModel::grpHoldBottom, Qt::UserRole+1); hold_bottom_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable); qsi_list.clear(); qsi_list << hold_bottom << hold_bottom_a; grp->appendRow(qsi_list); //Add the texts of the group for(DynamicElementTextItem *deti : group->texts()) { QStandardItem *group_item = m_groups_list.value(group); group_item->appendRow(itemsForText(deti)); } setConnection(group, true); enableGroupRotationAndPos(group); } /** @brief DynamicElementTextModel::removeGroup Remove the text item group from this model @param group */ void DynamicElementTextModel::removeGroup(ElementTextItemGroup *group) { if(m_groups_list.keys().contains(group)) { QModelIndex group_index = m_groups_list.value(group)->index(); this->removeRow(group_index.row(), group_index.parent()); m_groups_list.remove(group); setConnection(group, false); } } /** @brief DynamicElementTextModel::textAddedToGroup Add the text text to the group group @param deti @param group */ void DynamicElementTextModel::addTextToGroup(DynamicElementTextItem *deti, ElementTextItemGroup *group) { QStandardItem *group_item = m_groups_list.value(group); group_item->appendRow(itemsForText(deti)); } void DynamicElementTextModel::removeTextFromGroup(DynamicElementTextItem *deti, ElementTextItemGroup *group) { Q_UNUSED(group) if(m_texts_list.keys().contains(deti)) { QStandardItem *text_item = m_texts_list.value(deti); QModelIndex text_index = indexFromItem(text_item); removeRow(text_index.row(), text_index.parent()); m_texts_list.remove(deti); } } /** @brief DynamicElementTextModel::groupFromIndex @param index @return the group associated with index. Return value can be nullptr Index can be a child of an index associated with a group and can be the column 0 or 1. */ ElementTextItemGroup *DynamicElementTextModel::groupFromIndex( const QModelIndex &index) const { if(!index.isValid()) return nullptr; if (QStandardItem *item = itemFromIndex(index)) return groupFromItem(item); else return nullptr; } /** @brief DynamicElementTextModel::groupFromItem @param item @return the group associated with item. Return value can be nullptr item can be a child of an item associated with a group and can be the column 0 or 1. */ ElementTextItemGroup *DynamicElementTextModel::groupFromItem( QStandardItem *item) const { //Get the item of the column 0 if(item->column() == 1) { if(item->parent()) item = item->parent()->child(item->row(), 0); else item = itemFromIndex(index(item->row(),0)); } while (item->parent()) item = item->parent(); if(m_groups_list.values().contains(item)) return m_groups_list.key(item); else return nullptr; } /** @brief DynamicElementTextModel::indexFromGroup @param group @return The index associated to the group group or a default QModelIndex if not match */ QModelIndex DynamicElementTextModel::indexFromGroup( ElementTextItemGroup *group) const { if(m_groups_list.keys().contains(group)) return m_groups_list.value(group)->index(); else return QModelIndex(); } /** @brief DynamicElementTextModel::indexIsText @param index @return True if index represente a text, both for the column 0 and 1. Return false if index is a child of an index associated to a text. */ bool DynamicElementTextModel::indexIsText(const QModelIndex &index) const { QStandardItem *item = nullptr; //The item represent the second column if(index.column() == 1) { if(index.parent().isValid()) item = itemFromIndex(index.parent() .QModelIndex::model()->index( index.row(), 0)); else item = itemFromIndex(this->index(index.row(),0)); } else item = itemFromIndex(index); if(item && m_texts_list.values().contains(item)) return true; else return false; } /** @brief DynamicElementTextModel::indexIsGroup @param index @return True if index represente a group, both for the column 0 and 1. Return false if index is a child of an index associated to a group. */ bool DynamicElementTextModel::indexIsGroup(const QModelIndex &index) const { QStandardItem *item = nullptr; //The item represent the second column if(index.column() == 1) { if(index.parent().isValid()) item = itemFromIndex(index.parent() .QModelIndex::model()->index( index.row(),0)); else item = itemFromIndex(this->index(index.row(),0)); } else item = itemFromIndex(index); if(item && m_groups_list.values().contains(item)) return true; else return false; } bool DynamicElementTextModel::canDropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const { Q_UNUSED(action); if(data->hasFormat("application/x-qet-element-text-uuid")) { QModelIndex index; if(parent.isValid() && row != -1 && column !=1) //Insert in child of parent index = parent.QModelIndex::model()->index(row, column); else if (parent.isValid() && row == -1 && column == -1) //Drop in parent index = parent; QUuid uuid(data->text()); //The data is drop in a group if(indexIsInGroup(index)) { //Data is dragged from a text direct child of element for(DynamicElementTextItem *text : m_element.data()->dynamicTextItems()) if(text->uuid() == uuid) return true; //Data is dragged from a text in a group for(ElementTextItemGroup *group : m_element.data()->textGroups()) { for(DynamicElementTextItem *text : group->texts()) if(text->uuid() == uuid) return true; } return false; } else //The data is not drop in a group, then the action must be a drag of text from a group to the element { for(ElementTextItemGroup *group : m_element.data()->textGroups()) { for(DynamicElementTextItem *text : group->texts()) if(text->uuid() == uuid) return true; } } } return false; } /** @brief DynamicElementTextModel::dropMimeData @param data @param action @param row @param column @param parent @return In any case return false, for overwrite the default behavior of model. */ bool DynamicElementTextModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(action) if(data->hasFormat("application/x-qet-element-text-uuid")) { QUuid uuid(data->text()); DynamicElementTextItem *deti = nullptr; ElementTextItemGroup *group = nullptr; QModelIndex index; if(parent.isValid() && row != -1 && column !=1) //Insert in child of parent index = parent.QModelIndex::model()->index(row, column); else if (parent.isValid() && row == -1 && column == -1) //Drop in parent index = parent; //Darg and drop in a group of text if(indexIsInGroup(index)) { //The dragged text is a direct child of element for(DynamicElementTextItem *text : m_element.data()->dynamicTextItems()) { if(text->uuid() == uuid) { deti = text; group = groupFromIndex(index); if(group && deti) //Text successfully added in a group { m_element.data()->diagram()->undoStack().push(new AddTextToGroupCommand(deti, group)); return true; } } } //The dragged text is in a group for(ElementTextItemGroup *grp : m_element.data()->textGroups()) { for(DynamicElementTextItem *text : grp->texts()) { if(text->uuid() == uuid) { deti = text; group = groupFromIndex(index); //Text successfully moved from a group to another group if(group && deti) { QUndoStack &stack = m_element.data()->diagram()->undoStack(); stack.beginMacro(tr("Déplacer un texte dans un autre groupe")); stack.push(new RemoveTextFromGroupCommand(deti, grp)); stack.push(new AddTextToGroupCommand(deti, group)); stack.endMacro(); return true; } } } } return false; } else //Drag and drop in anaother place { //Get the dropped text for(ElementTextItemGroup *grp : m_element.data()->textGroups()) { for(DynamicElementTextItem *text : grp->texts()) { if(text->uuid() == uuid) { deti = text; group = grp; break; } } if(deti) break; } if(deti && group) //Text successfully removed from group { m_element.data()->diagram()->undoStack().push((new RemoveTextFromGroupCommand(deti, group))); return true; } return false; } } return false; } QMimeData *DynamicElementTextModel::mimeData(const QModelIndexList &indexes) const { QModelIndex index = indexes.first(); if (index.isValid()) { QStandardItem *item = itemFromIndex(index); if(item) { DynamicElementTextItem *deti = m_texts_list.key(item); if(deti) { QMimeData *mime_data = new QMimeData(); mime_data->setText(deti->uuid().toString()); mime_data->setData("application/x-qet-element-text-uuid", deti->uuid().toString().toLatin1()); return mime_data; } } } return QStandardItemModel::mimeData(indexes); } /** @brief DynamicElementTextModel::mimeTypes @return */ QStringList DynamicElementTextModel::mimeTypes() const { QStringList mime_list = QAbstractItemModel::mimeTypes(); mime_list << "application/x-qet-element-text-uuid"; return mime_list; } /** @brief DynamicElementTextModel::enableSourceText Enable the good field, according to the current source of text, for the edited text deti @param deti @param tf */ void DynamicElementTextModel::enableSourceText( DynamicElementTextItem *deti, DynamicElementTextItem::TextFrom tf) { if (!m_texts_list.contains(deti)) return; QStandardItem *qsi = m_texts_list.value(deti); bool usr = false, info = false, compo = false; switch (tf) { case DynamicElementTextItem::UserText: usr = true; break; case DynamicElementTextItem::ElementInfo: info = true; break; case DynamicElementTextItem::CompositeText: compo = true;break; } //User text qsi->child(usr_txt_row,0)->setEnabled(usr); qsi->child(usr_txt_row,1)->setEnabled(usr); //Info text qsi->child(info_txt_row,0)->setEnabled(info); qsi->child(info_txt_row,1)->setEnabled(info); //Composite text qsi->child(compo_txt_row,0)->setEnabled(compo); qsi->child(compo_txt_row,1)->setEnabled(compo); } /** @brief DynamicElementTextModel::enableGroupRotation Enable/disable the item "group rotation" according the option hold to bottom @param group */ void DynamicElementTextModel::enableGroupRotationAndPos( ElementTextItemGroup *group) { if(!m_groups_list.contains(group)) return; QStandardItem *qsi = m_groups_list.value(group); if(group->holdToBottomPage()) { qsi->child(x_grp_row, 0)->setFlags(Qt::ItemIsSelectable); qsi->child(x_grp_row, 1)->setFlags(Qt::ItemIsSelectable); qsi->child(y_grp_row, 0)->setFlags(Qt::ItemIsSelectable); qsi->child(y_grp_row, 1)->setFlags(Qt::ItemIsSelectable); qsi->child(rot_grp_row, 0)->setFlags(Qt::ItemIsSelectable); qsi->child(rot_grp_row, 1)->setFlags(Qt::ItemIsSelectable); } else { qsi->child(x_grp_row, 0)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); qsi->child(x_grp_row, 1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi->child(y_grp_row, 0)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); qsi->child(y_grp_row, 1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); qsi->child(rot_grp_row, 0)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); qsi->child(rot_grp_row, 1)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable); } } void DynamicElementTextModel::itemDataChanged(QStandardItem *qsi) { DynamicElementTextItem *deti = textFromItem(qsi); ElementTextItemGroup *etig = groupFromItem(qsi); if (!deti && !etig) return; if(deti) { QStandardItem *text_qsi = m_texts_list.value(deti); DiagramContext dc; if(deti->elementUseForInfo()) dc = deti->elementUseForInfo()->elementInformations(); if (qsi->data().toInt() == textFrom) { QString from = qsi->data(Qt::DisplayRole).toString(); if (from == tr("Texte utilisateur")) { enableSourceText(deti, DynamicElementTextItem::UserText); text_qsi->setData(text_qsi->child(usr_txt_row,1)->data(Qt::DisplayRole).toString()); } else if (from == tr("Information de l'élément")) { enableSourceText(deti, DynamicElementTextItem::ElementInfo); QString info = text_qsi->child(info_txt_row,1)->data(Qt::UserRole+2).toString(); text_qsi->setData(dc.value(info), Qt::DisplayRole); } else { enableSourceText(deti, DynamicElementTextItem::CompositeText); QString compo = text_qsi->child(compo_txt_row,1)->data(Qt::UserRole+2).toString(); text_qsi->setData(autonum::AssignVariables::replaceVariable(compo, dc), Qt::DisplayRole); } } else if (qsi->data().toInt() == userText) { QString text = qsi->data(Qt::DisplayRole).toString(); text_qsi->setData(text, Qt::DisplayRole); } else if (qsi->data().toInt() == infoText && deti->elementUseForInfo()) { QString info = qsi->data(Qt::UserRole+2).toString(); text_qsi->setData(dc.value(info), Qt::DisplayRole); } else if (qsi->data().toInt() == compositeText && deti->elementUseForInfo()) { QString compo = qsi->data(Qt::UserRole+2).toString(); text_qsi->setData(autonum::AssignVariables::replaceVariable(compo, dc), Qt::DisplayRole); } } //We emit the signal only if qsi is in the second column, //because the data are stored on this column //the first column is use only for display the title of the property, //except for the name of texts group if((m_groups_list.values().contains(qsi) || qsi->column() == 1) && !m_block_dataChanged) emit dataChanged(); if(deti) deti->updateXref(); } /** @brief DynamicElementTextModel::setConnection Set up the connection for deti to keep up to date the data of this model and the text. Is notably use with the use of QUndoCommand. @param deti - text to setup connection @param set - true = set connection - false unset connection */ void DynamicElementTextModel::setConnection(DynamicElementTextItem *deti, bool set) { if(set) { if(m_hash_text_connect.keys().contains(deti)) return; QList connection_list; connection_list << connect(deti, &DynamicElementTextItem::colorChanged, [deti,this](){this->updateDataFromText(deti, color);}); connection_list << connect(deti, &DynamicElementTextItem::fontChanged, [deti,this](){this->updateDataFromText(deti, font);}); connection_list << connect(deti, &DynamicElementTextItem::textFromChanged, [deti,this](){this->updateDataFromText(deti, textFrom);}); connection_list << connect(deti, &DynamicElementTextItem::textChanged, [deti,this](){this->updateDataFromText(deti, userText);}); connection_list << connect(deti, &DynamicElementTextItem::infoNameChanged, [deti,this](){this->updateDataFromText(deti, infoText);}); connection_list << connect(deti, &DynamicElementTextItem::xChanged, [deti,this](){this->updateDataFromText(deti, pos);}); connection_list << connect(deti, &DynamicElementTextItem::yChanged, [deti,this](){this->updateDataFromText(deti, pos);}); connection_list << connect(deti, &DynamicElementTextItem::frameChanged, [deti,this](){this->updateDataFromText(deti, frame);}); connection_list << connect(deti, &DynamicElementTextItem::rotationChanged, [deti,this](){this->updateDataFromText(deti, rotation);}); connection_list << connect(deti, &DynamicElementTextItem::textWidthChanged,[deti,this](){this->updateDataFromText(deti, textWidth);}); connection_list << connect(deti, &DynamicElementTextItem::compositeTextChanged, [deti, this]() {this->updateDataFromText(deti, compositeText);}); m_hash_text_connect.insert(deti, connection_list); } else { if(!m_hash_text_connect.keys().contains(deti)) return; for (const QMetaObject::Connection& con : m_hash_text_connect.value(deti)) disconnect(con); m_hash_text_connect.remove(deti); } } /** @brief DynamicElementTextModel::setConnection Set up the connection for group to keep up to date the data of this model and the group. Is notably use with the use of QUndoCommand. @param group group to setup the connection @param set true = set connection - false unset connection */ void DynamicElementTextModel::setConnection(ElementTextItemGroup *group, bool set) { if(set) { if(m_hash_group_connect.keys().contains(group)) return; QList connection_list; connection_list << connect(group, &ElementTextItemGroup::alignmentChanged, [group, this]() {this->updateDataFromGroup(group, grpAlignment);}); connection_list << connect(group, &ElementTextItemGroup::rotationChanged, [group, this]() {this->updateDataFromGroup(group, grpRotation);}); connection_list << connect(group, &ElementTextItemGroup::verticalAdjustmentChanged, [group, this]() {this->updateDataFromGroup(group, grpVAdjust);}); connection_list << connect(group, &ElementTextItemGroup::verticalAdjustmentChanged, [group, this]() {this->updateDataFromGroup(group, grpName);}); connection_list << connect(group, &ElementTextItemGroup::holdToBottomPageChanged, [group, this]() {this->updateDataFromGroup(group, grpHoldBottom);}); connection_list << connect(group, &ElementTextItemGroup::xChanged, [group, this]() {this->updateDataFromGroup(group, grpPos);}); connection_list << connect(group, &ElementTextItemGroup::yChanged, [group, this]() {this->updateDataFromGroup(group, grpPos);}); connection_list << connect(group, &ElementTextItemGroup::frameChanged, [group, this]() {this->updateDataFromGroup(group, grpFrame);}); m_hash_group_connect.insert(group, connection_list); } else { if(!m_hash_group_connect.keys().contains(group)) return; for (const QMetaObject::Connection& con : m_hash_group_connect.value(group)) disconnect(con); m_hash_group_connect.remove(group); } } void DynamicElementTextModel::updateDataFromText(DynamicElementTextItem *deti, ValueType type) { QStandardItem *qsi = m_texts_list.value(deti); if (!qsi) return; m_block_dataChanged = true; switch (type) { case textFrom: { switch (deti->textFrom()) { case DynamicElementTextItem::UserText: qsi->child(0,1)->setData(tr("Texte utilisateur"), Qt::DisplayRole); break; case DynamicElementTextItem::ElementInfo : qsi->child(0,1)->setData(tr("Information de l'élément"), Qt::DisplayRole); break; case DynamicElementTextItem::CompositeText : qsi->child(0,1)->setData(tr("Texte composé"), Qt::DisplayRole); break; } enableSourceText(deti, deti->textFrom()); qsi->setData(deti->toPlainText(), Qt::DisplayRole); break; } case userText: { qsi->setData(deti->toPlainText(), Qt::DisplayRole); qsi->child(usr_txt_row,1)->setData(deti->toPlainText(), Qt::DisplayRole); qsi->setData(deti->toPlainText(), Qt::DisplayRole); break; } case infoText: { qsi->setData(deti->toPlainText(), Qt::DisplayRole); QString info_name = deti->infoName(); qsi->child(info_txt_row,1)->setData(info_name, Qt::UserRole+2); qsi->child(info_txt_row,1)->setData(QETApp::elementTranslatedInfoKey(info_name), Qt::DisplayRole); break; } case compositeText: { qsi->setData(deti->toPlainText(), Qt::DisplayRole); qsi->child(compo_txt_row,1)->setData(deti->compositeText(), Qt::UserRole+2); qsi->child(compo_txt_row,1)->setData(deti->toPlainText(), Qt::DisplayRole); qsi->setData(deti->toPlainText(), Qt::DisplayRole); break; } case size: //qsi->child(size_txt_row,1)->setData(deti->fontSize(), Qt::EditRole); break; case font: { QFont f(deti->font()); qsi->child(font_txt_row,1)->setData(f.family(), Qt::EditRole); qsi->child(font_txt_row,1)->setData(f, Qt::UserRole+2); qsi->child(size_txt_row,1)->setData(f.pointSize(), Qt::EditRole); break; } case color: { qsi->child(color_txt_row,1)->setData(deti->color(), Qt::EditRole); qsi->child(color_txt_row,1)->setData(deti->color(), Qt::ForegroundRole); break; } case pos: { if(qsi->child(x_txt_row,1)) qsi->child(x_txt_row,1)->setData(deti->pos().x(), Qt::EditRole); if(qsi->child(y_txt_row,1)) qsi->child(y_txt_row,1)->setData(deti->pos().y(), Qt::EditRole); break; } case frame: { qsi->child(frame_txt_row,1)->setCheckState(deti->frame()? Qt::Checked : Qt::Unchecked); break; } case rotation: { if(qsi->child(rot_txt_row,1)) qsi->child(rot_txt_row,1)->setData(deti->rotation(), Qt::EditRole); break; } case textWidth: { qsi->child(width_txt_row,1)->setData(deti->textWidth(), Qt::EditRole); break; } default:break; } m_block_dataChanged = false; } void DynamicElementTextModel::updateDataFromGroup( ElementTextItemGroup *group, DynamicElementTextModel::ValueType type) { QStandardItem *qsi = m_groups_list.value(group); if (!qsi) return; m_block_dataChanged = true; switch (type) { case grpAlignment: { switch (group->alignment()) { case Qt::AlignLeft: qsi->child(align_grp_row,1)->setData(tr("Gauche"), Qt::DisplayRole); break; case Qt::AlignRight : qsi->child(align_grp_row,1)->setData(tr("Droite"), Qt::DisplayRole); break; case Qt::AlignVCenter : qsi->child(align_grp_row,1)->setData(tr("Centre"), Qt::DisplayRole); break; default: qsi->child(0,1)->setData("", Qt::DisplayRole); break; } break; } case grpPos: { qsi->child(x_grp_row,1)->setData(group->pos().x(), Qt::EditRole); qsi->child(y_grp_row,1)->setData(group->pos().y(), Qt::EditRole); break; } case grpRotation: qsi->child(rot_grp_row,1)->setData(group->rotation(), Qt::EditRole); break; case grpVAdjust: qsi->child(adjust_grp_row,1)->setData(group->verticalAdjustment(), Qt::EditRole); break; case grpName: qsi->setData(group->name(), Qt::DisplayRole); break; case grpHoldBottom: { qsi->child(hold_to_bottom_grp_row,1)->setCheckState(group->holdToBottomPage()? Qt::Checked : Qt::Unchecked); enableGroupRotationAndPos(group); break; } case grpFrame: qsi->child(frame_grp_row, 1)->setCheckState(group->frame()? Qt::Checked : Qt::Unchecked); break; default:break; } m_block_dataChanged = false; } /*************************************************** A little delegate only for add a combobox and a color dialog, for use with the model ***************************************************/ DynamicTextItemDelegate::DynamicTextItemDelegate(QObject *parent) : QStyledItemDelegate(parent) {} QWidget *DynamicTextItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { switch (index.data(Qt::UserRole+1).toInt()) { case DynamicElementTextModel::textFrom: { QComboBox *qcb = new QComboBox(parent); qcb->setObjectName("text_from"); qcb->addItem(tr("Texte utilisateur")); qcb->addItem(tr("Information de l'élément")); qcb->addItem(tr("Texte composé")); return qcb; } case DynamicElementTextModel::infoText: { const DynamicElementTextModel *detm = static_cast(index.model()); QStandardItem *qsi = detm->itemFromIndex(index); if(!qsi) break; DynamicElementTextItem *deti = detm->textFromIndex(index); if(!deti) break; //We use a QMap because the keys of the map are sorted, then no matter the curent local, //the value of the combo box are always alphabetically sorted QMap info_map; for(const QString& str : availableInfo(deti)) { info_map.insert(QETApp::elementTranslatedInfoKey(str), str); } QComboBox *qcb = new QComboBox(parent); qcb->setObjectName("info_text"); for (const QString& key : info_map.keys()) { qcb->addItem(key, info_map.value(key)); } return qcb; } case DynamicElementTextModel::compositeText: { const DynamicElementTextModel *detm = static_cast(index.model()); QStandardItem *qsi = detm->itemFromIndex(index); if(!qsi) break; DynamicElementTextItem *deti = detm->textFromIndex(index); if(!deti) break; CompositeTextEditDialog *cted = new CompositeTextEditDialog(deti, parent); cted->setObjectName("composite_text"); return cted; } case DynamicElementTextModel::txtAlignment: { const DynamicElementTextModel *detm = static_cast(index.model()); QStandardItem *qsi = detm->itemFromIndex(index); if(!qsi) break; DynamicElementTextItem *deti = detm->textFromIndex(index); if(!deti) break; AlignmentTextDialog *atd = new AlignmentTextDialog(deti->alignment(), parent); atd->setObjectName("alignment_text"); return atd; } case DynamicElementTextModel::size: { QSpinBox *sb = new QSpinBox(parent); sb->setObjectName("font_size"); sb->setFrame(false); return sb; } case DynamicElementTextModel::font: { bool ok; QFont font = QFontDialog::getFont(&ok, index.data(Qt::UserRole+2).value(), parent); QWidget *w = new QWidget(parent); if (ok) { w->setFont(font); w->setProperty("ok", ok); } w->setObjectName("font_dialog"); return w; } case DynamicElementTextModel::color: { QColorDialog *cd = new QColorDialog(index.data(Qt::EditRole).value(), parent); cd->setObjectName("color_dialog"); return cd; } case DynamicElementTextModel::pos: { QSpinBox *sb = new QSpinBox(parent); sb->setObjectName("pos_dialog"); sb->setRange(-1000,10000); sb->setFrame(false); sb->setSuffix(" px"); return sb; } case DynamicElementTextModel::rotation: { QSpinBox *sb = new QSpinBox(parent); sb->setObjectName("rot_spinbox"); sb->setRange(0, 359); sb->setWrapping(true); sb->setFrame(false); sb->setSuffix(" °"); return sb; } case DynamicElementTextModel::textWidth: { QSpinBox *sb = new QSpinBox(parent); sb->setObjectName("width_spinbox"); sb->setRange(-1, 500); sb->setFrame(false); sb->setSuffix(" px"); return sb; } case DynamicElementTextModel::grpAlignment: { QComboBox *qcb = new QComboBox(parent); qcb->setFrame(false); qcb->setObjectName("group_alignment"); qcb->addItem(tr("Gauche")); qcb->addItem(tr("Centre")); qcb->addItem(tr("Droite")); return qcb; } case DynamicElementTextModel::grpPos: { QSpinBox *sb = new QSpinBox(parent); sb->setObjectName("group_pos"); sb->setRange(-1000,10000); sb->setFrame(false); sb->setSuffix(" px"); return sb; } case DynamicElementTextModel::grpRotation: { QSpinBox *sb = new QSpinBox(parent); sb->setObjectName("group_rotation"); sb->setRange(0, 359); sb->setWrapping(true); sb->setFrame(false); sb->setSuffix(" °"); return sb; } case DynamicElementTextModel::grpVAdjust: { QSpinBox *sb = new QSpinBox(parent); sb->setObjectName("group_v_adjustment"); sb->setRange(-20, 20); sb->setFrame(false); sb->setSuffix(" px"); return sb; } } return QStyledItemDelegate::createEditor(parent, option, index); } void DynamicTextItemDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { if (index.isValid()) { if (editor->objectName() == "font_dialog") { if (QStandardItemModel *qsim = dynamic_cast(model)) { if(QStandardItem *qsi = qsim->itemFromIndex(index)) { if (editor->property("ok").toBool() == true) { qsi->setData(editor->font().family(), Qt::EditRole); qsi->setData(editor->font(), Qt::UserRole+2); } return; } } } else if(editor->objectName() == "color_dialog") { if (QStandardItemModel *qsim = dynamic_cast(model)) { if(QStandardItem *qsi = qsim->itemFromIndex(index)) { QColorDialog *cd = static_cast (editor); if (cd->result() == QDialog::Accepted) { qsi->setData(cd->selectedColor(), Qt::EditRole); qsi->setData(cd->selectedColor(), Qt::ForegroundRole); } return; } } } else if (editor->objectName() == "info_text") { if (QStandardItemModel *qsim = dynamic_cast(model)) { if(QStandardItem *qsi = qsim->itemFromIndex(index)) { QComboBox *cb = static_cast(editor); qsi->setData(cb->currentText(), Qt::DisplayRole); qsi->setData(cb->currentData(), Qt::UserRole+2); return; } } } else if (editor->objectName() == "composite_text") { if (QStandardItemModel *qsim = dynamic_cast(model)) { if(QStandardItem *qsi = qsim->itemFromIndex(index)) { CompositeTextEditDialog *cted = static_cast(editor); QString edited_text = cted->plainText(); QString assigned_text; const DynamicElementTextModel *detm = static_cast(index.model()); DynamicElementTextItem *deti = detm->textFromIndex(index); if(deti) { DiagramContext dc; if(deti->elementUseForInfo()) dc = deti->elementUseForInfo()->elementInformations(); assigned_text = autonum::AssignVariables::replaceVariable(edited_text, dc); } qsi->setData(assigned_text, Qt::DisplayRole); qsi->setData(edited_text, Qt::UserRole+2); return; } } } else if (editor->objectName() == "alignment_text") { if(QStandardItemModel *qsim = dynamic_cast(model)) { if(QStandardItem *qsi = qsim->itemFromIndex(index)) { AlignmentTextDialog *atd = static_cast(editor); Qt::Alignment align = atd->alignment(); qsi->setData(QVariant::fromValue(align), Qt::UserRole+2); return; } } } else if (editor->objectName() == "group_alignment") { if(QStandardItemModel *qsim = dynamic_cast(model)) { if(QStandardItem *qsi = qsim->itemFromIndex(index)) { QComboBox *cb = static_cast(editor); qsi->setData(cb->currentText(), Qt::DisplayRole); } } } } QStyledItemDelegate::setModelData(editor, model, index); } bool DynamicTextItemDelegate::eventFilter(QObject *object, QEvent *event) { //This is a bad hack, for change the normal behavior : //in normal behavior, //the value is commited when the spinbox lose focus or enter key is pressed //With this hack the value is commited each time the value change without the need to validate. //then the change is apply in live if(object->objectName() == "pos_dialog" || object->objectName() == "font_size" || object->objectName() == "rot_spinbox" || \ object->objectName() == "group_rotation" || object->objectName() == "group_v_adjustment" || object->objectName() == "width_spinbox" ||\ object->objectName() == "group_pos") { object->event(event); QSpinBox *sb = static_cast(object); switch (event->type()) { case QEvent::KeyPress: emit commitData(sb); break; case QEvent::KeyRelease: emit commitData(sb); break; case QEvent::MouseButtonPress: emit commitData(sb); break; case QEvent::MouseButtonRelease: emit commitData(sb); break; case QEvent::Wheel: emit commitData(sb); break; default:break; } return true; } //Like the hack above, change the current index of the combobox, // apply the change immediately, no need to lose focus or press enter. if((object->objectName() == "text_from" || object->objectName() == "info_text" || object->objectName() == "group_alignment") && event->type() == QEvent::FocusIn) { QComboBox *qcb = static_cast(object); connect(qcb, static_cast(&QComboBox::currentIndexChanged), [this,qcb](){emit commitData(qcb);}); } return QStyledItemDelegate::eventFilter(object, event); } /** @brief DynamicTextItemDelegate::availableInfo @param deti @return A list of available info of element */ QStringList DynamicTextItemDelegate::availableInfo( DynamicElementTextItem *deti) const { QStringList qstrl; if(deti->parentElement()->linkType() & Element::AllReport) //Special treatment for text owned by a folio report { qstrl << "label"; if(!deti->m_watched_conductor.isNull()) { Conductor *cond = deti->m_watched_conductor.data(); if (!cond->properties().m_function.isEmpty()) qstrl << "function"; if(!cond->properties().m_tension_protocol.isEmpty()) qstrl << "tension_protocol"; if(!cond->properties().m_wire_color.isEmpty()) qstrl << "conductor_color"; if(!cond->properties().m_wire_section.isEmpty()) qstrl << "conductor_section"; } return qstrl; } else { Element *elmt = deti->elementUseForInfo(); if(!elmt) return qstrl; QStringList info_list = QETApp::elementInfoKeys(); info_list.removeAll("formula"); //No need to have formula DiagramContext dc = elmt->elementInformations(); for(const QString& info : info_list) { if(dc.contains(info)) qstrl << info; } } return qstrl; }