File indexing completed on 2024-04-28 05:08:15
0001 /*************************************************************************** 0002 Copyright (C) 2003-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include "collectionfieldsdialog.h" 0026 #include "collection.h" 0027 #include "field.h" 0028 #include "fieldformat.h" 0029 #include "collectionfactory.h" 0030 #include "gui/listwidgetitem.h" 0031 #include "gui/stringmapdialog.h" 0032 #include "gui/combobox.h" 0033 #include "translators/tellico_xml.h" 0034 #include "utils/string_utils.h" 0035 #include "tellico_debug.h" 0036 0037 #include <KLocalizedString> 0038 #include <KMessageBox> 0039 #include <KAcceleratorManager> 0040 #include <KHelpClient> 0041 0042 #include <QPushButton> 0043 #include <QLineEdit> 0044 #include <QLabel> 0045 #include <QRadioButton> 0046 #include <QGroupBox> 0047 #include <QCheckBox> 0048 #include <QRegularExpression> 0049 #include <QTimer> 0050 #include <QHBoxLayout> 0051 #include <QVBoxLayout> 0052 #include <QGridLayout> 0053 #include <QListWidget> 0054 #include <QDialogButtonBox> 0055 0056 using namespace Tellico; 0057 using Tellico::FieldListItem; 0058 using Tellico::CollectionFieldsDialog; 0059 0060 class Tellico::FieldListItem : public Tellico::GUI::ListWidgetItem { 0061 public: 0062 FieldListItem(QListWidget* parent_, Data::FieldPtr field_) : GUI::ListWidgetItem(field_->title(), parent_), m_field(field_) {} 0063 0064 Data::FieldPtr field() const { return m_field; } 0065 void setField(Data::FieldPtr field) { m_field = field; } 0066 0067 private: 0068 Data::FieldPtr m_field; 0069 }; 0070 0071 CollectionFieldsDialog::CollectionFieldsDialog(Tellico::Data::CollPtr coll_, QWidget* parent_) 0072 : QDialog(parent_), 0073 m_coll(coll_), 0074 m_defaultCollection(nullptr), 0075 m_currentField(nullptr), 0076 m_modified(false), 0077 m_updatingValues(false), 0078 m_reordered(false), 0079 m_oldIndex(-1), 0080 m_notifyMode(NotifyKernel) { 0081 setModal(false); 0082 setWindowTitle(i18n("Collection Fields")); 0083 0084 QVBoxLayout* mainLayout = new QVBoxLayout(); 0085 setLayout(mainLayout); 0086 0087 QWidget* page = new QWidget(this); 0088 mainLayout->addWidget(page); 0089 QBoxLayout* topLayout = new QHBoxLayout(page); 0090 page->setLayout(topLayout); 0091 0092 QGroupBox* fieldsGroup = new QGroupBox(i18n("Current Fields"), page); 0093 QBoxLayout* fieldsLayout = new QVBoxLayout(fieldsGroup); 0094 topLayout->addWidget(fieldsGroup, 1); 0095 0096 m_fieldsWidget = new QListWidget(fieldsGroup); 0097 m_fieldsWidget->setMinimumWidth(150); 0098 fieldsLayout->addWidget(m_fieldsWidget); 0099 0100 Data::FieldList fields = m_coll->fields(); 0101 foreach(Data::FieldPtr field, fields) { 0102 // ignore fields which are not user-editable 0103 if(!field->hasFlag(Data::Field::NoEdit)) { 0104 (void) new FieldListItem(m_fieldsWidget, field); 0105 } 0106 } 0107 connect(m_fieldsWidget, &QListWidget::currentRowChanged, this, &CollectionFieldsDialog::slotHighlightedChanged); 0108 0109 QWidget* hb1 = new QWidget(fieldsGroup); 0110 QHBoxLayout* hb1HBoxLayout = new QHBoxLayout(hb1); 0111 hb1HBoxLayout->setMargin(0); 0112 fieldsLayout->addWidget(hb1); 0113 m_btnNew = new QPushButton(i18nc("New Field", "&New"), hb1); 0114 hb1HBoxLayout->addWidget(m_btnNew); 0115 m_btnNew->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); 0116 m_btnNew->setWhatsThis(i18n("Add a new field to the collection")); 0117 m_btnDelete = new QPushButton(i18nc("Delete Field", "Delete"), hb1); 0118 hb1HBoxLayout->addWidget(m_btnDelete); 0119 m_btnDelete->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); 0120 m_btnDelete->setWhatsThis(i18n("Remove a field from the collection")); 0121 0122 connect(m_btnNew, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotNew); 0123 connect(m_btnDelete, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotDelete); 0124 0125 QWidget* hb2 = new QWidget(fieldsGroup); 0126 QHBoxLayout* hb2HBoxLayout = new QHBoxLayout(hb2); 0127 hb2HBoxLayout->setMargin(0); 0128 fieldsLayout->addWidget(hb2); 0129 m_btnUp = new QPushButton(hb2); 0130 hb2HBoxLayout->addWidget(m_btnUp); 0131 m_btnUp->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); 0132 m_btnUp->setWhatsThis(i18n("Move this field up in the list. The list order is important " 0133 "for the layout of the entry editor.")); 0134 m_btnDown = new QPushButton(hb2); 0135 hb2HBoxLayout->addWidget(m_btnDown); 0136 m_btnDown->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); 0137 m_btnDown->setWhatsThis(i18n("Move this field down in the list. The list order is important " 0138 "for the layout of the entry editor.")); 0139 0140 connect(m_btnUp, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotMoveUp); 0141 connect(m_btnDown, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotMoveDown); 0142 0143 QWidget* vbox = new QWidget(page); 0144 QVBoxLayout* vboxVBoxLayout = new QVBoxLayout(vbox); 0145 vboxVBoxLayout->setMargin(0); 0146 topLayout->addWidget(vbox, 2); 0147 0148 QGroupBox* propGroup = new QGroupBox(i18n("Field Properties"), vbox); 0149 vboxVBoxLayout->addWidget(propGroup); 0150 QBoxLayout* propLayout = new QVBoxLayout(propGroup); 0151 0152 QWidget* grid = new QWidget(propGroup); 0153 QGridLayout* layout = new QGridLayout(grid); 0154 propLayout->addWidget(grid); 0155 0156 int row = -1; 0157 QLabel* label = new QLabel(i18n("&Title:"), grid); 0158 layout->addWidget(label, ++row, 0); 0159 m_titleEdit = new QLineEdit(grid); 0160 layout->addWidget(m_titleEdit, row, 1); 0161 label->setBuddy(m_titleEdit); 0162 QString whats = i18n("The title of the field"); 0163 label->setWhatsThis(whats); 0164 m_titleEdit->setWhatsThis(whats); 0165 connect(m_titleEdit, &QLineEdit::textChanged, this, &CollectionFieldsDialog::slotModified); 0166 0167 label = new QLabel(i18n("T&ype:"), grid); 0168 layout->addWidget(label, row, 2); 0169 m_typeCombo = new KComboBox(grid); 0170 layout->addWidget(m_typeCombo, row, 3); 0171 label->setBuddy(m_typeCombo); 0172 whats = QStringLiteral("<qt>"); 0173 whats += i18n("The type of the field determines what values may be used. "); 0174 whats += i18n("<i>Simple Text</i> is used for most fields. "); 0175 whats += i18n("<i>Paragraph</i> is for large text blocks. "); 0176 whats += i18n("<i>Choice</i> limits the field to certain values. "); 0177 whats += i18n("<i>Checkbox</i> is for a simple yes/no value. "); 0178 whats += i18n("<i>Number</i> indicates that the field contains a numerical value. "); 0179 whats += i18n("<i>URL</i> is for fields which refer to URLs, including references to other files. "); 0180 whats += i18n("A <i>Table</i> may hold one or more columns of values. "); 0181 whats += i18n("An <i>Image</i> field holds a picture. "); 0182 whats += i18n("A <i>Date</i> field can be used for values with a day, month, and year. "); 0183 whats += i18n("A <i>Rating</i> field uses stars to show a rating number. "); 0184 whats += QLatin1String("</qt>"); 0185 label->setWhatsThis(whats); 0186 m_typeCombo->setWhatsThis(whats); 0187 // the typeTitles match the fieldMap().values() but in a better order 0188 m_typeCombo->addItems(Data::Field::typeTitles()); 0189 void (QComboBox::* activatedInt)(int) = &QComboBox::activated; 0190 connect(m_typeCombo, activatedInt, this, &CollectionFieldsDialog::slotModified); 0191 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) 0192 void (QComboBox::* activatedString)(const QString&) = &QComboBox::activated; 0193 connect(m_typeCombo, activatedString, this, &CollectionFieldsDialog::slotTypeChanged); 0194 #else 0195 connect(m_typeCombo, &QComboBox::textActivated, this, &CollectionFieldsDialog::slotTypeChanged); 0196 #endif 0197 0198 label = new QLabel(i18n("Cate&gory:"), grid); 0199 layout->addWidget(label, ++row, 0); 0200 m_catCombo = new KComboBox(true, grid); 0201 layout->addWidget(m_catCombo, row, 1); 0202 label->setBuddy(m_catCombo); 0203 whats = i18n("The field category determines where the field is placed in the editor."); 0204 label->setWhatsThis(whats); 0205 m_catCombo->setWhatsThis(whats); 0206 0207 // I don't want to include the categories for singleCategory fields 0208 QStringList cats; 0209 const QStringList allCats = m_coll->fieldCategories(); 0210 foreach(const QString& cat, allCats) { 0211 Data::FieldList fields = m_coll->fieldsByCategory(cat); 0212 if(!fields.isEmpty() && !fields.at(0)->isSingleCategory()) { 0213 cats.append(cat); 0214 } 0215 } 0216 m_catCombo->addItems(cats); 0217 m_catCombo->setDuplicatesEnabled(false); 0218 connect(m_catCombo, &QComboBox::currentTextChanged, this, &CollectionFieldsDialog::slotModified); 0219 0220 m_btnExtended = new QPushButton(i18n("Set &properties..."), grid); 0221 m_btnExtended->setIcon(QIcon::fromTheme(QStringLiteral("bookmarks"))); 0222 layout->addWidget(m_btnExtended, row, 2, 1, 2); 0223 label->setBuddy(m_btnExtended); 0224 whats = i18n("Extended field properties are used to specify things such as the corresponding bibtex field."); 0225 label->setWhatsThis(whats); 0226 m_btnExtended->setWhatsThis(whats); 0227 connect(m_btnExtended, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotShowExtendedProperties); 0228 0229 label = new QLabel(i18n("Description:"), grid); 0230 layout->addWidget(label, ++row, 0); 0231 m_descEdit = new QLineEdit(grid); 0232 m_descEdit->setMinimumWidth(150); 0233 layout->addWidget(m_descEdit, row, 1, 1, 3); 0234 label->setBuddy(m_descEdit); 0235 0236 whats = i18n("The description is a useful reminder of what information is contained in the field."); 0237 label->setWhatsThis(whats); 0238 m_descEdit->setWhatsThis(whats); 0239 connect(m_descEdit, &QLineEdit::textChanged, this, &CollectionFieldsDialog::slotModified); 0240 0241 QGroupBox* valueGroup = new QGroupBox(i18n("Value Options"), vbox); 0242 vboxVBoxLayout->addWidget(valueGroup); 0243 QGridLayout* valueLayout = new QGridLayout(valueGroup); 0244 int valueRow = -1; 0245 0246 label = new QLabel(i18n("Default value:"), valueGroup); 0247 valueLayout->addWidget(label, ++valueRow, 0); 0248 m_defaultEdit = new QLineEdit(valueGroup); 0249 valueLayout->addWidget(m_defaultEdit, valueRow, 1, 1, 3); 0250 label->setBuddy(m_defaultEdit); 0251 whats = i18n("<qt>A default value can be set for new entries.</qt>"); 0252 label->setWhatsThis(whats); 0253 m_defaultEdit->setWhatsThis(whats); 0254 connect(m_defaultEdit, &QLineEdit::textChanged, this, &CollectionFieldsDialog::slotModified); 0255 0256 label = new QLabel(i18n("Value template:"), valueGroup); 0257 valueLayout->addWidget(label, ++valueRow, 0); 0258 m_derivedEdit = new QLineEdit(valueGroup); 0259 m_derivedEdit->setMinimumWidth(150); 0260 valueLayout->addWidget(m_derivedEdit, valueRow, 1); 0261 label->setBuddy(m_derivedEdit); 0262 0263 /* TRANSLATORS: Do not translate %{year} and %{title}. */ 0264 whats = i18n("Derived values are formed from the values of other fields according to the value template. " 0265 "Named fields, such as \"%{year} %{title}\", get substituted in the value."); 0266 label->setWhatsThis(whats); 0267 m_derivedEdit->setWhatsThis(whats); 0268 connect(m_derivedEdit, &QLineEdit::textChanged, this, &CollectionFieldsDialog::slotModified); 0269 0270 m_derived = new QCheckBox(i18n("Use derived value"), valueGroup); 0271 m_derived->setWhatsThis(whats); 0272 valueLayout->addWidget(m_derived, valueRow, 2, 1, 2); 0273 connect(m_derived, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotDerivedChecked); 0274 connect(m_derived, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotModified); 0275 0276 label = new QLabel(i18n("A&llowed values:"), valueGroup); 0277 valueLayout->addWidget(label, ++valueRow, 0); 0278 m_allowEdit = new QLineEdit(valueGroup); 0279 valueLayout->addWidget(m_allowEdit, valueRow, 1, 1, 3); 0280 label->setBuddy(m_allowEdit); 0281 whats = i18n("<qt>For <i>Choice</i>-type fields, these are the only values allowed. They are " 0282 "placed in a combo box. The possible values have to be separated by a semi-colon, " 0283 "for example: \"dog; cat; mouse\"</qt>"); 0284 label->setWhatsThis(whats); 0285 m_allowEdit->setWhatsThis(whats); 0286 connect(m_allowEdit, &QLineEdit::textChanged, this, &CollectionFieldsDialog::slotModified); 0287 0288 label = new QLabel(i18n("Format options:"), valueGroup); 0289 valueLayout->addWidget(label, ++valueRow, 0); 0290 m_formatCombo = new GUI::ComboBox(valueGroup); 0291 valueLayout->addWidget(m_formatCombo, valueRow, 1, 1, 3); 0292 label->setBuddy(m_formatCombo); 0293 0294 m_formatCombo->addItem(i18n("No formatting"), FieldFormat::FormatNone); 0295 m_formatCombo->addItem(i18n("Allow auto-capitalization only"), FieldFormat::FormatPlain); 0296 m_formatCombo->addItem(i18n("Format as a title"), FieldFormat::FormatTitle); 0297 m_formatCombo->addItem(i18n("Format as a name"), FieldFormat::FormatName); 0298 void (QComboBox::* currentIndexChanged)(int) = &QComboBox::currentIndexChanged; 0299 connect(m_formatCombo, currentIndexChanged, this, &CollectionFieldsDialog::slotModified); 0300 0301 QGroupBox* optionsGroup = new QGroupBox(i18n("Field Options"), vbox); 0302 vboxVBoxLayout->addWidget(optionsGroup); 0303 QBoxLayout* optionsLayout = new QVBoxLayout(optionsGroup); 0304 m_complete = new QCheckBox(i18n("Enable auto-completion"), optionsGroup); 0305 m_complete->setWhatsThis(i18n("If checked, KDE auto-completion will be enabled in the " 0306 "text edit box for this field.")); 0307 m_multiple = new QCheckBox(i18n("Allow multiple values"), optionsGroup); 0308 m_multiple->setWhatsThis(i18n("If checked, Tellico will parse the values in the field " 0309 "for multiple values, separated by a semi-colon.")); 0310 m_grouped = new QCheckBox(i18n("Allow grouping"), optionsGroup); 0311 m_grouped->setWhatsThis(i18n("If checked, this field may be used to group the entries in " 0312 "the group view.")); 0313 optionsLayout->addWidget(m_complete); 0314 optionsLayout->addWidget(m_multiple); 0315 optionsLayout->addWidget(m_grouped); 0316 0317 connect(m_complete, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotModified); 0318 connect(m_multiple, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotModified); 0319 connect(m_grouped, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotModified); 0320 0321 // need to stretch at bottom 0322 vboxVBoxLayout->addStretch(1); 0323 0324 // keep a default collection 0325 m_defaultCollection = CollectionFactory::collection(m_coll->type(), true); 0326 0327 m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok| 0328 QDialogButtonBox::Cancel| 0329 QDialogButtonBox::Help| 0330 QDialogButtonBox::RestoreDefaults| 0331 QDialogButtonBox::Apply); 0332 mainLayout->addWidget(m_buttonBox); 0333 0334 QPushButton* okButton = m_buttonBox->button(QDialogButtonBox::Ok); 0335 okButton->setDefault(true); 0336 okButton->setShortcut(Qt::CTRL | Qt::Key_Return); 0337 connect(m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); 0338 connect(m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); 0339 connect(m_buttonBox, &QDialogButtonBox::helpRequested, this, &CollectionFieldsDialog::slotHelp); 0340 0341 m_buttonBox->button(QDialogButtonBox::RestoreDefaults)->setWhatsThis(i18n("Revert the selected field's properties to the default values.")); 0342 0343 connect(okButton, &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotOk); 0344 connect(m_buttonBox->button(QDialogButtonBox::Apply), &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotApply); 0345 connect(m_buttonBox->button(QDialogButtonBox::RestoreDefaults), &QAbstractButton::clicked, this, &CollectionFieldsDialog::slotDefault); 0346 0347 okButton->setEnabled(false); 0348 m_buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); 0349 m_buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(false); 0350 0351 // initially the m_typeCombo is populated with all types, but as soon as something is 0352 // selected in the fields box, the combo box is cleared and filled with the allowable 0353 // new types. The problem is that when more types are added, the size of the combo box 0354 // doesn't change. So when everything is laid out, the combo box needs to have all the 0355 // items there. 0356 QTimer::singleShot(0, this, &CollectionFieldsDialog::slotSelectInitial); 0357 } 0358 0359 CollectionFieldsDialog::~CollectionFieldsDialog() { 0360 } 0361 0362 void CollectionFieldsDialog::setNotifyKernel(bool notify_) { 0363 if(notify_) { 0364 m_notifyMode = NotifyKernel; 0365 } else { 0366 m_notifyMode = NoNotification; 0367 } 0368 } 0369 0370 void CollectionFieldsDialog::slotSelectInitial() { 0371 // the accel management is here so that it doesn't cause conflicts with the 0372 // ones explicitly set in the constructor 0373 KAcceleratorManager::manage(this); 0374 m_fieldsWidget->setCurrentRow(0); 0375 } 0376 0377 void CollectionFieldsDialog::slotHelp() { 0378 KHelpClient::invokeHelp(QStringLiteral("fields-dialog")); 0379 } 0380 0381 void CollectionFieldsDialog::slotOk() { 0382 slotApply(); 0383 accept(); 0384 } 0385 0386 void CollectionFieldsDialog::slotApply() { 0387 updateField(); 0388 if(!checkValues()) { 0389 return; 0390 } 0391 0392 applyChanges(); 0393 } 0394 0395 void CollectionFieldsDialog::applyChanges() { 0396 // start a command group, "Modify" is a generic term here since the commands could be add, modify, or delete 0397 if(m_notifyMode == NotifyKernel) { 0398 emit beginCommandGroup(i18n("Modify Fields")); 0399 } 0400 0401 foreach(Data::FieldPtr field, m_copiedFields) { 0402 // check for Choice fields with removed values to warn user 0403 if(field->type() == Data::Field::Choice || field->type() == Data::Field::Rating) { 0404 QStringList oldValues = m_coll->fieldByName(field->name())->allowed(); 0405 QStringList newValues = field->allowed(); 0406 for(QStringList::ConstIterator vIt = oldValues.constBegin(); vIt != oldValues.constEnd(); ++vIt) { 0407 if(newValues.contains(*vIt)) { 0408 continue; 0409 } 0410 int ret = KMessageBox::warningContinueCancel(this, 0411 i18n("<qt>Removing allowed values from the <i>%1</i> field which " 0412 "currently exist in the collection may cause data corruption. " 0413 "Do you want to keep your modified values or cancel and revert " 0414 "to the current ones?</qt>", field->title()), 0415 QString(), 0416 KGuiItem(i18n("Keep modified values"))); 0417 if(ret != KMessageBox::Continue) { 0418 if(field->type() == Data::Field::Choice) { 0419 field->setAllowed(oldValues); 0420 } else { // rating field 0421 Data::FieldPtr oldField = m_coll->fieldByName(field->name()); 0422 field->setProperty(QStringLiteral("minimum"), oldField->property(QStringLiteral("minimum"))); 0423 field->setProperty(QStringLiteral("maximum"), oldField->property(QStringLiteral("maximum"))); 0424 } 0425 } 0426 break; 0427 } 0428 } 0429 if(m_notifyMode == NotifyKernel) { 0430 emit modifyField(field); 0431 } else { 0432 m_coll->modifyField(field); 0433 } 0434 } 0435 0436 foreach(Data::FieldPtr field, m_newFields) { 0437 if(m_notifyMode == NotifyKernel) { 0438 emit addField(field); 0439 } else { 0440 m_coll->addField(field); 0441 } 0442 } 0443 0444 // set all text not to be colored, and get new list 0445 Data::FieldList fields; 0446 fields.reserve(m_fieldsWidget->count()); 0447 for(int i = 0; i < m_fieldsWidget->count(); ++i) { 0448 FieldListItem* item = static_cast<FieldListItem*>(m_fieldsWidget->item(i)); 0449 item->setColored(false); 0450 if(m_reordered) { 0451 Data::FieldPtr field = item->field(); 0452 if(field) { 0453 fields.append(field); 0454 } 0455 } 0456 } 0457 0458 // if reordering fields, need to add ReadOnly fields since they were not shown 0459 if(m_reordered) { 0460 foreach(Data::FieldPtr field, m_coll->fields()) { 0461 if(field->hasFlag(Data::Field::NoEdit)) { 0462 fields.append(field); 0463 } 0464 } 0465 } 0466 0467 if(fields.count() > 0) { 0468 if(m_notifyMode == NotifyKernel) { 0469 emit reorderFields(fields); 0470 } else { 0471 m_coll->reorderFields(fields); 0472 } 0473 } 0474 0475 // commit command group 0476 if(m_notifyMode == NotifyKernel) { 0477 emit endCommandGroup(); 0478 } 0479 0480 // now clear copied fields 0481 m_copiedFields.clear(); 0482 // clear new ones, too 0483 m_newFields.clear(); 0484 0485 m_currentField = static_cast<FieldListItem*>(m_fieldsWidget->currentItem())->field(); 0486 0487 // the field type might have changed, so need to update the type combo list with possible values 0488 if(m_currentField) { 0489 // set the updating flag since the values are changing and slots are firing 0490 // but we don't care about UI indications of changes 0491 bool wasUpdating = m_updatingValues; 0492 m_updatingValues = true; 0493 QString currType = m_typeCombo->currentText(); 0494 m_typeCombo->clear(); 0495 m_typeCombo->addItems(newTypesAllowed(m_currentField->type())); 0496 m_typeCombo->setCurrentItem(currType); 0497 // template might have been changed for dependent fields 0498 m_derivedEdit->setText(m_currentField->property(QStringLiteral("template"))); 0499 m_updatingValues = wasUpdating; 0500 } 0501 m_buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); 0502 } 0503 0504 void CollectionFieldsDialog::slotNew() { 0505 // first update the current one with all the values from the edit widgets 0506 updateField(); 0507 0508 // next check old values 0509 if(!checkValues()) { 0510 return; 0511 } 0512 0513 QString name = QLatin1String("custom") + QString::number(m_newFields.count()+1); 0514 int count = m_newFields.count() + 1; 0515 QString title = i18n("New Field %1", count); 0516 while(!m_fieldsWidget->findItems(title, Qt::MatchExactly).isEmpty()) { 0517 ++count; 0518 title = i18n("New Field %1", count); 0519 } 0520 0521 Data::FieldPtr field(new Data::Field(name, title)); 0522 m_newFields.append(field); 0523 // myDebug() << "adding new field " << title; 0524 0525 m_currentField = field; 0526 0527 FieldListItem* item = new FieldListItem(m_fieldsWidget, field); 0528 item->setColored(true); 0529 m_fieldsWidget->setCurrentItem(item); 0530 m_fieldsWidget->scrollToItem(item); 0531 slotModified(); 0532 m_titleEdit->setFocus(); 0533 m_titleEdit->selectAll(); 0534 } 0535 0536 void CollectionFieldsDialog::slotDelete() { 0537 if(!m_currentField) { 0538 return; 0539 } 0540 0541 if(m_newFields.contains(m_currentField)) { 0542 // remove field from vector before deleting item containing field 0543 m_newFields.removeAll(m_currentField); 0544 } else { 0545 if(m_notifyMode == NotifyKernel) { 0546 emit removeField(m_currentField); 0547 } else { 0548 m_coll->removeField(m_currentField); 0549 } 0550 emit signalCollectionModified(); 0551 m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 0552 } 0553 int currentRow = m_fieldsWidget->currentRow(); 0554 delete m_fieldsWidget->takeItem(currentRow); 0555 m_fieldsWidget->setCurrentRow(qMin(currentRow, m_fieldsWidget->count()-1)); 0556 m_fieldsWidget->scrollToItem(m_fieldsWidget->currentItem()); 0557 m_currentField = static_cast<FieldListItem*>(m_fieldsWidget->currentItem())->field(); // QSharedData gets auto-deleted 0558 } 0559 0560 void CollectionFieldsDialog::slotTypeChanged(const QString& type_) { 0561 Data::Field::Type type = Data::Field::Undef; 0562 const Data::Field::FieldMap fieldMap = Data::Field::typeMap(); 0563 for(Data::Field::FieldMap::ConstIterator it = fieldMap.begin(); it != fieldMap.end(); ++it) { 0564 if(it.value() == type_) { 0565 type = it.key(); 0566 break; 0567 } 0568 } 0569 if(type == Data::Field::Undef) { 0570 myWarning() << "type name not recognized:" << type_; 0571 type = Data::Field::Line; 0572 } 0573 0574 // only choice types gets allowed values 0575 m_allowEdit->setEnabled(type == Data::Field::Choice); 0576 0577 // paragraphs, tables, and images are their own category 0578 bool isCategory = (type == Data::Field::Para || type == Data::Field::Table || 0579 type == Data::Field::Image); 0580 m_catCombo->setEnabled(!isCategory); 0581 0582 // formatting is only applicable when the type is simple text or a table 0583 bool isText = (type == Data::Field::Line || type == Data::Field::Table); 0584 // formatNone is the default 0585 m_formatCombo->setEnabled(isText); 0586 0587 // multiple is only applicable for simple text and number 0588 isText = (type == Data::Field::Line || type == Data::Field::Number); 0589 m_multiple->setEnabled(isText); 0590 0591 // completion is only applicable for simple text, number, and URL 0592 isText = (isText || type == Data::Field::URL); 0593 m_complete->setEnabled(isText); 0594 0595 // grouping is not possible with paragraphs or images 0596 m_grouped->setEnabled(type != Data::Field::Para && type != Data::Field::Image); 0597 } 0598 0599 void CollectionFieldsDialog::slotHighlightedChanged(int index_) { 0600 if(index_ == m_oldIndex) { 0601 return; // state when checkValues() returns false 0602 } 0603 0604 // use this instead of blocking signals everywhere 0605 m_updatingValues = true; 0606 0607 // first update the current one with all the values from the edit widgets 0608 updateField(); 0609 0610 // next check old values 0611 if(!checkValues()) { 0612 // Other functions get called and change selection after this one. Use a SingleShot to revert 0613 QTimer::singleShot(0, this, &CollectionFieldsDialog::resetToCurrent); 0614 m_updatingValues = false; 0615 return; 0616 } 0617 m_oldIndex = index_; 0618 0619 m_btnUp->setEnabled(index_ > 0); 0620 m_btnDown->setEnabled(index_ < static_cast<int>(m_fieldsWidget->count())-1); 0621 0622 FieldListItem* item = dynamic_cast<FieldListItem*>(m_fieldsWidget->item(index_)); 0623 if(!item) { 0624 return; 0625 } 0626 0627 // need to get a pointer to the field with the new values to insert 0628 Data::FieldPtr field = item->field(); 0629 if(!field) { 0630 myDebug() << "no field found!"; 0631 return; 0632 } 0633 0634 // type is limited to certain types, unless it's a new field 0635 m_typeCombo->clear(); 0636 if(m_newFields.contains(field)) { 0637 m_typeCombo->addItems(newTypesAllowed(Data::Field::Undef)); 0638 } else { 0639 m_typeCombo->addItems(newTypesAllowed(field->type())); 0640 } 0641 populate(field); 0642 0643 // default button is enabled only if default collection contains the field 0644 if(m_defaultCollection) { 0645 const bool hasField = m_defaultCollection->hasField(field->name()); 0646 m_buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(hasField); 0647 } 0648 0649 m_currentField = field; 0650 m_updatingValues = false; 0651 } 0652 0653 void CollectionFieldsDialog::updateField() { 0654 Data::FieldPtr field = m_currentField; 0655 if(!field || !m_modified) { 0656 return; 0657 } 0658 0659 // only update name if it's one of the new ones 0660 if(m_newFields.contains(field)) { 0661 // name needs to be a valid XML element name 0662 QString name = XML::elementName(m_titleEdit->text().toLower()); 0663 if(name.isEmpty()) { // might end up with empty string 0664 name = QLatin1String("custom") + QString::number(m_newFields.count()+1); 0665 } 0666 while(m_coll->hasField(name)) { // ensure name uniqueness 0667 name += QLatin1String("-new"); 0668 } 0669 field->setName(name); 0670 } 0671 0672 const QString title = m_titleEdit->text().simplified(); 0673 updateTitle(title); 0674 0675 const Data::Field::FieldMap& fieldMap = Data::Field::typeMap(); 0676 for(Data::Field::FieldMap::ConstIterator it = fieldMap.begin(); it != fieldMap.end(); ++it) { 0677 if(it.value() == m_typeCombo->currentText()) { 0678 field->setType(it.key()); 0679 break; 0680 } 0681 } 0682 0683 if(field->type() == Data::Field::Choice) { 0684 static const QRegularExpression rx(QLatin1String("\\s*;\\s*")); 0685 #if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0)) 0686 field->setAllowed(m_allowEdit->text().split(rx, QString::SkipEmptyParts)); 0687 #else 0688 field->setAllowed(m_allowEdit->text().split(rx, Qt::SkipEmptyParts)); 0689 #endif 0690 field->setProperty(QStringLiteral("minimum"), QString()); 0691 field->setProperty(QStringLiteral("maximum"), QString()); 0692 } else if(field->type() == Data::Field::Rating) { 0693 QString v = field->property(QStringLiteral("minimum")); 0694 if(v.isEmpty()) { 0695 field->setProperty(QStringLiteral("minimum"), QString::number(1)); 0696 } 0697 v = field->property(QStringLiteral("maximum")); 0698 if(v.isEmpty()) { 0699 field->setProperty(QStringLiteral("maximum"), QString::number(5)); 0700 } 0701 } 0702 0703 if(field->isSingleCategory()) { 0704 field->setCategory(field->title()); 0705 } else { 0706 QString category = m_catCombo->currentText().simplified(); 0707 field->setCategory(category); 0708 m_catCombo->setCurrentItem(category, true); // if it doesn't exist, it's added 0709 } 0710 0711 if(m_derived->isChecked()) { 0712 field->setProperty(QStringLiteral("template"), m_derivedEdit->text()); 0713 } 0714 field->setDescription(m_descEdit->text()); 0715 field->setDefaultValue(m_defaultEdit->text()); 0716 0717 if(m_formatCombo->isEnabled()) { 0718 field->setFormatType(static_cast<FieldFormat::Type>(m_formatCombo->currentData().toInt())); 0719 } else { 0720 field->setFormatType(FieldFormat::FormatNone); 0721 } 0722 0723 int flags = 0; 0724 if(m_derived->isChecked()) { 0725 flags |= Data::Field::Derived; 0726 } 0727 if(m_complete->isChecked()) { 0728 flags |= Data::Field::AllowCompletion; 0729 } 0730 if(m_grouped->isChecked()) { 0731 flags |= Data::Field::AllowGrouped; 0732 } 0733 if(m_multiple->isChecked()) { 0734 flags |= Data::Field::AllowMultiple; 0735 } 0736 field->setFlags(flags); 0737 0738 m_modified = false; 0739 } 0740 0741 // The purpose here is to first set the modified flag. Then, if the field being edited is one 0742 // that exists in the collection already, a deep copy needs to be made. 0743 void CollectionFieldsDialog::slotModified() { 0744 // if I'm just updating the values, I don't care 0745 if(m_updatingValues) { 0746 return; 0747 } 0748 0749 m_modified = true; 0750 0751 m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 0752 m_buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); 0753 0754 if(!m_currentField) { 0755 myDebug() << "no current field!"; 0756 m_currentField = static_cast<FieldListItem*>(m_fieldsWidget->currentItem())->field(); 0757 } 0758 0759 // color the text 0760 static_cast<FieldListItem*>(m_fieldsWidget->currentItem())->setColored(true); 0761 0762 // check if copy exists already 0763 if(m_copiedFields.contains(m_currentField)) { 0764 return; 0765 } 0766 0767 // or, check if is a new field, in which case no copy is needed 0768 // check if copy exists already 0769 if(m_newFields.contains(m_currentField)) { 0770 return; 0771 } 0772 0773 m_currentField = new Data::Field(*m_currentField); 0774 m_copiedFields.append(m_currentField); 0775 static_cast<FieldListItem*>(m_fieldsWidget->currentItem())->setField(m_currentField); 0776 } 0777 0778 void CollectionFieldsDialog::updateTitle(const QString& title_) { 0779 if(m_currentField && m_currentField->title() != title_) { 0780 m_fieldsWidget->blockSignals(true); 0781 FieldListItem* oldItem = findItem(m_currentField); 0782 if(!oldItem) { 0783 return; 0784 } 0785 oldItem->setText(title_); 0786 // will always be colored since it's new 0787 oldItem->setColored(true); 0788 0789 m_currentField->setTitle(title_); 0790 m_fieldsWidget->blockSignals(false); 0791 } 0792 } 0793 0794 void CollectionFieldsDialog::slotDefault() { 0795 if(!m_currentField) { 0796 return; 0797 } 0798 0799 Data::FieldPtr defaultField = m_defaultCollection->fieldByName(m_currentField->name()); 0800 if(!defaultField) { 0801 return; 0802 } 0803 0804 QString caption = i18n("Revert Field Properties"); 0805 QString text = i18n("<qt><p>Do you really want to revert the properties for the <em>%1</em> " 0806 "field back to their default values?</p></qt>", m_currentField->title()); 0807 QString dontAsk = QStringLiteral("RevertFieldProperties"); 0808 int ret = KMessageBox::warningContinueCancel(this, text, caption, KGuiItem(i18n("Revert")), KStandardGuiItem::cancel(), dontAsk); 0809 if(ret != KMessageBox::Continue) { 0810 return; 0811 } 0812 0813 // now update all values with default 0814 m_updatingValues = true; 0815 populate(defaultField); 0816 m_updatingValues = false; 0817 slotModified(); 0818 } 0819 0820 void CollectionFieldsDialog::slotMoveUp() { 0821 int idx = m_fieldsWidget->currentRow(); 0822 if(idx < 1) { 0823 return; 0824 } 0825 // takeItem ends up signalling that the current index changed 0826 // need to revert m_oldIndex after taking the item 0827 QListWidgetItem* item = m_fieldsWidget->takeItem(idx); 0828 m_oldIndex++; 0829 m_fieldsWidget->insertItem(idx-1, item); 0830 m_fieldsWidget->setCurrentItem(item); 0831 m_reordered = true; 0832 // don't call slotModified() since that creates a deep copy. 0833 m_modified = true; 0834 0835 m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 0836 m_buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); 0837 } 0838 0839 void CollectionFieldsDialog::slotMoveDown() { 0840 int idx = m_fieldsWidget->currentRow(); 0841 if(idx > m_fieldsWidget->count()-1) { 0842 return; 0843 } 0844 // takeItem ends up signalling that the current index changed 0845 // need to revert m_oldIndex after taking the item 0846 QListWidgetItem* item = m_fieldsWidget->takeItem(idx); 0847 m_oldIndex--; 0848 m_fieldsWidget->insertItem(idx+1, item); 0849 m_fieldsWidget->setCurrentItem(item); 0850 m_reordered = true; 0851 // don't call slotModified() since that creates a deep copy. 0852 m_modified = true; 0853 0854 m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); 0855 m_buttonBox->button(QDialogButtonBox::Apply)->setEnabled(true); 0856 } 0857 0858 Tellico::FieldListItem* CollectionFieldsDialog::findItem(Tellico::Data::FieldPtr field_) { 0859 for(int i = 0; i < m_fieldsWidget->count(); ++i) { 0860 FieldListItem* textItem = static_cast<FieldListItem*>(m_fieldsWidget->item(i)); 0861 if(textItem->field() == field_) { 0862 return textItem; 0863 } 0864 } 0865 return nullptr; 0866 } 0867 0868 bool CollectionFieldsDialog::slotShowExtendedProperties() { 0869 if(!m_currentField) { 0870 return false; 0871 } 0872 0873 // the default value is included in properties, but it has a 0874 // separate edit box 0875 QString dv = m_currentField->defaultValue(); 0876 QString dt = m_currentField->property(QStringLiteral("template")); 0877 StringMap props = m_currentField->propertyList(); 0878 props.remove(QStringLiteral("default")); 0879 props.remove(QStringLiteral("template")); 0880 0881 StringMapDialog dlg(props, this, true); 0882 dlg.setWindowTitle(i18n("Extended Field Properties")); 0883 dlg.setLabels(i18n("Property"), i18n("Value")); 0884 if(dlg.exec() == QDialog::Accepted) { 0885 props = dlg.stringMap(); 0886 if(!dv.isEmpty()) { 0887 props.insert(QStringLiteral("default"), dv); 0888 } 0889 if(!dt.isEmpty()) { 0890 props.insert(QStringLiteral("template"), dt); 0891 } 0892 m_currentField->setPropertyList(props); 0893 slotModified(); 0894 return true; 0895 } 0896 return false; 0897 } 0898 0899 void CollectionFieldsDialog::slotDerivedChecked(bool checked_) { 0900 m_defaultEdit->setEnabled(!checked_); 0901 m_derivedEdit->setEnabled(checked_); 0902 } 0903 0904 void CollectionFieldsDialog::resetToCurrent() { 0905 m_fieldsWidget->setCurrentRow(m_oldIndex); 0906 } 0907 0908 bool CollectionFieldsDialog::checkValues() { 0909 if(!m_currentField) { 0910 return true; 0911 } 0912 0913 const QString title = m_currentField->title(); 0914 // find total number of boxes with this title in case multiple new ones with same title were added 0915 int titleCount = m_fieldsWidget->findItems(title, Qt::MatchExactly).count(); 0916 if((m_coll->fieldByTitle(title) && m_coll->fieldNameByTitle(title) != m_currentField->name()) || 0917 titleCount > 1) { 0918 // already have a field with this title 0919 KMessageBox::error(this, i18n("A field with this title already exists. Please enter a different title.")); 0920 m_titleEdit->selectAll(); 0921 return false; 0922 } 0923 0924 const QString category = m_currentField->category(); 0925 if(category.isEmpty()) { 0926 KMessageBox::error(this, i18n("<qt>The category may not be empty. Please enter a category.</qt>")); 0927 m_catCombo->lineEdit()->selectAll(); 0928 return false; 0929 } 0930 0931 Data::FieldList fields = m_coll->fieldsByCategory(category); 0932 if(!fields.isEmpty() && fields[0]->isSingleCategory() && fields[0]->name() != m_currentField->name()) { 0933 // can't have this category, cause it conflicts with a single-category field 0934 KMessageBox::error(this, i18n("<qt>A field may not be in the same category as a <em>Paragraph</em>, " 0935 "<em>Table</em> or <em>Image</em> field. Please enter a different category.</qt>")); 0936 m_catCombo->lineEdit()->selectAll(); 0937 return false; 0938 } 0939 0940 // the combobox is disabled for single-category fields 0941 if(!m_catCombo->isEnabled() && m_coll->fieldByTitle(title) && m_coll->fieldNameByTitle(title) != m_currentField->name()) { 0942 KMessageBox::error(this, i18n("A field's title may not be the same as an existing category. " 0943 "Please enter a different title.")); 0944 m_titleEdit->selectAll(); 0945 return false; 0946 } 0947 0948 // check for rating values outside bounds 0949 if(m_currentField->type() == Data::Field::Rating) { 0950 bool ok; // ok to ignore this here 0951 int low = Tellico::toUInt(m_currentField->property(QStringLiteral("minimum")), &ok); 0952 int high = Tellico::toUInt(m_currentField->property(QStringLiteral("maximum")), &ok); 0953 while(low < 1 || low > 9 || high < 1 || high > 10 || low >= high) { 0954 KMessageBox::error(this, i18n("The range for a rating field must be between 1 and 10, " 0955 "and the lower bound must be less than the higher bound. " 0956 "Please enter different low and high properties.")); 0957 if(slotShowExtendedProperties()) { 0958 low = Tellico::toUInt(m_currentField->property(QStringLiteral("minimum")), &ok); 0959 high = Tellico::toUInt(m_currentField->property(QStringLiteral("maximum")), &ok); 0960 } else { 0961 return false; 0962 } 0963 } 0964 } else if(m_currentField->type() == Data::Field::Table) { 0965 bool ok; // ok to ignore this here 0966 int ncols = Tellico::toUInt(m_currentField->property(QStringLiteral("columns")), &ok); 0967 // also enforced in GUI::TableFieldWidget 0968 if(ncols > 10) { 0969 KMessageBox::error(this, i18n("Tables are limited to a maximum of ten columns.")); 0970 m_currentField->setProperty(QStringLiteral("columns"), QStringLiteral("10")); 0971 } 0972 } 0973 0974 if(m_derived->isChecked() && !m_derivedEdit->text().contains(QLatin1Char('%'))) { 0975 KMessageBox::error(this, i18n("A field with a derived value must have a value template.")); 0976 m_derivedEdit->setFocus(); 0977 m_derivedEdit->selectAll(); 0978 return false; 0979 } 0980 0981 return true; 0982 } 0983 0984 void CollectionFieldsDialog::populate(Data::FieldPtr field_) { 0985 m_titleEdit->setText(field_->title()); 0986 0987 // if the current name is not there, then this will change the list! 0988 const Data::Field::FieldMap& fieldMap = Data::Field::typeMap(); 0989 int idx = m_typeCombo->findText(fieldMap[field_->type()]); 0990 m_typeCombo->setCurrentIndex(idx); 0991 slotTypeChanged(fieldMap[field_->type()]); // just setting the text doesn't emit the activated signal 0992 0993 if(field_->type() == Data::Field::Choice) { 0994 m_allowEdit->setText(field_->allowed().join(FieldFormat::delimiterString())); 0995 } else { 0996 m_allowEdit->clear(); 0997 } 0998 0999 idx = m_catCombo->findText(field_->category()); 1000 if(idx > -1) { 1001 m_catCombo->setCurrentIndex(idx); // have to do this here 1002 } else { 1003 m_catCombo->lineEdit()->setText(field_->category()); 1004 } 1005 m_descEdit->setText(field_->description()); 1006 if(field_->hasFlag(Data::Field::Derived)) { 1007 m_derivedEdit->setText(field_->property(QStringLiteral("template"))); 1008 m_derived->setChecked(true); 1009 m_defaultEdit->clear(); 1010 } else { 1011 m_derivedEdit->clear(); 1012 m_derived->setChecked(false); 1013 m_defaultEdit->setText(field_->defaultValue()); 1014 } 1015 slotDerivedChecked(m_derived->isChecked()); 1016 1017 m_formatCombo->setCurrentData(field_->formatType()); 1018 1019 m_complete->setChecked(field_->hasFlag(Data::Field::AllowCompletion)); 1020 m_multiple->setChecked(field_->hasFlag(Data::Field::AllowMultiple)); 1021 m_grouped->setChecked(field_->hasFlag(Data::Field::AllowGrouped)); 1022 1023 m_btnDelete->setEnabled(!field_->hasFlag(Data::Field::NoDelete)); 1024 } 1025 1026 // only certain type changes are allowed 1027 QStringList CollectionFieldsDialog::newTypesAllowed(int type_ /*=0*/) { 1028 // Undef means return all 1029 if(type_ == Data::Field::Undef) { 1030 return Data::Field::typeTitles(); 1031 } 1032 1033 const Data::Field::FieldMap& fieldMap = Data::Field::typeMap(); 1034 1035 QStringList newTypes; 1036 switch(type_) { 1037 case Data::Field::Line: // might not work if converted to a number or URL, but ok 1038 case Data::Field::Number: 1039 case Data::Field::URL: 1040 newTypes += fieldMap[Data::Field::Line]; 1041 newTypes += fieldMap[Data::Field::Para]; 1042 newTypes += fieldMap[Data::Field::Number]; 1043 newTypes += fieldMap[Data::Field::URL]; 1044 newTypes += fieldMap[Data::Field::Table]; 1045 break; 1046 1047 case Data::Field::Date: 1048 newTypes += fieldMap[Data::Field::Line]; 1049 newTypes += fieldMap[Data::Field::Date]; 1050 break; 1051 1052 case Data::Field::Bool: // doesn't really make sense, but can't hurt 1053 newTypes += fieldMap[Data::Field::Line]; 1054 newTypes += fieldMap[Data::Field::Para]; 1055 newTypes += fieldMap[Data::Field::Bool]; 1056 newTypes += fieldMap[Data::Field::Number]; 1057 newTypes += fieldMap[Data::Field::URL]; 1058 newTypes += fieldMap[Data::Field::Table]; 1059 break; 1060 1061 case Data::Field::Choice: 1062 newTypes += fieldMap[Data::Field::Line]; 1063 newTypes += fieldMap[Data::Field::Para]; 1064 newTypes += fieldMap[Data::Field::Choice]; 1065 newTypes += fieldMap[Data::Field::Number]; 1066 newTypes += fieldMap[Data::Field::URL]; 1067 newTypes += fieldMap[Data::Field::Table]; 1068 newTypes += fieldMap[Data::Field::Rating]; 1069 break; 1070 1071 case Data::Field::Table: // not really a good idea since the row delimiter will be exposed, but allow it 1072 case Data::Field::Table2: 1073 newTypes += fieldMap[Data::Field::Line]; 1074 newTypes += fieldMap[Data::Field::Number]; 1075 newTypes += fieldMap[Data::Field::Table]; 1076 break; 1077 1078 case Data::Field::Para: 1079 newTypes += fieldMap[Data::Field::Line]; 1080 newTypes += fieldMap[Data::Field::Para]; 1081 break; 1082 1083 case Data::Field::Rating: 1084 newTypes += fieldMap[Data::Field::Choice]; 1085 newTypes += fieldMap[Data::Field::Rating]; 1086 break; 1087 1088 // these can never be changed 1089 case Data::Field::Image: 1090 newTypes += fieldMap[static_cast<Data::Field::Type>(type_)]; 1091 break; 1092 1093 default: 1094 myDebug() << "no match for " << type_; 1095 newTypes = Data::Field::typeTitles(); 1096 break; 1097 } 1098 return newTypes; 1099 }