diff --git a/src/app/dialogs/app/dialogaboutapp.cpp b/src/app/dialogs/app/dialogaboutapp.cpp index aa9b69050..47d2f8fa2 100644 --- a/src/app/dialogs/app/dialogaboutapp.cpp +++ b/src/app/dialogs/app/dialogaboutapp.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include //--------------------------------------------------------------------------------------------------------------------- DialogAboutApp::DialogAboutApp(QWidget *parent) : @@ -65,7 +67,7 @@ DialogAboutApp::~DialogAboutApp() */ void DialogAboutApp::webButtonClicked() { - if ( ! QDesktopServices::openUrl(QUrl(VER_COMPANYDOMAIN_STR))) + if ( QDesktopServices::openUrl(QUrl(VER_COMPANYDOMAIN_STR)) == false) { QMessageBox::warning(this, tr("Warning"), tr("Cannot open your default browser")); } diff --git a/src/app/dialogs/app/dialogaboutapp.h b/src/app/dialogs/app/dialogaboutapp.h index f9b98e1cf..66d10afe5 100644 --- a/src/app/dialogs/app/dialogaboutapp.h +++ b/src/app/dialogs/app/dialogaboutapp.h @@ -31,8 +31,9 @@ #include -namespace Ui { -class DialogAboutApp; +namespace Ui +{ + class DialogAboutApp; } class DialogAboutApp : public QDialog diff --git a/src/app/dialogs/app/dialogpatternxmledit.cpp b/src/app/dialogs/app/dialogpatternxmledit.cpp new file mode 100644 index 000000000..21044fd26 --- /dev/null +++ b/src/app/dialogs/app/dialogpatternxmledit.cpp @@ -0,0 +1,1259 @@ +/************************************************************************ + ** + ** @file dialogpatternxmledit.cpp + ** @author Patrick Proy + ** @date 14 5, 2014 + ** + ** @brief Code file for the XML editor dialog + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2013 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ + +#include "dialogpatternxmledit.h" +#include "ui_dialogpatternxmledit.h" + +#include + +const short int DialogPatternXmlEdit::ChangeTypeDelete=1; +const short int DialogPatternXmlEdit::ChangeTypeAdd=2; +const short int DialogPatternXmlEdit::ChangeTypeModify=3; + + +//--------------------------------------------------------------------------------------------------------------------- +DialogPatternXmlEdit::DialogPatternXmlEdit(QWidget *parent, VPattern *xmldoc) + :QDialog(parent), treeChange(false), currentNodeEdited(nullptr), currentNodeEditedStatus(0), + currentNodeEditedStack(nullptr), ui(new Ui::DialogPatternXmlEdit), doc(nullptr), root(QDomElement()), + rootNode(nullptr), rootBases(nullptr), rootBasesNum(0), xmlmodel(nullptr), changeStackRoot(nullptr), + changeStackLast(nullptr) +{ + ui->setupUi(this); + + this->xmlmodel = new VXMLTreeView(); + this->doc=xmldoc; + this->root = this->doc->documentElement(); + // disable edit trigers (no edition directly on tree) + ui->treeView_main->setEditTriggers(QTreeView::NoEditTriggers); + + ui->treeView_main->setWindowTitle("XML"); + + this->rootNode = this->xmlmodel->invisibleRootItem(); + + int drawnum=xmldoc->elementsByTagName("draw").size(); + this->rootBases = new VXMLTreeElement*[drawnum+1]; + this->rootBasesNum=1; + this->rootBases[0]=new VXMLTreeElement("Valentina", VXMLTreeElement::TypeRoot, root, false); + // TODO : OOM exception. + + + VXMLTreeElement* standard_base = new VXMLTreeElement("Valentina", VXMLTreeElement::TypeRoot, root, false); + ui->comboBox_Base_Selection->addItem(tr("All pattern pieces"), QVariant(0)); + + //rootBases[0]=(QDomNode) doc->DocumentNode; + this->rootNode->appendRow(standard_base); + + this->ReadNodes(this->root, standard_base, this->xmlmodel, false); + + ui->treeView_main->setModel(xmlmodel); + + //ui->treeView_main->expandAll(); + + // connectors + connect(ui->comboBox_Base_Selection, static_cast(&QComboBox::currentIndexChanged), + this, &DialogPatternXmlEdit::BaseSelectionChanged); + connect(ui->treeView_main, &QTreeView::clicked, this, &DialogPatternXmlEdit::ElementClicked); + connect(ui->lineEdit_Name, &QLineEdit::textEdited, this, &DialogPatternXmlEdit::NameTextEdited); + connect(ui->lineEdit_Value, &QLineEdit::textEdited, this, &DialogPatternXmlEdit::ValueTextEdited); + connect(ui->pushButton_Set_Values, &QPushButton::clicked, this, &DialogPatternXmlEdit::ButtonSetClicked); + connect(ui->pushButton_Cancel_Values, &QPushButton::clicked, this, &DialogPatternXmlEdit::ButtonCancelClicked); + connect(ui->pushButton_Remove_attribute, &QPushButton::clicked, + this, &DialogPatternXmlEdit::ButtonDeleteAttributeClicked); + connect(ui->pushButton_Add_son, &QPushButton::clicked, this, &DialogPatternXmlEdit::ButtonAddSonClicked); + connect(ui->pushButton_Add_attribute, &QPushButton::clicked, + this, &DialogPatternXmlEdit::ButtonAddAttributeClicked); + connect(ui->pushButton_Apply_Changes, &QPushButton::clicked, + this, &DialogPatternXmlEdit::ButtonApplyChangesClicked); + connect(ui->pushButton_Undo_Last_Change, &QPushButton::clicked, this, &DialogPatternXmlEdit::ButtonUndoLastChange); + connect(ui->pushButton_Remove_Node, &QPushButton::clicked, this, &DialogPatternXmlEdit::ButtonDeleteNode); +} + +bool DialogPatternXmlEdit::CheckChanges(QString &message, QDomNode testRoot) +{ + message="OK"; + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool DialogPatternXmlEdit::ApplyAttributeChange(QDomNode domElement, QString name, QString value) +{ + if (domElement.isElement() == false) + { + return false; + } + domElement.toElement().setAttribute(name,value); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool DialogPatternXmlEdit::ApplyNodeChange(QDomNode domElement, QString name, QString value) +{ + if (domElement.isElement() == false) + { + return false; + } + domElement.toElement().setNodeValue(value); + domElement.toElement().setTagName(name); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool DialogPatternXmlEdit::ApplyNodeAdd(QDomNode domElement, VXMLTreeElement* treeElement, QString name, QString value) +{ + QDomElement newnode = domElement.ownerDocument().createElement(name); + //Q_ASSERT(newnode != nullptr); + newnode.setNodeValue(value); + domElement.appendChild(newnode); + treeElement->SetDocNode(newnode); + return true; +} + +bool DialogPatternXmlEdit::ApplyAttributeDelete(QDomNode domElement, QString name) +{ + if (domElement.isElement() == false) + { + return false; + } + domElement.toElement().removeAttribute(name); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool DialogPatternXmlEdit::ApplyNodeDelete(QDomNode domElement) +{ + QDomNode mother=domElement.parentNode(); + mother.removeChild(domElement); + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonDeleteNode() +{ + ChangesStackElement* newstack; + + // TODO : maybe assert functions here + if (this->currentNodeEdited == nullptr) + { + return; + } + if (this->currentNodeEdited->GetelementType() != VXMLTreeElement::TypeNode) + { + return; + } + + if (this->currentNodeEditedStatus != 0) + { + if (this->currentNodeEditedStatus == DialogPatternXmlEdit::ChangeTypeDelete) + { // Change already done ??? ignore... + return; + } + if (this->currentNodeEditedStatus == DialogPatternXmlEdit::ChangeTypeAdd) + { // Attribute was previously added, just undo the change + if ( this->UndoChange(this->currentNodeEditedStack) == false ) + { // Error in undo... warn user + QMessageBox::warning(this, tr("No changes"), tr("Cannot delete previously created node")); + return; + } + this->ClearEditData(); + return; + } + if (this->currentNodeEditedStatus == DialogPatternXmlEdit::ChangeTypeModify) + { // Node was edited : remove change then continue to delete node + this->UndoChange(this->currentNodeEditedStack); + } + } + + // Modify display + QFont textfont=currentNodeEdited->font(); + textfont.setStrikeOut(true); + this->currentNodeEdited->setFont(textfont); + // + this->DeleteNodeAndSons(this->currentNodeEdited, true); + // Create change + newstack = this->CreateStackElement(DialogPatternXmlEdit::ChangeTypeDelete); + newstack->element= this->currentNodeEdited; + // Activate changes + this->treeChange=true; + ui->pushButton_Apply_Changes->setEnabled(true); + ui->pushButton_Undo_Last_Change->setEnabled(true); + // clear dialog + this->ClearEditData(); + return; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool DialogPatternXmlEdit::DeleteNodeAndSons(VXMLTreeElement * currentNode, bool onlydeactivate) +{ + + QList stack; + VXMLTreeElement * currentNodeStack; + // First undo all changes on sons + stack << currentNode; + while (stack.isEmpty() == false) + { + //pop first element + currentNodeStack=stack.takeFirst(); + // clear all changes made in son node and not on current or it will loop + if (currentNodeStack != currentNode) + { + ChangesStackElement * local = this->changeStackRoot; + while (local != nullptr) + { + if (local->element == currentNodeStack) + { + this->UndoChange(local); + break; + } + local=local->next; + } + } + // add sons to stack + int index=currentNodeStack->rowCount(); + while (index > 0) + { + stack << static_cast (currentNodeStack->child(index-1)); + index--; + } + //stack.removeFirst(); + } + // Next set strike font on all + if (onlydeactivate==true) + { + stack << currentNode; + while (stack.isEmpty() == false) + { + //pop first element + currentNodeStack=stack.takeFirst(); + + currentNodeStack->SetSetlectable(false); + QFont textfont=currentNodeStack->font(); + textfont.setStrikeOut(true); + currentNodeStack->setFont(textfont); + // add sons to stack + int index=currentNodeStack->rowCount(); + while (index > 0) + { + stack << static_cast (currentNodeStack->child(index-1)); + index--; + } + } + } + + currentNode->SetSetlectable(true); + + if (onlydeactivate==false) + { // Remove node from parent + // Get parent node + QStandardItem * parent= currentNode->parent(); + int index=parent->rowCount(); + while (index >= 0) + { + if (static_cast (parent->child(index)) == currentNode) + { + break; + } + index--; + } + if (index < 0) + { + Q_ASSERT(index==0); + return false; + } + parent->removeRow(index); + } + return true; +} + +//--------------------------------------------------------------------------------------------------------------------- +DialogPatternXmlEdit::ChangesStackElement* DialogPatternXmlEdit::CreateStackElement(short int typechange) +{ + ChangesStackElement* tmp; + + tmp= new ChangesStackElement; + //if (tmp==0) TODO + tmp->type=typechange; + tmp->changedText=tmp->changedValue=false; + + if (changeStackLast==nullptr ) + { + changeStackLast=changeStackRoot=tmp; + } + else + { + changeStackLast->next=tmp; + changeStackLast=changeStackLast->next; + } + changeStackLast->newValue=changeStackLast->newText=nullptr; + changeStackLast->oldValue=changeStackLast->oldText=nullptr; + changeStackLast->next=nullptr; + return changeStackLast; +} + +//--------------------------------------------------------------------------------------------------------------------- +bool DialogPatternXmlEdit::UndoChange(DialogPatternXmlEdit::ChangesStackElement* current) +{ + Q_ASSERT(current != nullptr); + + VXMLTreeElement * currentNode = current->element; + + if (current->type == DialogPatternXmlEdit::ChangeTypeDelete) + { + if (currentNode->GetelementType()==VXMLTreeElement::TypeAttr) + { + // Attribute previously deleted -> restore + QFont textfont=currentNode->font(); + textfont.setStrikeOut(false); + currentNode->setFont(textfont); + this->RemoveChangeStackElement(current); + } + else if (currentNode->GetelementType()==VXMLTreeElement::TypeNode) + { + QList stack; + stack << currentNode; + while (stack.isEmpty() == false) + { + currentNode=stack.takeFirst(); + currentNode->SetSetlectable(true); + QFont textfont=currentNode->font(); + textfont.setStrikeOut(false); + currentNode->setFont(textfont); + + int index=currentNode->rowCount(); + while (index > 0) + { + stack << static_cast (currentNode->child(index-1)); + index--; + } + } + this->RemoveChangeStackElement(current); + } + } + else if (current->type == DialogPatternXmlEdit::ChangeTypeAdd) + { + if (currentNode->GetelementType()==VXMLTreeElement::TypeAttr) + { + // Get parent node + VXMLTreeElement * parent= static_cast (currentNode->parent()); + int index=parent->rowCount(); + while (index >= 0) + { + if (static_cast (parent->child(index)) == currentNode) + { + break; + } + index--; + } + if (index < 0) + { + Q_ASSERT(index==0); + return false; + } + parent->removeRow(index); + this->RemoveChangeStackElement(current); + } + else if (currentNode->GetelementType()==VXMLTreeElement::TypeNode) + { + if (this->DeleteNodeAndSons(currentNode, false) == false) + { + // TODO : error message. + return false; + } + this->RemoveChangeStackElement(current); + } + } + else if (current->type == DialogPatternXmlEdit::ChangeTypeModify) + { + if (current->changedText == true) + { + currentNode->SetTreeNodeName(*current->oldText); + } + if (current->changedValue == true) + { + currentNode->SetTreeNodeValue(*current->oldValue); + } + + QFont textfont=currentNode->font(); + textfont.setBold(false); + currentNode->setFont(textfont); + this->RemoveChangeStackElement(current); + } + // Check if last change was undone + if (this->changeStackLast == nullptr) + { + this->treeChange=false; + ui->pushButton_Apply_Changes->setEnabled(false); + ui->pushButton_Undo_Last_Change->setEnabled(false); + } + return true; +} + + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonUndoLastChange() +{ + ChangesStackElement* current=this->changeStackLast; + + if (current == nullptr) + { + QMessageBox::warning(this, tr("No changes"), tr("No changes left")); + this->ui->pushButton_Undo_Last_Change->setEnabled(false); + return; + } + if (this->UndoChange(current) == false) + { + QMessageBox::warning(this, tr("No changes"), tr("Cannot undo change")); + } + this->ClearEditData(); + +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonApplyChangesClicked() +{ + QString Changes=""; + QStringList stringtype; + stringtype << "node" << "attribute" << "root"; + QString nodetype; + ChangesStackElement* currentChange; + if (this->changeStackRoot==nullptr) + { + Changes="No Changes"; + } + else + { + currentChange=this->changeStackRoot; + do + { + nodetype=stringtype.at(currentChange->element->GetelementType()-1); + if (currentChange->type == DialogPatternXmlEdit::ChangeTypeAdd) + { + Changes += QString("Added type %1 : ").arg(nodetype); + Changes += currentChange->element->GettreeNodeName(); + Changes += "/"; + Changes += (currentChange->element->GettreeNodeValueSet()) ? + currentChange->element->GettreeNodeValue(): QString(tr("")); + Changes += "\n"; + } + else + { + if (currentChange->type == DialogPatternXmlEdit::ChangeTypeModify) + { + Changes += QString("Modified type %1 : ").arg(nodetype); + Changes += (currentChange->changedText) ? *currentChange->newText : QString(tr("Unchanged")); + Changes += "/"; + Changes += (currentChange->changedValue) ? *currentChange->newValue: QString(tr("Unchanged")); + Changes += "\n"; + } + else + { + if (currentChange->type == DialogPatternXmlEdit::ChangeTypeDelete) + { + Changes += QString("Deleted type %1 : ").arg(nodetype); + Changes += currentChange->element->GettreeNodeName(); + Changes += "/"; + Changes += (currentChange->element->GettreeNodeValueSet()) ? + currentChange->element->GettreeNodeValue(): QString(tr("")); + Changes += "\n"; + } + } + } + currentChange=currentChange->next; + } while (currentChange != nullptr); + } + QMessageBox::information(this, "Changes (not REALLY applied for now)", Changes); + // TODO : clear stack and apply + + currentChange=this->changeStackRoot; + // copy DOM + QDomNode newroot = root.cloneNode(true); + + QString name, value; + while (currentChange != nullptr) + { + if (currentChange->type == DialogPatternXmlEdit::ChangeTypeModify) + { + name=(currentChange->changedText == false) ? currentChange->element->GettreeNodeName() + : *currentChange->newText; + value=(currentChange->changedValue == false) ? currentChange->element->GettreeNodeValue() + : *currentChange->newValue; + if (currentChange->element->GetelementType() == VXMLTreeElement::TypeAttr) + { + + this->ApplyAttributeChange(currentChange->element->GetDocNode(), name, value); + } + else if (currentChange->element->GetelementType() == VXMLTreeElement::TypeNode) + { + this->ApplyNodeChange(currentChange->element->GetDocNode(), name, value); + } + else + { + QMessageBox::warning(this, "Error in changes", "Invalid node type"); + return; + } + } + else if (currentChange->type == DialogPatternXmlEdit::ChangeTypeAdd) + { + name=(currentChange->changedText == false) ? currentChange->element->GettreeNodeName() + : *currentChange->newText; + value=(currentChange->changedValue == false) ? currentChange->element->GettreeNodeValue() + : *currentChange->newValue; + if (currentChange->element->GetelementType() == VXMLTreeElement::TypeAttr) + { + this->ApplyAttributeChange(currentChange->element->GetFatherElement()->GetDocNode(), name, value); + } + else if (currentChange->element->GetelementType() == VXMLTreeElement::TypeNode) + { + this->ApplyNodeAdd(currentChange->element->GetFatherElement()->GetDocNode(), currentChange->element, + name, value); + } + else + { + QMessageBox::warning(this, "Error in changes", "Invalid node type"); + return; + } + } + else if (currentChange->type == DialogPatternXmlEdit::ChangeTypeDelete) + { + if (currentChange->element->GetelementType() == VXMLTreeElement::TypeAttr) + { + name=(currentChange->changedText == false) ? currentChange->element->GettreeNodeName() + : *currentChange->newText; + this->ApplyAttributeDelete(currentChange->element->GetDocNode(), name); + } + else if (currentChange->element->GetelementType() == VXMLTreeElement::TypeNode) + { + this->ApplyNodeDelete(currentChange->element->GetDocNode().parentNode()); + } + else + { + QMessageBox::warning(this, "Error in changes", "Invalid node type"); + return; + } + } + currentChange=currentChange->next; + } + QString message; + if (this->CheckChanges(message,newroot) == false) + { + QMessageBox::warning(this, "Error in changes", message); + return; + } + this->doc->FullUpdateTree(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonCancelClicked() +{ + this->ClearEditData(); + if (this->currentNodeEditedStatus==DialogPatternXmlEdit::ChangeTypeDelete) + { + if (this->UndoChange(this->currentNodeEditedStack) == false) + { + QMessageBox::warning(this, "Error", "Cannot undo"); + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::RemoveChangeStackElement(ChangesStackElement* elmt) +{ + ChangesStackElement* index = this->changeStackRoot; + + if (changeStackRoot == elmt) + { + if (elmt->newText != nullptr) + { + delete elmt->newText; + } + if (elmt->newValue != nullptr) + { + delete elmt->newValue; + } + if (elmt->oldText != nullptr) + { + delete elmt->oldText; + } + if (elmt->oldValue != nullptr) + { + delete elmt->oldValue; + } + this->changeStackRoot = elmt->next; + if (this->changeStackLast == elmt) + { + this->changeStackLast= elmt->next; + } + delete elmt; + return; + } + while (index->next!=nullptr) + { + if (index->next == elmt) + { + break; + } + index=index->next; + } + if (index->next == nullptr) + { + Q_ASSERT(index->next != nullptr); + return; + } + if (index->next->newText != nullptr) + { + delete index->next->newText; + } + if (index->next->newValue != nullptr) + { + delete index->next->newValue; + } + if (index->next->oldText != nullptr) + { + delete index->next->oldText; + } + if (index->next->oldValue != nullptr) + { + delete index->next->oldValue; + } + index->next=index->next->next; + if (this->changeStackLast == elmt) + { + this->changeStackLast= index; + } + delete elmt; +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonDeleteAttributeClicked() +{ + ChangesStackElement* newstack; + + // TODO : maybe assert functions here + if (this->currentNodeEdited == nullptr) + { + return; + } + if (this->currentNodeEdited->GetelementType() != VXMLTreeElement::TypeAttr) + { + return; + } + + if (this->currentNodeEditedStatus != 0) + { + if (this->currentNodeEditedStatus == DialogPatternXmlEdit::ChangeTypeDelete) + { // Change already done ??? ignore... + return; + } + if (this->currentNodeEditedStatus == DialogPatternXmlEdit::ChangeTypeAdd) + { // Attribute was previously added, just undo the change + if ( this->UndoChange(this->currentNodeEditedStack) == false ) + { // Error in undo... warn user + QMessageBox::warning(this, tr("No changes"), tr("Cannot delete previously created attribute")); + return; + } + this->ClearEditData(); + return; + } + if (this->currentNodeEditedStatus == DialogPatternXmlEdit::ChangeTypeModify) + { // Node was edited : remove change then continue to delete node + this->UndoChange(this->currentNodeEditedStack); + } + } + newstack = this->CreateStackElement(DialogPatternXmlEdit::ChangeTypeDelete); + newstack->element= this->currentNodeEdited; + + QFont textfont=currentNodeEdited->font(); + textfont.setStrikeOut(true); + this->currentNodeEdited->setFont(textfont); + // Activate changes + this->treeChange=true; + ui->pushButton_Apply_Changes->setEnabled(true); + ui->pushButton_Undo_Last_Change->setEnabled(true); + // clear dialog + this->ClearEditData(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonAddSonClicked() +{ + ChangesStackElement* newstack; + bool ok; + //clear_edit_data(); + // TODO : maybe assert functions here + if (this->currentNodeEdited == nullptr) + { + return; + } + if (this->currentNodeEdited->GetelementType() != VXMLTreeElement::TypeNode) + { + return; + } + + + QString name = QInputDialog::getText(this, tr("Node Name"), tr("Name:"), QLineEdit::Normal, "", &ok); + if (ok==false) + { + return; + } + QString value = QInputDialog::getText(this, tr("Node Value (may be empty)"),tr("Value:"), + QLineEdit::Normal,"", &ok); + if (ok==false) + { + return; + } + + // create element tree and put father tree element to catch up with DOM tree. + QDomNode empty; + VXMLTreeElement* tElement = new VXMLTreeElement(name, VXMLTreeElement::TypeNode, empty, true); + tElement->SetFatherElement(this->currentNodeEdited); + + if (value.isEmpty() == false) + { + tElement->SetTreeNodeValue(value); + } + currentNodeEdited->appendRow(tElement); + xmlmodel->appendchain(tElement); + QFont textfont=currentNodeEdited->font(); + textfont.setBold(true); + tElement->setFont(textfont); + + // Add to change stack + newstack = this->CreateStackElement(DialogPatternXmlEdit::ChangeTypeAdd); + newstack->element=tElement; + newstack->newText=new QString(name); newstack->changedText=true; + if (value.isEmpty()) + { + newstack->changedValue=true;newstack->newValue=new QString(value); + } + // Activate changes + treeChange=true; + ui->pushButton_Apply_Changes->setEnabled(true); + ui->pushButton_Undo_Last_Change->setEnabled(true); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonAddAttributeClicked() +{ + ChangesStackElement* newstack; + bool ok; + QDomNode empty; // empty QNode to pas to create function : maybe a better way to do this ? + + // TODO : maybe assert functions here + if (this->currentNodeEdited == nullptr) + { + return; + } + if (this->currentNodeEdited->GetelementType() != VXMLTreeElement::TypeNode) + { + return; + } + + QString name = QInputDialog::getText(this, tr("Attribute Name"), + tr("Name:"), QLineEdit::Normal, + "", &ok); + if (ok==false) + { + return; + } + QString value = QInputDialog::getText(this, tr("Attribute Value"), + tr("Value:"), QLineEdit::Normal, + "", &ok); + if (ok==false) + { + return; + } + + // create element tree but do not add attribute in DOM (will be done in apply). + VXMLTreeElement* tElement = new VXMLTreeElement(name, VXMLTreeElement::TypeAttr, empty, true); + // set parent node. + tElement->SetFatherElement(this->currentNodeEdited); + + tElement->SetTreeNodeValue(value); + currentNodeEdited->appendRow(tElement); + xmlmodel->appendchain(tElement); + QFont textfont=currentNodeEdited->font(); + textfont.setBold(true); + tElement->setFont(textfont); + // Add to change stack + newstack = this->CreateStackElement(DialogPatternXmlEdit::ChangeTypeAdd); + newstack->element= tElement; + newstack->type=VXMLTreeElement::TypeAttr; + newstack->newText=new QString(name); + newstack->newValue=new QString(value); + // Activate changes + treeChange=true; + ui->pushButton_Apply_Changes->setEnabled(true); + ui->pushButton_Undo_Last_Change->setEnabled(true); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ButtonSetClicked() +{ + QString name, value; + ChangesStackElement* newstack; + + if (this->currentNodeEdited == nullptr) + { + return; + } + name=ui->lineEdit_Name->text(); + value=ui->lineEdit_Value->text(); + bool nameedit, valueedit; + + nameedit = (name != currentNodeEdited->GettreeNodeName()) ? true : false; + valueedit= (value != currentNodeEdited->GettreeNodeValue()) ? true : false; + + if ( nameedit == true || valueedit == true ) + { + if (this->currentNodeEditedStatus != 0) + { // If node was created or edited previously, rewrite + if (this->currentNodeEditedStatus == DialogPatternXmlEdit::ChangeTypeDelete) + { // You shouldn't be able to edit a deleted node... + Q_ASSERT(this->currentNodeEditedStatus != DialogPatternXmlEdit::ChangeTypeDelete); + ClearEditData(); + return; + } + newstack=this->currentNodeEditedStack; + if (nameedit == true) + { + newstack->changedText=true; + *newstack->newText=name; + currentNodeEdited->SetTreeNodeName(name); + } + if (valueedit == true) + { + if (newstack->changedValue==true) + { + *newstack->newValue = value; + } + else + { + newstack->changedValue=true; + newstack->newValue= new QString(value); + newstack->oldValue= new QString(this->currentNodeEdited->GettreeNodeValue()); + } + currentNodeEdited->SetTreeNodeValue(value); + } + } + else + { + newstack = this->CreateStackElement(DialogPatternXmlEdit::ChangeTypeModify); + newstack->element= this->currentNodeEdited; + + if (nameedit == true) + { + newstack->changedText=true; + newstack->newText=new QString(name); + newstack->oldText=new QString(this->currentNodeEdited->GettreeNodeName()); + currentNodeEdited->SetTreeNodeName(name); + } + if (valueedit == true) + { + newstack->changedValue=true; + newstack->newValue= new QString(value); + newstack->oldValue= new QString(this->currentNodeEdited->GettreeNodeValue()); + currentNodeEdited->SetTreeNodeValue(value); + } + } + QFont textfont=currentNodeEdited->font(); + textfont.setBold(true); + currentNodeEdited->setFont(textfont); + treeChange=true; + ui->pushButton_Apply_Changes->setEnabled(true); + ui->pushButton_Undo_Last_Change->setEnabled(true); + ClearEditData(); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::NameTextEdited(QString newtext) +{ + //QMessageBox::information(this, "nameTextEdited", QString("%1").arg(newtext)); + ui->pushButton_Set_Values->setEnabled(true); + ui->pushButton_Cancel_Values->setEnabled(true); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ValueTextEdited(QString newtext) +{ + //QMessageBox::information(this, "valueTextEdited", QString("%1").arg(newtext)); + ui->pushButton_Set_Values->setEnabled(true); + ui->pushButton_Cancel_Values->setEnabled(true); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ClearEditData() +{ + ui->lineEdit_Name->setText(""); + ui->lineEdit_Value->setText(""); + ui->lineEdit_Name->setEnabled(false); + ui->lineEdit_Value->setEnabled(false); + + ui->label_type_value->setText(tr("No selection")); + ui->pushButton_Set_Values->setEnabled(false); + ui->pushButton_Add_attribute->setEnabled(false); + ui->pushButton_Add_son->setEnabled(false); + ui->pushButton_Remove_attribute->setEnabled(false); + ui->pushButton_Cancel_Values->setEnabled(false); + ui->pushButton_Remove_Node->setEnabled(false); +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ClearStack() +{ + ChangesStackElement * tmp; + while (changeStackRoot != nullptr) + { + if (changeStackRoot->newText != nullptr) + { + delete changeStackRoot->newText; + } + if (changeStackRoot->newValue != nullptr) + { + delete changeStackRoot->newValue; + } + tmp=changeStackRoot; + changeStackRoot=changeStackRoot->next; + delete tmp; + } + changeStackLast=nullptr; +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::BaseSelectionChanged(int value) +{ + QDomNode newbase; + + int index; + + if (this->treeChange == true) + {//Changes have been made : warn ? + } + this->ClearStack(); + ui->pushButton_Apply_Changes->setEnabled(false); + + index = ui->comboBox_Base_Selection->itemData(value).toInt(); //.convert(QVariant::Int); + Q_ASSERT(value < rootBasesNum); + // QMessageBox::information(this, "test", QString("%1:%2").arg(value).arg(index)); + + // Clear all tree info and nodes + // TODO : Check + while (rootNode->rowCount() > 0) + { + rootNode->removeRow(0); + } + this->xmlmodel->ClearTree(); + + VXMLTreeElement* standard_base = new VXMLTreeElement( + rootBases[index]->GettreeNodeName(), + VXMLTreeElement::TypeRoot, + rootBases[index]->GetDocNode(), + false); + rootNode->appendRow(standard_base); + ReadNodes(rootBases[index]->GetDocNode(), standard_base, xmlmodel, true); + + ui->treeView_main->setModel(xmlmodel); + this->ClearEditData(); + // TODO : warn if changes ? + this->ClearStack(); + return; +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ElementClicked ( const QModelIndex & index ) +{ + + // Get item (function returns parent of clicked item) + VXMLTreeElement *item = static_cast (index.internalPointer()); + + // Get child specified by index row/column + VXMLTreeElement * item2 = static_cast (item->child(index.row(), index.column())); + + // Clear all data and disable buttons + this->ClearEditData(); + // Check if element is selectable at this time + if (item2->IsSelectable() == false) + { + return; + } + // Check status of element in change stack + this->currentNodeEdited=item2; + this->currentNodeEditedStatus=0; + ChangesStackElement * local = this->changeStackRoot; + while (local != nullptr) + { + if (local->element == item2) + { + this->currentNodeEditedStatus=local->type; + this->currentNodeEditedStack=local; + if (local->type == DialogPatternXmlEdit::ChangeTypeDelete) + { + // Node is deleted, only enable cancel button + ui->pushButton_Cancel_Values->setEnabled(true); + return; + } + } + local=local->next; + } + // Fill the dialog and Activate the line edit + if (item2->GetelementType() != VXMLTreeElement::TypeRoot) + { + ui->lineEdit_Name->setText(currentNodeEdited->GettreeNodeName()); + ui->lineEdit_Name->setEnabled(true); + // Fill value + ui->lineEdit_Value->setText(currentNodeEdited->GettreeNodeValue()); + ui->lineEdit_Value->setEnabled(true); + } + if (item2->GetelementType() == VXMLTreeElement::TypeRoot) + { + ui->label_type_value->setText(tr("Root node"));; + ui->pushButton_Add_son->setEnabled(true); + } + else if (item2->GetelementType() == VXMLTreeElement::TypeNode) + { + ui->label_type_value->setText(tr("Node")); + ui->pushButton_Add_attribute->setEnabled(true); + ui->pushButton_Add_son->setEnabled(true); + ui->pushButton_Remove_Node->setEnabled(true); + } + else if (item2->GetelementType() == VXMLTreeElement::TypeAttr) + { + ui->label_type_value->setText(tr("Attribute")); + ui->pushButton_Remove_attribute->setEnabled(true); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +DialogPatternXmlEdit::~DialogPatternXmlEdit() +{ + this->ClearStack(); + this->xmlmodel->ClearTree(); + delete ui; +} + +//--------------------------------------------------------------------------------------------------------------------- +void DialogPatternXmlEdit::ReadNodes(QDomNode dNode, VXMLTreeElement* root, VXMLTreeView* xmlmodel, bool refresh) +{ + + QDomNode tNode, tNode2; + VXMLTreeElement* tElement, *tElement2; + int totalOfChilds = dNode.childNodes().size(); + if (totalOfChilds == 0) + { + return; // empty xml + } + for (int i=0;iappendchain(tElement); + root->appendRow(tElement); + if (tNode.nodeName() == "draw") + { + for (int i = 0; i < tNode.attributes().size(); i++) + { + if ((tNode.attributes().item(i).nodeName() == "name") + && (refresh == false)) + { + ui->comboBox_Base_Selection->addItem(tNode.attributes().item(i).nodeValue(), + QVariant(rootBasesNum)); + rootBases[rootBasesNum]=new VXMLTreeElement( + QString("Drawing %1").arg(tNode.attributes().item(i).nodeValue()), + VXMLTreeElement::TypeRoot, tNode, false); + rootBasesNum++; + //QStandardItem* rootNode = (QStandardItem*) rootBases[rootBasesNum]->invisibleRootItem(); + //rootNode->appendRow(tElement); + } + } + } + } + } + + do + { + tElement=xmlmodel->getCurrent()->elmt; + tNode=tElement->GetDocNode(); + if (tElement->GetelementType() == VXMLTreeElement::TypeNode) + { + totalOfChilds = tNode.childNodes().size(); + for (int i=0;iappendchain(tElement2); + tElement->appendRow(tElement2); + } + } + + if (tNode.nodeType() == QDomNode::TextNode) + { + tElement->SetTreeNodeValue(tNode.nodeValue()); + } + + for (int i = 0; i < tNode.attributes().size(); i++) + { + tElement2 = new VXMLTreeElement(tNode.attributes().item(i).nodeName(), VXMLTreeElement::TypeAttr, + tNode, false); + tElement2->SetTreeNodeValue(tNode.attributes().item(i).nodeValue()); + tElement->appendRow(tElement2); + xmlmodel->appendchain(tElement2); + } + } + xmlmodel->SetCurrent(xmlmodel->getCurrent()->next); + } + while (xmlmodel->getCurrent() != 0); + return; +} + +//--------------------------------------------------------------------------------------------------------------------- +VXMLTreeView::VXMLTreeView(QObject *parent) + : QStandardItemModel(parent), items(nullptr), current(nullptr), last(nullptr) +{} + +//--------------------------------------------------------------------------------------------------------------------- +void VXMLTreeView::ClearTree() +{ + + // TODO check if treeitems are deleted with the delete row command of QDom + + //clear the chain link + TreeElementchain * tmp; + while (items != nullptr) + { + tmp=items; + items=items->next; + delete tmp; + } + // reset chain counters + current=last=items=nullptr; +} + +//--------------------------------------------------------------------------------------------------------------------- +VXMLTreeView::~VXMLTreeView() +{} + +//--------------------------------------------------------------------------------------------------------------------- +void VXMLTreeView::appendchain(VXMLTreeElement* elmt) +{ + if (last == nullptr) + { // first element + current = new TreeElementchain; + if (current == nullptr) + { + Q_ASSERT(current != nullptr); + // TODO : throw exception + } + current->elmt=elmt; + current->next=nullptr; + last=items=current; + return; + } + TreeElementchain* temp= new TreeElementchain; + if (temp == nullptr) + { + Q_ASSERT(temp != nullptr); + // TODO : throw exception + } + temp->elmt=elmt; + temp->next=nullptr; + last->next=temp; + last=temp; +} + +const short int VXMLTreeElement::TypeNode=1; +const short int VXMLTreeElement::TypeAttr=2; +const short int VXMLTreeElement::TypeRoot=3; + +//--------------------------------------------------------------------------------------------------------------------- +//TODO warning: conversion to 'short int' from 'int' may alter its value [-Wconversion] +//treeNodeValueSet(false), treeNodeName(name) +// ^ +VXMLTreeElement::VXMLTreeElement(QString name, int nodetype, QDomNode source, bool editor) + : QStandardItem(name), DocNode(source), addedNode(editor), elementType(nodetype), treeNodeValue(""), + treeNodeValueSet(false), treeNodeName(name), selectable(true), parentnode(nullptr) +{ + if (editor == false) + { + this->DocNode=source; + } + this->setText(this->DisplayText()); + switch (this->elementType) + { + case VXMLTreeElement::TypeAttr: + this->setBackground(BACKGROUND_COLOR_ATTRIBUTE); + break; + default: + break; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +VXMLTreeElement::~VXMLTreeElement() +{} + +//--------------------------------------------------------------------------------------------------------------------- +void VXMLTreeElement::SetTreeNodeValue(QString value) +{ + this->treeNodeValue=value; + this->treeNodeValueSet=true; + this->setText(this->DisplayText()); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VXMLTreeElement::SetTreeNodeName(QString value) +{ + this->treeNodeName=value; + this->setText(this->DisplayText()); +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VXMLTreeElement::DisplayText() +{ + if (this->elementType == VXMLTreeElement::TypeRoot) + { + return this->treeNodeName; + } + return QString("%1 : %2").arg((this->treeNodeName)).arg(this->treeNodeValue); +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VXMLTreeElement::GettreeNodeValue() +{ + // Only return value if it's really set. + if (this->treeNodeValueSet) + { + return this->treeNodeValue; + } + else + { + return QString(); + } +} diff --git a/src/app/dialogs/app/dialogpatternxmledit.h b/src/app/dialogs/app/dialogpatternxmledit.h new file mode 100644 index 000000000..51e3e316f --- /dev/null +++ b/src/app/dialogs/app/dialogpatternxmledit.h @@ -0,0 +1,388 @@ +/************************************************************************ + ** + ** @file dialogpatternxmledit.h + ** @author Patrick Proy + ** @date 14 5, 2014 + ** + ** @brief Include file for the XML editor dialog + ** @copyright + ** This source code is part of the Valentine project, a pattern making + ** program, whose allow create and modeling patterns of clothing. + ** Copyright (C) 2013 Valentina project + ** All Rights Reserved. + ** + ** Valentina 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 3 of the License, or + ** (at your option) any later version. + ** + ** Valentina 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 Valentina. If not, see . + ** + *************************************************************************/ + +#ifndef DIALOGPATTERNXMLEDIT_H +#define DIALOGPATTERNXMLEDIT_H + +#include +#include +#include "../../xml/vpattern.h" + +//******************************************************************************************** +/** + * @brief The vXMLTreeElement class : node/attribute of xml pattern. Used by vXMLTreeView + * + */ + +#define BACKGROUND_COLOR_ATTRIBUTE QBrush(Qt::GlobalColor::cyan) +#define BACKGROUND_COLOR_INACTIVE_NODE QBrush(Qt::GlobalColor::gray) +class VXMLTreeElement : public QStandardItem +{ + +public: + /** + * @brief vXMLTreeElement + * @param name : display name + * @param nodetype : node type (node, attribute, root) + * @param source : the source dom node + */ + explicit VXMLTreeElement (QString name, int nodetype, QDomNode source, bool editor); + + explicit VXMLTreeElement (QString name, int nodetype); + + ~VXMLTreeElement (); + static const short int TypeNode; + static const short int TypeAttr; + static const short int TypeRoot; + /** + * @brief setNodeValue : set value of node (content or attribute) + * @param value : the value + */ + void SetTreeNodeValue(QString value); + /** + * @brief displayText : text to display + * @return text to display + */ + QString DisplayText(); + /** + * @brief getDocNode + * @return current document node + */ + QDomNode GetDocNode(); + /** + * @brief SetDocNode set tree element DomNode + * @param node + */ + inline void SetDocNode(QDomNode node) + { + this->DocNode=node; + } + inline void SetAddedNode(bool state) {this->addedNode=state;} + inline bool GetAddedNode() {return this->addedNode;} + + QString GettreeNodeName(); + QString GettreeNodeValue(); + /** + * @brief GettreeNodeValueSet check if value has been set + * @return true if value is set + */ + bool GettreeNodeValueSet(); + void SetTreeNodeName(QString value); + /** + * @brief getelementType + * @return elementType value + */ + short int GetelementType(); + bool IsSelectable(); + void SetSetlectable(bool value); + + inline void SetFatherElement(VXMLTreeElement* parent) + { + this->parentnode=parent; + } + inline VXMLTreeElement* GetFatherElement() + { + return this->parentnode; + } + +private: + /** + * @brief DocNode : link to current document node + */ + QDomNode DocNode; + + /** + * @brief parentnode parent node of this element. If null then the DocNode must be valid + */ + VXMLTreeElement* parentnode; + + /** + * @brief addedNode : true if node is added by editor (implies empty DocNode) + */ + bool addedNode; + /** + * @brief type : element type (node, attribute, text value of node) + */ + short int elementType; + /** + * @brief nodeValue : Attribute or node value + */ + QString treeNodeValue; + /** + * @brief treeNodeValueSet : true if value has been set + */ + bool treeNodeValueSet; + /** + * @brief nodeValue : Attribute or node value + */ + QString treeNodeName; + /** + * @brief selectable : can item be selected to be changed (ex : false if father deleted). + */ + bool selectable; + Q_DISABLE_COPY(VXMLTreeElement) +}; + +inline bool VXMLTreeElement::IsSelectable() +{ + return this->selectable; +} + +inline void VXMLTreeElement::SetSetlectable(bool value) +{ + this->selectable=value; +} + +inline short int VXMLTreeElement::GetelementType() +{ + return this->elementType; +} + +inline QDomNode VXMLTreeElement::GetDocNode() +{ + return this->DocNode; +} + +inline QString VXMLTreeElement::GettreeNodeName() +{ + return this->treeNodeName; +} + +inline bool VXMLTreeElement::GettreeNodeValueSet() +{ + return this->treeNodeValueSet; +} + +//******************************************************************************************** +/** + * @brief The vXMLTreeView class : container to display/edit xml pattern + */ +class VXMLTreeView : public QStandardItemModel +{ +public: + explicit VXMLTreeView (QObject *parent = 0); + void appendchain(VXMLTreeElement* elmt); + + /** + * @brief The TreeElement struct : chained list of vXMLTreeElement + */ + typedef struct TreeElementchain + { + VXMLTreeElement* elmt; + TreeElementchain* next; + } TreeElementchain; + + TreeElementchain * getCurrent(); + void SetCurrent(TreeElementchain * value); + TreeElementchain * GetLast(); + TreeElementchain * GetItems(); + /** + * @brief clearTree : clear tree elements and listed items. + */ + void ClearTree(); + ~VXMLTreeView (); +private: + Q_DISABLE_COPY(VXMLTreeView) + + /** + * @brief items : root of chained list of vXMLTreeElement + */ + TreeElementchain * items; + /** + * @brief current : used to parse in iteration. + */ + TreeElementchain * current; + /** + * @brief last : used to parse in iteration. + */ + TreeElementchain * last; +}; + +inline VXMLTreeView::TreeElementchain * VXMLTreeView::getCurrent() +{ + return this->current; +} +inline void VXMLTreeView::SetCurrent(VXMLTreeView::TreeElementchain * value) +{ + this->current=value; +} +inline VXMLTreeView::TreeElementchain * VXMLTreeView::GetLast() +{ + return this->last; +} +inline VXMLTreeView::TreeElementchain * VXMLTreeView::GetItems() +{ + return this->items; +} + +//******************************************************************************************** + +namespace Ui +{ + class DialogPatternXmlEdit; +} +/** + * @brief The DialogPatternXmlEdit class : ui dialog for XML editing of pattern + */ +class DialogPatternXmlEdit : public QDialog +{ + Q_OBJECT + +public: + explicit DialogPatternXmlEdit(QWidget *parent = 0, VPattern *xmldoc = 0); + ~DialogPatternXmlEdit(); + + /** + * @brief clear_edit_data : clear input boxes and disables buttons. + */ + void ClearEditData(); + + void NameTextEdited(QString newtext); + void ValueTextEdited(QString newtext); + void ButtonSetClicked(); + void ButtonCancelClicked(); + void ButtonDeleteAttributeClicked(); + void ButtonAddSonClicked(); + void ButtonAddAttributeClicked(); + void ButtonApplyChangesClicked(); + void ButtonUndoLastChange(); + void ButtonDeleteNode(); + + // Stack of changes definition + typedef struct ChangesStackElement + { + short int type; + VXMLTreeElement *element; + QString *newText; + QString *oldText; + bool changedText; + QString *newValue; + QString *oldValue; + bool changedValue; + ChangesStackElement* next; + } ChangesStackElement; + + // Change stack functions + ChangesStackElement* CreateStackElement(short int typechange); + void RemoveChangeStackElement(ChangesStackElement* elmt); + void ClearStack(); + bool treeChange; + VXMLTreeElement* currentNodeEdited; + short int currentNodeEditedStatus; + ChangesStackElement* currentNodeEditedStack; + /** + * @brief UndoChange : undo change in change stack element + * @param current : change to undo + * @return true if undo has been done, false on error + */ + bool UndoChange(ChangesStackElement* current); + /** + * @brief DeleteNodeAndSons : delete node and all it's attribute and sons below + * @param currentNode : node to delete + * @param onlydeactivate : if true, dont delete just deactivate sons and attributes + * @return false if changes couldn't be done + */ + bool DeleteNodeAndSons(VXMLTreeElement *currentNode, bool onlydeactivate); + + /** + * @brief ApplyAttributeChange change or add attribute for node + * @param domElement : node containing attribute + * @param name + * @param value + * @return true on success + */ + bool ApplyAttributeChange(QDomNode domElement, QString name, QString value); + /** + * @brief ApplyNodeChange Change name or text content of node + * @param domElement node + * @param name + * @param value text content of node + * @return true on success + */ + bool ApplyNodeChange(QDomNode domElement, QString name, QString value); + /** + * @brief ApplyNodeAdd add node as child of domElement and set DocNode of treeElement + * @param domElement + * @param treeElement the XMLTreeElement of added node + * @param name + * @param value + * @return true on success + */ + bool ApplyNodeAdd(QDomNode domElement, VXMLTreeElement* treeElement, QString name, QString value); + /** + * @brief ApplyAttributeDelete delete attribute for node + * @param domElement + * @param name attribute name + * @return true on success + */ + bool ApplyAttributeDelete(QDomNode domElement, QString name); + /** + * @brief ApplyNodeDelete delete node domElement + * @param domElement + * @return true on success + */ + bool ApplyNodeDelete(QDomNode domElement); + /** + * @brief CheckChanges Check if changes made are OK + * @param message error message returned if false + * @param testRoot root of DOM to test + * @return true if validated, false otherwise + */ + bool CheckChanges(QString &message, QDomNode testRoot); +private slots: + void BaseSelectionChanged(int value); + void ElementClicked ( const QModelIndex & index ); + +private: + Q_DISABLE_COPY(DialogPatternXmlEdit) + Ui::DialogPatternXmlEdit *ui; + + VPattern *doc; + + QDomElement root; + QStandardItem *rootNode; + //typedef struct rootbases { vXMLTreeElement * root; QString name; } rootbases; + VXMLTreeElement ** rootBases; + qint16 rootBasesNum; + + void ReadNodes(QDomNode dNode, VXMLTreeElement* root, VXMLTreeView *xmlmodel, bool refresh); + VXMLTreeView* xmlmodel; + + + // Stack of changes + static const short int ChangeTypeDelete; + static const short int ChangeTypeAdd; + static const short int ChangeTypeModify; + + // Stack of changes + + ChangesStackElement* changeStackRoot; + ChangesStackElement* changeStackLast; +}; + +#endif // DIALOGPATTERNXMLEDIT_H diff --git a/src/app/dialogs/app/dialogpatternxmledit.ui b/src/app/dialogs/app/dialogpatternxmledit.ui new file mode 100644 index 000000000..2b4c4a83a --- /dev/null +++ b/src/app/dialogs/app/dialogpatternxmledit.ui @@ -0,0 +1,367 @@ + + + DialogPatternXmlEdit + + + + 0 + 0 + 664 + 459 + + + + + 1 + 1 + + + + + 400 + 300 + + + + + 0 + 0 + + + + Qt::DefaultContextMenu + + + XML Editor + + + false + + + false + + + + + + QLayout::SetMaximumSize + + + + + QLayout::SetDefaultConstraint + + + 0 + + + + + false + + + QAbstractItemView::SingleSelection + + + true + + + false + + + + + + + QLayout::SetMinimumSize + + + 9 + + + + + + 0 + 0 + + + + Value : + + + + + + + false + + + + + + + false + + + + + + + + 0 + 0 + + + + Name : + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 10 + + + + + + + + QLayout::SetDefaultConstraint + + + + + + 0 + 0 + + + + <No selection> + + + + + + + + 0 + 0 + + + + Type : + + + + + + + false + + + Add attribute + + + + + + + false + + + Add son + + + + + + + + + QLayout::SetNoConstraint + + + QFormLayout::ExpandingFieldsGrow + + + + + false + + + Remove attibute + + + + + + + false + + + Remove node + + + + + + + false + + + Qt::LeftToRight + + + Set + + + + + + + false + + + Qt::LeftToRight + + + Cancel + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + false + + + Apply changes + + + + + + + false + + + Undo last + + + + + + + Immediate apply + + + false + + + + + + + + + + 0 + 0 + + + + Base selection + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 5 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + DialogPatternXmlEdit + accept() + + + 248 + 254 + + + 157 + 274 + + + + + diff --git a/src/app/dialogs/dialogs.h b/src/app/dialogs/dialogs.h index a64ffcdbb..ec4e9c874 100644 --- a/src/app/dialogs/dialogs.h +++ b/src/app/dialogs/dialogs.h @@ -58,5 +58,6 @@ #include "app/dialogindividualmeasurements.h" #include "app/dialogstandardmeasurements.h" #include "app/dialogaboutapp.h" +#include "app/dialogpatternxmledit.h" #endif // DIALOGS_H diff --git a/src/app/dialogs/dialogs.pri b/src/app/dialogs/dialogs.pri index 01e895748..8bbb24693 100644 --- a/src/app/dialogs/dialogs.pri +++ b/src/app/dialogs/dialogs.pri @@ -29,8 +29,9 @@ HEADERS += \ dialogs/app/dialogmeasurements.h \ dialogs/app/dialogstandardmeasurements.h \ dialogs/app/dialogindividualmeasurements.h \ - dialogs/app/dialogaboutapp.h \ - dialogs/tools/dialogeditwrongformula.h + dialogs/app/dialogaboutapp.h \ + dialogs/tools/dialogeditwrongformula.h \ + dialogs/app/dialogpatternxmledit.h SOURCES += \ dialogs/tools/dialogtriangle.cpp \ @@ -62,8 +63,9 @@ SOURCES += \ dialogs/app/dialogmeasurements.cpp \ dialogs/app/dialogstandardmeasurements.cpp \ dialogs/app/dialogindividualmeasurements.cpp \ - dialogs/app/dialogaboutapp.cpp \ - dialogs/tools/dialogeditwrongformula.cpp + dialogs/app/dialogaboutapp.cpp \ + dialogs/app/dialogpatternxmledit.cpp \ + dialogs/tools/dialogeditwrongformula.cpp FORMS += \ dialogs/tools/dialogtriangle.ui \ @@ -92,5 +94,6 @@ FORMS += \ dialogs/app/dialogmeasurements.ui \ dialogs/app/dialogstandardmeasurements.ui \ dialogs/app/dialogindividualmeasurements.ui \ - dialogs/app/dialogaboutapp.ui \ - dialogs/tools/dialogeditwrongformula.ui + dialogs/app/dialogaboutapp.ui \ + dialogs/app/dialogpatternxmledit.ui \ + dialogs/tools/dialogeditwrongformula.ui diff --git a/src/app/mainwindow.cpp b/src/app/mainwindow.cpp index 652abf98d..8a431c9b2 100644 --- a/src/app/mainwindow.cpp +++ b/src/app/mainwindow.cpp @@ -685,7 +685,7 @@ void MainWindow::ClosedDialogCutArc(int result) void MainWindow::About() { DialogAboutApp * about_dialog = new DialogAboutApp(this); - about_dialog->setAttribute(Qt::WA_DeleteOnClose,true); + about_dialog->setAttribute(Qt::WA_DeleteOnClose, true); about_dialog->show(); } @@ -735,6 +735,14 @@ void MainWindow::PatternProperties() proper.exec(); } +//--------------------------------------------------------------------------------------------------------------------- +void MainWindow::EditPatternCode() +{ + DialogPatternXmlEdit *Pattern = new DialogPatternXmlEdit (this, doc); + Pattern->setAttribute(Qt::WA_DeleteOnClose, true); + Pattern->show(); +} + //--------------------------------------------------------------------------------------------------------------------- /** * @brief showEvent handle after show window. @@ -1396,7 +1404,9 @@ void MainWindow::SetEnableWidgets(bool enable) } ui->actionTable->setEnabled(enable); ui->actionHistory->setEnabled(enable); - ui->actionZoomIn->setEnabled(enable); + ui->actionPattern_properties->setEnabled(enable); + ui->actionEdit_pattern_code->setEnabled(enable); + ui->actionZoomIn->setEnabled(enable); ui->actionZoomOut->setEnabled(enable); } @@ -1730,6 +1740,8 @@ void MainWindow::CreateActions() connect(ui->actionPreferences, &QAction::triggered, this, &MainWindow::Preferences); connect(ui->actionPattern_properties, &QAction::triggered, this, &MainWindow::PatternProperties); ui->actionPattern_properties->setEnabled(false); + connect(ui->actionEdit_pattern_code, &QAction::triggered, this, &MainWindow::EditPatternCode); + ui->actionEdit_pattern_code->setEnabled(false); //Actions for recent files loaded by a main window application. for (int i = 0; i < MaxRecentFiles; ++i) diff --git a/src/app/mainwindow.h b/src/app/mainwindow.h index 87925ea63..07b0f3b00 100644 --- a/src/app/mainwindow.h +++ b/src/app/mainwindow.h @@ -129,6 +129,10 @@ public slots: void ShowToolTip(const QString &toolTip); void OpenRecentFile(); void Clear(); + /** + * @brief Edit XML code of pattern + */ + void EditPatternCode(); signals: /** * @brief ModelChosen emit after calculation all details. diff --git a/src/app/mainwindow.ui b/src/app/mainwindow.ui index 3ba2bcbfe..3cab66be0 100644 --- a/src/app/mainwindow.ui +++ b/src/app/mainwindow.ui @@ -699,6 +699,7 @@ + @@ -1056,6 +1057,11 @@ Zoom out + + + Edit pattern XML code + + diff --git a/src/app/widgets/vapplication.cpp b/src/app/widgets/vapplication.cpp index 8eadb791d..9456047d0 100644 --- a/src/app/widgets/vapplication.cpp +++ b/src/app/widgets/vapplication.cpp @@ -163,7 +163,7 @@ QString VApplication::pathToTables() const return QApplication::applicationDirPath() + QStringLiteral("/tables/standard"); #else QDir dir(QApplication::applicationDirPath() + QStringLiteral("/tables/standard")); - if(dir.exist()) + if (dir.exist()) { return dir.absolutePath(); } @@ -186,7 +186,7 @@ QString VApplication::translationsPath() const return QApplication::applicationDirPath() + QStringLiteral("/translations"); #else QDir dir(QApplication::applicationDirPath() + QStringLiteral("/translations")); - if(dir.exist()) + if (dir.exist()) { return dir.absolutePath(); } diff --git a/src/libs/qmuparser/qmuparser.h b/src/libs/qmuparser/qmuparser.h index e36f52b5d..e65bdfa40 100644 --- a/src/libs/qmuparser/qmuparser.h +++ b/src/libs/qmuparser/qmuparser.h @@ -80,7 +80,7 @@ namespace qmu static qreal Avg(const qreal*, int); // mean value static qreal Min(const qreal*, int); // minimum static qreal Max(const qreal*, int); // maximum -}; + }; //--------------------------------------------------------------------------------------------------------------------- /**