![]() |
XML Mill
1.0.0
A GUI based XML editor with a memory.
|
00001 /* Copyright (c) 2012 - 2013 by William Hallatt. 00002 * 00003 * This file forms part of "XML Mill". 00004 * 00005 * The official website for this project is <http://www.goblincoding.com> and, 00006 * although not compulsory, it would be appreciated if all works of whatever 00007 * nature using this source code (in whole or in part) include a reference to 00008 * this site. 00009 * 00010 * Should you wish to contact me for whatever reason, please do so via: 00011 * 00012 * <http://www.goblincoding.com/contact> 00013 * 00014 * This program is free software: you can redistribute it and/or modify it under 00015 * the terms of the GNU General Public License as published by the Free Software 00016 * Foundation, either version 3 of the License, or (at your option) any later 00017 * version. 00018 * 00019 * This program is distributed in the hope that it will be useful, but WITHOUT 00020 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00021 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00022 * 00023 * You should have received a copy of the GNU General Public License along with 00024 * this program (GNUGPL.txt). If not, see 00025 * 00026 * <http://www.gnu.org/licenses/> 00027 */ 00028 00029 #include "gcaddsnippetsform.h" 00030 #include "ui_gcaddsnippetsform.h" 00031 #include "db/gcdatabaseinterface.h" 00032 #include "utils/gccombobox.h" 00033 #include "utils/gcmessagespace.h" 00034 #include "utils/gcglobalspace.h" 00035 #include "utils/gctreewidgetitem.h" 00036 00037 #include <QCheckBox> 00038 #include <QMessageBox> 00039 00040 /*--------------------------------------------------------------------------------------*/ 00041 00042 const int LABELCOLUMN = 0; 00043 const int COMBOCOLUMN = 1; 00044 const int INCRCOLUMN = 2; 00045 00046 /*--------------------------------------------------------------------------------------*/ 00047 00048 GCAddSnippetsForm::GCAddSnippetsForm( const QString& elementName, GCTreeWidgetItem* parentItem, QWidget* parent ) 00049 : QDialog ( parent ), 00050 ui ( new Ui::GCAddSnippetsForm ), 00051 m_parentItem ( parentItem ), 00052 m_treeItemActivated( false ) 00053 { 00054 ui->setupUi( this ); 00055 ui->tableWidget->setFont( QFont( GCGlobalSpace::FONT, GCGlobalSpace::FONTSIZE ) ); 00056 ui->tableWidget->horizontalHeader()->setFont( QFont( GCGlobalSpace::FONT, GCGlobalSpace::FONTSIZE ) ); 00057 00058 ui->tableWidget->setColumnWidth( INCRCOLUMN, 40 ); // restricted for checkbox 00059 ui->treeWidget->setColumnWidth( 0, 50 ); // restricted for checkbox 00060 ui->showHelpButton->setVisible( GCGlobalSpace::showHelpButtons() ); 00061 00062 ui->treeWidget->populateFromDatabase( elementName ); 00063 ui->treeWidget->setAllCheckStates( Qt::Checked ); 00064 elementSelected( ui->treeWidget->gcCurrentItem(), 0 ); 00065 00066 connect( ui->closeButton, SIGNAL( clicked() ), this, SLOT( close() ) ); 00067 connect( ui->addButton, SIGNAL( clicked() ), this, SLOT( addSnippet() ) ); 00068 connect( ui->showHelpButton, SIGNAL( clicked() ), this, SLOT( showHelp() ) ); 00069 connect( ui->tableWidget, SIGNAL( itemChanged( QTableWidgetItem* ) ), this, SLOT( attributeChanged( QTableWidgetItem* ) ) ); 00070 connect( ui->treeWidget, SIGNAL( gcCurrentItemSelected( GCTreeWidgetItem*, int ) ), this, SLOT( elementSelected( GCTreeWidgetItem*, int ) ) ); 00071 00072 setAttribute( Qt::WA_DeleteOnClose ); 00073 } 00074 00075 /*--------------------------------------------------------------------------------------*/ 00076 00077 GCAddSnippetsForm::~GCAddSnippetsForm() 00078 { 00079 delete ui; 00080 } 00081 00082 /*--------------------------------------------------------------------------------------*/ 00083 00084 void GCAddSnippetsForm::elementSelected( GCTreeWidgetItem* item, int column ) 00085 { 00086 Q_UNUSED( column ); 00087 00088 if( item ) 00089 { 00090 m_treeItemActivated = true; 00091 00092 ui->tableWidget->clearContents(); // also deletes current items 00093 ui->tableWidget->setRowCount( 0 ); 00094 00095 /* Populate the table widget with the attributes and values associated with the element selected. */ 00096 QString elementName = item->name(); 00097 QStringList attributeNames = GCDataBaseInterface::instance()->attributes( elementName ); 00098 00099 /* Create and add the "increment" checkbox to the first column of the table widget, add all the 00100 known attribute names to the cells in the second column of the table widget, create and populate 00101 combo boxes with the values associated with the attributes in question and insert the combo boxes 00102 into the third column of the table widget. */ 00103 for( int i = 0; i < attributeNames.count(); ++i ) 00104 { 00105 ui->tableWidget->setRowCount( i + 1 ); 00106 00107 QCheckBox* checkBox = new QCheckBox; 00108 00109 /* Overrides main style sheet. */ 00110 checkBox->setStyleSheet( "QCheckBox{ padding-right: 1px; }" 00111 "QCheckBox::indicator{ subcontrol-position: center; width: 15px; height: 15px; }" ); 00112 00113 ui->tableWidget->setCellWidget( i, INCRCOLUMN, checkBox ); 00114 connect( checkBox, SIGNAL( clicked() ), this, SLOT( attributeValueChanged() ) ); 00115 00116 QDomAttr attribute = item->element().attributeNode( attributeNames.at( i ) ).toAttr(); 00117 checkBox->setChecked( item->incrementAttribute( attribute.name() ) ); 00118 00119 /* Items are editable by default, disable this option. */ 00120 QTableWidgetItem* label = new QTableWidgetItem( attributeNames.at( i ) ); 00121 label->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable ); 00122 ui->tableWidget->setItem( i, LABELCOLUMN, label ); 00123 00124 GCComboBox* attributeCombo = new GCComboBox; 00125 attributeCombo->addItems( GCDataBaseInterface::instance()->attributeValues( elementName, attributeNames.at( i ) ) ); 00126 attributeCombo->setEditable( true ); 00127 attributeCombo->setCurrentIndex( attributeCombo->findText( item->element().attribute( attributeNames.at( i ) ) ) ); 00128 00129 connect( attributeCombo, SIGNAL( currentIndexChanged( QString ) ), this, SLOT( attributeValueChanged() ) ); 00130 00131 if( item->attributeIncluded( attributeNames.at( i ) ) ) 00132 { 00133 label->setCheckState( Qt::Checked ); 00134 attributeCombo->setEnabled( true ); 00135 } 00136 else 00137 { 00138 label->setCheckState( Qt::Unchecked ); 00139 attributeCombo->setEnabled( false ); 00140 } 00141 00142 ui->tableWidget->setCellWidget( i, COMBOCOLUMN, attributeCombo ); 00143 00144 if( item->checkState( 0 ) == Qt::Unchecked ) 00145 { 00146 ui->tableWidget->setEnabled( false ); 00147 } 00148 else 00149 { 00150 ui->tableWidget->setEnabled( true ); 00151 } 00152 } 00153 00154 updateCheckStates( item ); 00155 00156 ui->tableWidget->horizontalHeader()->setSectionResizeMode( LABELCOLUMN, QHeaderView::Stretch ); 00157 ui->tableWidget->horizontalHeader()->setSectionResizeMode( COMBOCOLUMN, QHeaderView::Stretch ); 00158 ui->tableWidget->horizontalHeader()->setSectionResizeMode( INCRCOLUMN, QHeaderView::Fixed ); 00159 00160 m_treeItemActivated = false; 00161 } 00162 } 00163 00164 /*--------------------------------------------------------------------------------------*/ 00165 00166 void GCAddSnippetsForm::attributeChanged( QTableWidgetItem* item ) const 00167 { 00168 if( !m_treeItemActivated ) 00169 { 00170 GCTreeWidgetItem* treeItem = ui->treeWidget->gcCurrentItem(); 00171 GCComboBox* attributeValueCombo = dynamic_cast< GCComboBox* >( ui->tableWidget->cellWidget( item->row(), COMBOCOLUMN ) ); 00172 QCheckBox* checkBox = dynamic_cast< QCheckBox* >( ui->tableWidget->cellWidget( item->row(), INCRCOLUMN ) ); 00173 00174 if( item->checkState() == Qt::Checked ) 00175 { 00176 attributeValueCombo->setEnabled( true ); 00177 checkBox->setEnabled( true ); 00178 treeItem->includeAttribute( item->text(), attributeValueCombo->currentText() ); 00179 } 00180 else 00181 { 00182 attributeValueCombo->setEnabled( false ); 00183 checkBox->setEnabled( false ); 00184 treeItem->excludeAttribute( item->text() ); 00185 } 00186 } 00187 } 00188 00189 /*--------------------------------------------------------------------------------------*/ 00190 00191 void GCAddSnippetsForm::attributeValueChanged() const 00192 { 00193 /* Update the element's attribute inclusions, values and value increment flags. */ 00194 GCTreeWidgetItem* treeItem = ui->treeWidget->gcCurrentItem(); 00195 QDomNamedNodeMap attributes = treeItem->element().attributes(); 00196 00197 /* The table doesn't know which attributes are included or excluded and contains 00198 rows corresponding to all the attributes associated with the element. We only 00199 wish to act on attributes currently included. */ 00200 for( int i = 0; i < attributes.size(); ++i ) 00201 { 00202 for( int j = 0; j < ui->tableWidget->rowCount(); ++j ) 00203 { 00204 QString attributeName = ui->tableWidget->item( j, LABELCOLUMN )->text(); 00205 00206 if( attributeName == attributes.item( i ).nodeName() ) 00207 { 00208 QCheckBox* checkBox = dynamic_cast< QCheckBox* >( ui->tableWidget->cellWidget( j, INCRCOLUMN ) ); 00209 GCComboBox* comboBox = dynamic_cast< GCComboBox* >( ui->tableWidget->cellWidget( j, COMBOCOLUMN ) ); 00210 QString attributeValue = comboBox->currentText(); 00211 00212 if( treeItem->attributeIncluded( attributeName ) ) 00213 { 00214 treeItem->includeAttribute( attributeName, attributeValue ); 00215 } 00216 00217 treeItem->setIncrementAttribute( attributeName, checkBox->isChecked() ); 00218 } 00219 } 00220 } 00221 } 00222 00223 /*--------------------------------------------------------------------------------------*/ 00224 00225 void GCAddSnippetsForm::addSnippet() 00226 { 00227 QList< GCTreeWidgetItem* > includedItems = ui->treeWidget->includedTreeWidgetItems(); 00228 00229 /* Add the required number of snippets. */ 00230 for( int i = 0; i < ui->spinBox->value(); ++i ) 00231 { 00232 /* Update all the included elements and attribute values. */ 00233 for( int j = 0; j < includedItems.size(); ++j ) 00234 { 00235 GCTreeWidgetItem* localItem = includedItems.at( j ); 00236 00237 /* Sets a "restore point" so that we may increment attribute values and return 00238 to the previously fixed values (to avoid incrementing an incremented value). */ 00239 localItem->fixAttributeValues(); 00240 00241 QString elementName = localItem->element().tagName(); 00242 QDomNamedNodeMap attributes = localItem->element().attributes(); 00243 00244 for( int k = 0; k < attributes.size(); ++k ) 00245 { 00246 QDomAttr attr = attributes.item( k ).toAttr(); 00247 QString attributeValue = localItem->fixedValue( attr.name() ); 00248 00249 if( localItem->incrementAttribute( attr.name() ) ) 00250 { 00251 /* Check if this is a number (if it contains any non-digit character). */ 00252 if( !attributeValue.contains( QRegExp( "\\D+" ) ) ) 00253 { 00254 bool ok( false ); 00255 int intValue = attributeValue.toInt( &ok ); 00256 00257 if( ok ) 00258 { 00259 intValue += i; 00260 attributeValue = QString( "%1" ).arg( intValue ); 00261 } 00262 } 00263 else 00264 { 00265 /* If the value contains some string characters, it's a string value and that's all 00266 there is to it (it's not our responsibility to check that someone isn't incrementing 00267 "false", e.g.). */ 00268 attributeValue += QString( "%1" ).arg( i ); 00269 } 00270 00271 localItem->element().setAttribute( attr.name(), attributeValue ); 00272 } 00273 00274 /* This call does nothing if the attribute value already exists. */ 00275 GCDataBaseInterface::instance()->updateAttributeValues( elementName, attr.name(), QStringList( attributeValue ) ); 00276 } 00277 } 00278 00279 emit snippetAdded( m_parentItem, ui->treeWidget->cloneDocument().toElement() ); 00280 00281 /* Restore values. */ 00282 for( int j = 0; j < includedItems.size(); ++j ) 00283 { 00284 includedItems.at( j )->revertToFixedValues(); 00285 } 00286 } 00287 } 00288 00289 /*--------------------------------------------------------------------------------------*/ 00290 00291 void GCAddSnippetsForm::updateCheckStates( GCTreeWidgetItem* item ) const 00292 { 00293 /* Checking or unchecking an item must recursively update its children as well. */ 00294 if( item->checkState( 0 ) == Qt::Checked ) 00295 { 00296 item->setExcludeElement( false ); 00297 00298 /* When a low-level child is activated, we need to also update its parent tree all the way 00299 up to the root element since including a child automatically implies that the parent 00300 element is included. */ 00301 GCTreeWidgetItem* parent = item->gcParent(); 00302 00303 while( parent && ( parent->checkState( 0 ) != Qt::Checked ) ) 00304 { 00305 parent->setExcludeElement( false ); 00306 parent->setCheckState( 0, Qt::Checked ); 00307 parent = parent->gcParent(); 00308 } 00309 } 00310 else 00311 { 00312 item->setExcludeElement( true ); 00313 00314 for( int i = 0; i < item->childCount(); ++i ) 00315 { 00316 item->child( i )->setCheckState( 0, item->checkState( 0 ) ); 00317 updateCheckStates( item->gcChild( i ) ); 00318 } 00319 } 00320 } 00321 00322 /*--------------------------------------------------------------------------------------*/ 00323 00324 void GCAddSnippetsForm::showHelp() 00325 { 00326 QMessageBox::information( this, 00327 "How this works...", 00328 "Use this form to create XML snippets with the default values " 00329 "you specify. \n\n" 00330 "Unchecking an element will exclude it (and all of its children) from " 00331 "the snippet (similarly, check attributes that you want to be included in " 00332 "your snippet(s)). \n\n" 00333 "If you tick the \"Incr\" (increment) option next to an attribute value, then the " 00334 "value you provided will be incremented with \"1\" for however many " 00335 "snippets you generate. \n\n" 00336 "For example, if you specify \"10\" as an attribute value, then the " 00337 "first snippet will assign \"10\" to the attribute in question, " 00338 "the second will have \"11\", the third, \"12\", etc. \n\n" 00339 "Strings will have the incremented value appended to the name (\"true\" " 00340 "and \"false\" values are treated as strings, so be careful)." ); 00341 } 00342 00343 /*--------------------------------------------------------------------------------------*/