|
|
|
/***************************************************************************
|
|
|
|
copyright : (C) 2003-2006 by Robby Stephenson
|
|
|
|
email : robby@periapsis.org
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of version 2 of the GNU General Public License as *
|
|
|
|
* published by the Free Software Foundation; *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include "collectionfieldsdialog.h"
|
|
|
|
#include "collection.h"
|
|
|
|
#include "field.h"
|
|
|
|
#include "collectionfactory.h"
|
|
|
|
#include "gui/stringmapdialog.h"
|
|
|
|
#include "tellico_kernel.h"
|
|
|
|
#include "translators/tellico_xml.h"
|
|
|
|
#include "tellico_utils.h"
|
|
|
|
#include "tellico_debug.h"
|
|
|
|
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kcombobox.h>
|
|
|
|
#include <klineedit.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kmessagebox.h>
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
#include <kaccelmanager.h>
|
|
|
|
|
|
|
|
#include <tqgroupbox.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqhbox.h>
|
|
|
|
#include <tqvbox.h>
|
|
|
|
#include <tqlabel.h>
|
|
|
|
#include <tqradiobutton.h>
|
|
|
|
#include <tqbuttongroup.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqregexp.h>
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
|
|
|
|
using Tellico::FieldListBox;
|
|
|
|
using Tellico::CollectionFieldsDialog;
|
|
|
|
|
|
|
|
FieldListBox::FieldListBox(TQListBox* listbox_, Data::FieldPtr field_)
|
|
|
|
: GUI::ListBoxText(listbox_, field_->title()), m_field(field_) {
|
|
|
|
}
|
|
|
|
|
|
|
|
FieldListBox::FieldListBox(TQListBox* listbox_, Data::FieldPtr field_, TQListBoxItem* after_)
|
|
|
|
: GUI::ListBoxText(listbox_, field_->title(), after_), m_field(field_) {
|
|
|
|
}
|
|
|
|
|
|
|
|
CollectionFieldsDialog::CollectionFieldsDialog(Data::CollPtr coll_, TQWidget* parent_, const char* name_/*=0*/)
|
|
|
|
: KDialogBase(parent_, name_, false, i18n("Collection Fields"), Help|Default|Ok|Apply|Cancel, Ok, false),
|
|
|
|
m_coll(coll_),
|
|
|
|
m_defaultCollection(0),
|
|
|
|
m_currentField(0),
|
|
|
|
m_modified(false),
|
|
|
|
m_updatingValues(false),
|
|
|
|
m_reordered(false),
|
|
|
|
m_oldIndex(-1) {
|
|
|
|
TQWidget* page = new TQWidget(this);
|
|
|
|
setMainWidget(page);
|
|
|
|
TQHBoxLayout* topLayout = new TQHBoxLayout(page, 0, KDialog::spacingHint());
|
|
|
|
|
|
|
|
TQGroupBox* fieldsGroup = new TQGroupBox(1, Qt::Horizontal, i18n("Current Fields"), page);
|
|
|
|
topLayout->addWidget(fieldsGroup, 1);
|
|
|
|
m_fieldsBox = new TQListBox(fieldsGroup);
|
|
|
|
m_fieldsBox->setMinimumWidth(150);
|
|
|
|
|
|
|
|
Data::FieldVec fields = m_coll->fields();
|
|
|
|
for(Data::FieldVec::Iterator it = fields.begin(); it != fields.end(); ++it) {
|
|
|
|
// ignore ReadOnly
|
|
|
|
if(it->type() != Data::Field::ReadOnly) {
|
|
|
|
(void) new FieldListBox(m_fieldsBox, it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
connect(m_fieldsBox, TQT_SIGNAL(highlighted(int)), TQT_SLOT(slotHighlightedChanged(int)));
|
|
|
|
|
|
|
|
TQHBox* hb1 = new TQHBox(fieldsGroup);
|
|
|
|
hb1->setSpacing(KDialog::spacingHint());
|
|
|
|
m_btnNew = new KPushButton(i18n("New Field", "&New"), hb1);
|
|
|
|
m_btnNew->setIconSet(BarIcon(TQString::fromLatin1("filenew"), KIcon::SizeSmall));
|
|
|
|
TQWhatsThis::add(m_btnNew, i18n("Add a new field to the collection"));
|
|
|
|
m_btnDelete = new KPushButton(i18n("Delete Field", "&Delete"), hb1);
|
|
|
|
m_btnDelete->setIconSet(BarIconSet(TQString::fromLatin1("editdelete"), KIcon::SizeSmall));
|
|
|
|
TQWhatsThis::add(m_btnDelete, i18n("Remove a field from the collection"));
|
|
|
|
|
|
|
|
connect(m_btnNew, TQT_SIGNAL(clicked()), TQT_SLOT(slotNew()) );
|
|
|
|
connect(m_btnDelete, TQT_SIGNAL(clicked()), TQT_SLOT(slotDelete()));
|
|
|
|
|
|
|
|
TQHBox* hb2 = new TQHBox(fieldsGroup);
|
|
|
|
hb2->setSpacing(KDialog::spacingHint());
|
|
|
|
m_btnUp = new KPushButton(hb2);
|
|
|
|
m_btnUp->setPixmap(BarIcon(TQString::fromLatin1("up"), KIcon::SizeSmall));
|
|
|
|
TQWhatsThis::add(m_btnUp, i18n("Move this field up in the list. The list order is important "
|
|
|
|
"for the layout of the entry editor."));
|
|
|
|
m_btnDown = new KPushButton(hb2);
|
|
|
|
m_btnDown->setPixmap(BarIcon(TQString::fromLatin1("down"), KIcon::SizeSmall));
|
|
|
|
TQWhatsThis::add(m_btnDown, i18n("Move this field down in the list. The list order is important "
|
|
|
|
"for the layout of the entry editor."));
|
|
|
|
|
|
|
|
connect(m_btnUp, TQT_SIGNAL(clicked()), TQT_SLOT(slotMoveUp()) );
|
|
|
|
connect(m_btnDown, TQT_SIGNAL(clicked()), TQT_SLOT(slotMoveDown()));
|
|
|
|
|
|
|
|
TQVBox* vbox = new TQVBox(page);
|
|
|
|
vbox->setSpacing(KDialog::spacingHint());
|
|
|
|
topLayout->addWidget(vbox, 2);
|
|
|
|
|
|
|
|
TQGroupBox* propGroup = new TQGroupBox(1, Qt::Horizontal, i18n("Field Properties"), vbox);
|
|
|
|
|
|
|
|
TQWidget* grid = new TQWidget(propGroup);
|
|
|
|
// (parent, nrows, ncols, margin, spacing)
|
|
|
|
TQGridLayout* layout = new TQGridLayout(grid, 4, 4, 0, KDialog::spacingHint());
|
|
|
|
|
|
|
|
int row = -1;
|
|
|
|
TQLabel* label = new TQLabel(i18n("&Title:"), grid);
|
|
|
|
layout->addWidget(label, ++row, 0);
|
|
|
|
m_titleEdit = new KLineEdit(grid);
|
|
|
|
layout->addWidget(m_titleEdit, row, 1);
|
|
|
|
label->setBuddy(m_titleEdit);
|
|
|
|
TQString whats = i18n("The title of the field");
|
|
|
|
TQWhatsThis::add(label, whats);
|
|
|
|
TQWhatsThis::add(m_titleEdit, whats);
|
|
|
|
connect(m_titleEdit, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
label = new TQLabel(i18n("T&ype:"), grid);
|
|
|
|
layout->addWidget(label, row, 2);
|
|
|
|
m_typeCombo = new KComboBox(grid);
|
|
|
|
layout->addWidget(m_typeCombo, row, 3);
|
|
|
|
label->setBuddy(m_typeCombo);
|
|
|
|
whats = TQString::fromLatin1("<qt>");
|
|
|
|
whats += i18n("The type of the field determines what values may be used. ");
|
|
|
|
whats += i18n("<i>Simple Text</i> is used for most fields. ");
|
|
|
|
whats += i18n("<i>Paragraph</i> is for large text blocks. ");
|
|
|
|
whats += i18n("<i>Choice</i> limits the field to certain values. ");
|
|
|
|
whats += i18n("<i>Checkbox</i> is for a simple yes/no value. ");
|
|
|
|
whats += i18n("<i>Number</i> indicates that the field contains a numerical value. ");
|
|
|
|
whats += i18n("<i>URL</i> is for fields which refer to URLs, including references to other files. ");
|
|
|
|
whats += i18n("A <i>Table</i> may hold one or more columns of values. ");
|
|
|
|
whats += i18n("An <i>Image</i> field holds a picture. ");
|
|
|
|
whats += i18n("A <i>Date</i> field can be used for values with a day, month, and year. ");
|
|
|
|
whats += i18n("A <i>Rating</i> field uses stars to show a rating number. ");
|
|
|
|
whats += i18n("A <i>Dependent</i> field depends on the values of other "
|
|
|
|
"fields, and is formatted according to the field description. ");
|
|
|
|
whats += i18n("A <i>Read Only</i> is for internal values, possibly useful for import and export. ");
|
|
|
|
whats += TQString::fromLatin1("</qt>");
|
|
|
|
TQWhatsThis::add(label, whats);
|
|
|
|
TQWhatsThis::add(m_typeCombo, whats);
|
|
|
|
// the typeTitles match the fieldMap().values() but in a better order
|
|
|
|
m_typeCombo->insertStringList(Data::Field::typeTitles());
|
|
|
|
connect(m_typeCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotModified()));
|
|
|
|
connect(m_typeCombo, TQT_SIGNAL(activated(const TQString&)), TQT_SLOT(slotTypeChanged(const TQString&)));
|
|
|
|
|
|
|
|
label = new TQLabel(i18n("Cate&gory:"), grid);
|
|
|
|
layout->addWidget(label, ++row, 0);
|
|
|
|
m_catCombo = new KComboBox(true, grid);
|
|
|
|
layout->addWidget(m_catCombo, row, 1);
|
|
|
|
label->setBuddy(m_catCombo);
|
|
|
|
whats = i18n("The field category determines where the field is placed in the editor.");
|
|
|
|
TQWhatsThis::add(label, whats);
|
|
|
|
TQWhatsThis::add(m_catCombo, whats);
|
|
|
|
|
|
|
|
// I don't want to include the categories for singleCategory fields
|
|
|
|
TQStringList cats;
|
|
|
|
const TQStringList allCats = m_coll->fieldCategories();
|
|
|
|
for(TQStringList::ConstIterator it = allCats.begin(); it != allCats.end(); ++it) {
|
|
|
|
Data::FieldVec fields = m_coll->fieldsByCategory(*it);
|
|
|
|
if(!fields.isEmpty() && !fields.begin()->isSingleCategory()) {
|
|
|
|
cats.append(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_catCombo->insertStringList(cats);
|
|
|
|
m_catCombo->setDuplicatesEnabled(false);
|
|
|
|
connect(m_catCombo, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
label = new TQLabel(i18n("Descr&iption:"), grid);
|
|
|
|
layout->addWidget(label, ++row, 0);
|
|
|
|
m_descEdit = new KLineEdit(grid);
|
|
|
|
m_descEdit->setMinimumWidth(150);
|
|
|
|
layout->addMultiCellWidget(m_descEdit, row, row, 1, 3);
|
|
|
|
label->setBuddy(m_descEdit);
|
|
|
|
/* TRANSLATORS: Do not translate %{year} and %{title}. */
|
|
|
|
whats = i18n("The description is a useful reminder of what information is contained in the "
|
|
|
|
"field. For <i>Dependent</i> fields, the description is a format string such as "
|
|
|
|
"\"%{year} %{title}\" where the named fields get substituted in the string.");
|
|
|
|
TQWhatsThis::add(label, whats);
|
|
|
|
TQWhatsThis::add(m_descEdit, whats);
|
|
|
|
connect(m_descEdit, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
label = new TQLabel(i18n("&Default value:"), grid);
|
|
|
|
layout->addWidget(label, ++row, 0);
|
|
|
|
m_defaultEdit = new KLineEdit(grid);
|
|
|
|
layout->addMultiCellWidget(m_defaultEdit, row, row, 1, 3);
|
|
|
|
label->setBuddy(m_defaultEdit);
|
|
|
|
whats = i18n("<qt>A default value can be set for new entries.</qt>");
|
|
|
|
TQWhatsThis::add(label, whats);
|
|
|
|
TQWhatsThis::add(m_defaultEdit, whats);
|
|
|
|
connect(m_defaultEdit, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
label = new TQLabel(i18n("A&llowed values:"), grid);
|
|
|
|
layout->addWidget(label, ++row, 0);
|
|
|
|
m_allowEdit = new KLineEdit(grid);
|
|
|
|
layout->addMultiCellWidget(m_allowEdit, row, row, 1, 3);
|
|
|
|
label->setBuddy(m_allowEdit);
|
|
|
|
whats = i18n("<qt>For <i>Choice</i>-type fields, these are the only values allowed. They are "
|
|
|
|
"placed in a combo box. The possible values have to be separated by a semi-colon, "
|
|
|
|
"for example: \"dog; cat; mouse\"</qt>");
|
|
|
|
TQWhatsThis::add(label, whats);
|
|
|
|
TQWhatsThis::add(m_allowEdit, whats);
|
|
|
|
connect(m_allowEdit, TQT_SIGNAL(textChanged(const TQString&)), TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
label = new TQLabel(i18n("Extended &properties:"), grid);
|
|
|
|
layout->addWidget(label, ++row, 0);
|
|
|
|
m_btnExtended = new KPushButton(i18n("&Set..."), grid);
|
|
|
|
m_btnExtended->setIconSet(BarIcon(TQString::fromLatin1("bookmark"), KIcon::SizeSmall));
|
|
|
|
layout->addWidget(m_btnExtended, row, 1);
|
|
|
|
label->setBuddy(m_btnExtended);
|
|
|
|
whats = i18n("Extended field properties are used to specify things such as the corresponding bibtex field.");
|
|
|
|
TQWhatsThis::add(label, whats);
|
|
|
|
TQWhatsThis::add(m_btnExtended, whats);
|
|
|
|
connect(m_btnExtended, TQT_SIGNAL(clicked()), TQT_SLOT(slotShowExtendedProperties()));
|
|
|
|
|
|
|
|
TQButtonGroup* bg = new TQButtonGroup(1, Qt::Horizontal, i18n("Format Options"), vbox);
|
|
|
|
m_formatNone = new TQRadioButton(i18n("No formatting"), bg);
|
|
|
|
TQWhatsThis::add(m_formatNone, i18n("This option prevents the field from ever being "
|
|
|
|
"automatically formatted or capitalized."));
|
|
|
|
m_formatPlain = new TQRadioButton(i18n("Allow auto-capitalization only"), bg);
|
|
|
|
TQWhatsThis::add(m_formatPlain, i18n("This option allows the field to be capitalized, but "
|
|
|
|
"not specially formatted."));
|
|
|
|
m_formatTitle = new TQRadioButton(i18n("Format as a title"), bg);
|
|
|
|
TQWhatsThis::add(m_formatTitle, i18n("This option capitalizes and formats the field as a "
|
|
|
|
"title, but only if those options are globally set."));
|
|
|
|
m_formatName = new TQRadioButton(i18n("Format as a name"), bg);
|
|
|
|
TQWhatsThis::add(m_formatName, i18n("This option capitalizes and formats the field as a "
|
|
|
|
"name, but only if those options are globally set."));
|
|
|
|
connect(bg, TQT_SIGNAL(clicked(int)), TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
TQGroupBox* optionsGroup = new TQGroupBox(1, Qt::Horizontal, i18n("Field Options"), vbox);
|
|
|
|
m_complete = new TQCheckBox(i18n("Enable auto-completion"), optionsGroup);
|
|
|
|
TQWhatsThis::add(m_complete, i18n("If checked, KDE auto-completion will be enabled in the "
|
|
|
|
"text edit box for this field."));
|
|
|
|
m_multiple = new TQCheckBox(i18n("Allow multiple values"), optionsGroup);
|
|
|
|
TQWhatsThis::add(m_multiple, i18n("If checked, Tellico will parse the values in the field "
|
|
|
|
"for multiple values, separated by a semi-colon."));
|
|
|
|
m_grouped = new TQCheckBox(i18n("Allow grouping"), optionsGroup);
|
|
|
|
TQWhatsThis::add(m_grouped, i18n("If checked, this field may be used to group the entries in "
|
|
|
|
"the group view."));
|
|
|
|
connect(m_complete, TQT_SIGNAL(clicked()), TQT_SLOT(slotModified()));
|
|
|
|
connect(m_multiple, TQT_SIGNAL(clicked()), TQT_SLOT(slotModified()));
|
|
|
|
connect(m_grouped, TQT_SIGNAL(clicked()), TQT_SLOT(slotModified()));
|
|
|
|
|
|
|
|
// need to stretch at bottom
|
|
|
|
vbox->setStretchFactor(new TQWidget(vbox), 1);
|
|
|
|
KAcceleratorManager::manage(vbox);
|
|
|
|
|
|
|
|
// keep a default collection
|
|
|
|
m_defaultCollection = CollectionFactory::collection(m_coll->type(), true);
|
|
|
|
|
|
|
|
TQWhatsThis::add(actionButton(KDialogBase::Default),
|
|
|
|
i18n("Revert the selected field's properties to the default values."));
|
|
|
|
|
|
|
|
enableButtonOK(false);
|
|
|
|
enableButtonApply(false);
|
|
|
|
|
|
|
|
setHelp(TQString::fromLatin1("fields-dialog"));
|
|
|
|
|
|
|
|
// initially the m_typeCombo is populated with all types, but as soon as something is
|
|
|
|
// selected in the fields box, the combo box is cleared and filled with the allowable
|
|
|
|
// new types. The problem is that when more types are added, the size of the combo box
|
|
|
|
// doesn't change. So when everything is laid out, the combo box needs to have all the
|
|
|
|
// items there.
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotSelectInitial()));
|
|
|
|
}
|
|
|
|
|
|
|
|
CollectionFieldsDialog::~CollectionFieldsDialog() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotSelectInitial() {
|
|
|
|
m_fieldsBox->setSelected(0, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotOk() {
|
|
|
|
updateField();
|
|
|
|
if(!checkValues()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
applyChanges();
|
|
|
|
accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotApply() {
|
|
|
|
updateField();
|
|
|
|
if(!checkValues()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
applyChanges();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::applyChanges() {
|
|
|
|
// start a command group, "Modify" is a generic term here since the commands could be add, modify, or delete
|
|
|
|
Kernel::self()->beginCommandGroup(i18n("Modify Fields"));
|
|
|
|
|
|
|
|
Data::FieldPtr field;
|
|
|
|
for(Data::FieldVec::Iterator it = m_copiedFields.begin(); it != m_copiedFields.end(); ++it) {
|
|
|
|
field = it;
|
|
|
|
// check for Choice fields with removed values to warn user
|
|
|
|
if(field->type() == Data::Field::Choice || field->type() == Data::Field::Rating) {
|
|
|
|
TQStringList oldValues = m_coll->fieldByName(field->name())->allowed();
|
|
|
|
TQStringList newValues = field->allowed();
|
|
|
|
for(TQStringList::ConstIterator vIt = oldValues.begin(); vIt != oldValues.end(); ++vIt) {
|
|
|
|
if(newValues.contains(*vIt)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
int ret = KMessageBox::warningContinueCancel(this,
|
|
|
|
i18n("<qt>Removing allowed values from the <i>%1</i> field which "
|
|
|
|
"currently exist in the collection may cause data corruption. "
|
|
|
|
"Do you want to keep your modified values or cancel and revert "
|
|
|
|
"to the current ones?</qt>").arg(field->title()),
|
|
|
|
TQString(),
|
|
|
|
i18n("Keep modified values"));
|
|
|
|
if(ret != KMessageBox::Continue) {
|
|
|
|
if(field->type() == Data::Field::Choice) {
|
|
|
|
field->setAllowed(oldValues);
|
|
|
|
} else { // rating field
|
|
|
|
Data::FieldPtr oldField = m_coll->fieldByName(field->name());
|
|
|
|
field->setProperty(TQString::fromLatin1("minimum"), oldField->property(TQString::fromLatin1("minimum")));
|
|
|
|
field->setProperty(TQString::fromLatin1("maximum"), oldField->property(TQString::fromLatin1("maximum")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Kernel::self()->modifyField(field);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(Data::FieldVec::Iterator it = m_newFields.begin(); it != m_newFields.end(); ++it) {
|
|
|
|
Kernel::self()->addField(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
// set all text not to be colored, and get new list
|
|
|
|
Data::FieldVec fields;
|
|
|
|
for(TQListBoxItem* item = m_fieldsBox->firstItem(); item; item = item->next()) {
|
|
|
|
static_cast<FieldListBox*>(item)->setColored(false);
|
|
|
|
if(m_reordered) {
|
|
|
|
Data::FieldPtr field = static_cast<FieldListBox*>(item)->field();
|
|
|
|
if(field) {
|
|
|
|
fields.append(field);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if reordering fields, need to add ReadOnly fields since they were not shown
|
|
|
|
if(m_reordered) {
|
|
|
|
Data::FieldVec allFields = m_coll->fields();
|
|
|
|
for(Data::FieldVec::Iterator it = allFields.begin(); it != allFields.end(); ++it) {
|
|
|
|
if(it->type() == Data::Field::ReadOnly) {
|
|
|
|
fields.append(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fields.count() > 0) {
|
|
|
|
Kernel::self()->reorderFields(fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
// commit command group
|
|
|
|
Kernel::self()->endCommandGroup();
|
|
|
|
|
|
|
|
// now clear copied fields
|
|
|
|
m_copiedFields.clear();
|
|
|
|
// clear new ones, too
|
|
|
|
m_newFields.clear();
|
|
|
|
|
|
|
|
m_currentField = static_cast<FieldListBox*>(m_fieldsBox->selectedItem())->field();
|
|
|
|
|
|
|
|
// the field type might have changed, so need to update the type combo list with possible values
|
|
|
|
if(m_currentField) {
|
|
|
|
// set the updating flag since the values are changing and slots are firing
|
|
|
|
// but we don't care about UI indications of changes
|
|
|
|
bool wasUpdating = m_updatingValues;
|
|
|
|
m_updatingValues = true;
|
|
|
|
TQString currType = m_typeCombo->currentText();
|
|
|
|
m_typeCombo->clear();
|
|
|
|
m_typeCombo->insertStringList(newTypesAllowed(m_currentField->type()));
|
|
|
|
m_typeCombo->setCurrentItem(currType);
|
|
|
|
// description might have been changed for dependent fields
|
|
|
|
m_descEdit->setText(m_currentField->description());
|
|
|
|
m_updatingValues = wasUpdating;
|
|
|
|
}
|
|
|
|
enableButtonApply(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotNew() {
|
|
|
|
// first update the current one with all the values from the edit widgets
|
|
|
|
updateField();
|
|
|
|
|
|
|
|
// next check old values
|
|
|
|
if(!checkValues()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString name = TQString::fromLatin1("custom") + TQString::number(m_newFields.count()+1);
|
|
|
|
int count = m_newFields.count() + 1;
|
|
|
|
TQString title = i18n("New Field") + TQString::fromLatin1(" %1").arg(count);
|
|
|
|
while(m_fieldsBox->findItem(title)) {
|
|
|
|
++count;
|
|
|
|
title = i18n("New Field") + TQString::fromLatin1(" %1").arg(count);
|
|
|
|
}
|
|
|
|
|
|
|
|
Data::FieldPtr field = new Data::Field(name, title);
|
|
|
|
m_newFields.append(field);
|
|
|
|
// myDebug() << "CollectionFieldsDialog::slotNew() - adding new field " << title << endl;
|
|
|
|
|
|
|
|
m_currentField = field;
|
|
|
|
|
|
|
|
FieldListBox* box = new FieldListBox(m_fieldsBox, field);
|
|
|
|
m_fieldsBox->setSelected(box, true);
|
|
|
|
box->setColored(true);
|
|
|
|
m_fieldsBox->ensureCurrentVisible();
|
|
|
|
slotModified();
|
|
|
|
m_titleEdit->setFocus();
|
|
|
|
m_titleEdit->selectAll();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotDelete() {
|
|
|
|
if(!m_currentField) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_newFields.contains(m_currentField)) {
|
|
|
|
// remove field from vector before deleting item containing field
|
|
|
|
m_newFields.remove(m_currentField);
|
|
|
|
m_fieldsBox->removeItem(m_fieldsBox->currentItem());
|
|
|
|
m_fieldsBox->setSelected(m_fieldsBox->currentItem(), true);
|
|
|
|
m_fieldsBox->ensureCurrentVisible();
|
|
|
|
m_currentField = static_cast<FieldListBox*>(m_fieldsBox->selectedItem())->field(); // KShared gets auto-deleted
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool success = Kernel::self()->removeField(m_currentField);
|
|
|
|
if(success) {
|
|
|
|
emit signalCollectionModified();
|
|
|
|
m_fieldsBox->removeItem(m_fieldsBox->currentItem());
|
|
|
|
m_fieldsBox->setSelected(m_fieldsBox->currentItem(), true);
|
|
|
|
m_fieldsBox->ensureCurrentVisible();
|
|
|
|
m_currentField = static_cast<FieldListBox*>(m_fieldsBox->selectedItem())->field();
|
|
|
|
enableButtonOK(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotTypeChanged(const TQString& type_) {
|
|
|
|
Data::Field::Type type = Data::Field::Undef;
|
|
|
|
const Data::Field::FieldMap fieldMap = Data::Field::typeMap();
|
|
|
|
for(Data::Field::FieldMap::ConstIterator it = fieldMap.begin(); it != fieldMap.end(); ++it) {
|
|
|
|
if(it.data() == type_) {
|
|
|
|
type = it.key();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(type == Data::Field::Undef) {
|
|
|
|
kdWarning() << "CollectionFieldsDialog::slotTypeChanged() - type name not recognized: " << type_ << endl;
|
|
|
|
type = Data::Field::Line;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only choice types gets allowed values
|
|
|
|
m_allowEdit->setEnabled(type == Data::Field::Choice);
|
|
|
|
|
|
|
|
// paragraphs, tables, and images are their own category
|
|
|
|
bool isCategory = (type == Data::Field::Para || type == Data::Field::Table ||
|
|
|
|
type == Data::Field::Table2 || type == Data::Field::Image);
|
|
|
|
m_catCombo->setEnabled(!isCategory);
|
|
|
|
|
|
|
|
// formatting is only applicable when the type is simple text or a table
|
|
|
|
bool isText = (type == Data::Field::Line || type == Data::Field::Table ||
|
|
|
|
type == Data::Field::Table2);
|
|
|
|
// formatNone is the default
|
|
|
|
m_formatPlain->setEnabled(isText);
|
|
|
|
m_formatName->setEnabled(isText);
|
|
|
|
m_formatTitle->setEnabled(isText);
|
|
|
|
|
|
|
|
// multiple is only applicable for simple text and number
|
|
|
|
isText = (type == Data::Field::Line || type == Data::Field::Number);
|
|
|
|
m_multiple->setEnabled(isText);
|
|
|
|
|
|
|
|
// completion is only applicable for simple text, number, and URL
|
|
|
|
isText = (isText || type == Data::Field::URL);
|
|
|
|
m_complete->setEnabled(isText);
|
|
|
|
|
|
|
|
// grouping is not possible with paragraphs or images
|
|
|
|
m_grouped->setEnabled(type != Data::Field::Para && type != Data::Field::Image);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotHighlightedChanged(int index_) {
|
|
|
|
// myDebug() << "CollectionFieldsDialog::slotHighlightedChanged() - " << index_ << endl;
|
|
|
|
|
|
|
|
// use this instead of blocking signals everywhere
|
|
|
|
m_updatingValues = true;
|
|
|
|
|
|
|
|
// first update the current one with all the values from the edit widgets
|
|
|
|
updateField();
|
|
|
|
|
|
|
|
// next check old values
|
|
|
|
if(!checkValues()) {
|
|
|
|
m_fieldsBox->blockSignals(true);
|
|
|
|
m_fieldsBox->setSelected(m_oldIndex, true);
|
|
|
|
m_fieldsBox->blockSignals(false);
|
|
|
|
m_updatingValues = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_oldIndex = index_;
|
|
|
|
|
|
|
|
m_btnUp->setEnabled(index_ > 0);
|
|
|
|
m_btnDown->setEnabled(index_ < static_cast<int>(m_fieldsBox->count())-1);
|
|
|
|
|
|
|
|
FieldListBox* item = dynamic_cast<FieldListBox*>(m_fieldsBox->item(index_));
|
|
|
|
if(!item) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// need to get a pointer to the field with the new values to insert
|
|
|
|
Data::FieldPtr field = item->field();
|
|
|
|
if(!field) {
|
|
|
|
myDebug() << "CollectionFieldsDialog::slotHighlightedChanged() - no field found!" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_titleEdit->setText(field->title());
|
|
|
|
|
|
|
|
// type is limited to certain types, unless it's a new field
|
|
|
|
m_typeCombo->clear();
|
|
|
|
if(m_newFields.contains(field)) {
|
|
|
|
m_typeCombo->insertStringList(newTypesAllowed(Data::Field::Undef));
|
|
|
|
} else {
|
|
|
|
m_typeCombo->insertStringList(newTypesAllowed(field->type()));
|
|
|
|
}
|
|
|
|
// if the current name is not there, then this will change the list!
|
|
|
|
const Data::Field::FieldMap& fieldMap = Data::Field::typeMap();
|
|
|
|
m_typeCombo->setCurrentText(fieldMap[field->type()]);
|
|
|
|
slotTypeChanged(fieldMap[field->type()]); // just setting the text doesn't emit the activated signal
|
|
|
|
|
|
|
|
if(field->type() == Data::Field::Choice) {
|
|
|
|
m_allowEdit->setText(field->allowed().join(TQString::fromLatin1("; ")));
|
|
|
|
} else {
|
|
|
|
m_allowEdit->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_catCombo->setCurrentText(field->category()); // have to do this here
|
|
|
|
m_descEdit->setText(field->description());
|
|
|
|
m_defaultEdit->setText(field->defaultValue());
|
|
|
|
|
|
|
|
switch(field->formatFlag()) {
|
|
|
|
case Data::Field::FormatNone:
|
|
|
|
case Data::Field::FormatDate: // as yet unimplemented
|
|
|
|
m_formatNone->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::FormatPlain:
|
|
|
|
m_formatPlain->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::FormatTitle:
|
|
|
|
m_formatTitle->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::FormatName:
|
|
|
|
m_formatName->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
kdWarning() << "CollectionFieldsDialog::slotHighlightedChanged() - no format type!" << endl;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int flags = field->flags();
|
|
|
|
m_complete->setChecked(flags & Data::Field::AllowCompletion);
|
|
|
|
m_multiple->setChecked(flags & Data::Field::AllowMultiple);
|
|
|
|
m_grouped->setChecked(flags & Data::Field::AllowGrouped);
|
|
|
|
|
|
|
|
m_btnDelete->setEnabled(!(flags & Data::Field::NoDelete));
|
|
|
|
|
|
|
|
// default button is enabled only if default collection contains the field
|
|
|
|
if(m_defaultCollection) {
|
|
|
|
bool hasField = m_defaultCollection->hasField(field->name());
|
|
|
|
actionButton(KDialogBase::Default)->setEnabled(hasField);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentField = field;
|
|
|
|
m_updatingValues = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::updateField() {
|
|
|
|
// myDebug() << "CollectionFieldsDialog::updateField()" << endl;
|
|
|
|
Data::FieldPtr field = m_currentField;
|
|
|
|
if(!field || !m_modified) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only update name if it's one of the new ones
|
|
|
|
if(m_newFields.contains(field)) {
|
|
|
|
// name needs to be a valid XML element name
|
|
|
|
TQString name = XML::elementName(m_titleEdit->text().lower());
|
|
|
|
if(name.isEmpty()) { // might end up with empty string
|
|
|
|
name = TQString::fromLatin1("custom") + TQString::number(m_newFields.count()+1);
|
|
|
|
}
|
|
|
|
while(m_coll->hasField(name)) { // ensure name uniqueness
|
|
|
|
name += TQString::fromLatin1("-new");
|
|
|
|
}
|
|
|
|
field->setName(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQString title = m_titleEdit->text().simplifyWhiteSpace();
|
|
|
|
updateTitle(title);
|
|
|
|
|
|
|
|
const Data::Field::FieldMap& fieldMap = Data::Field::typeMap();
|
|
|
|
for(Data::Field::FieldMap::ConstIterator it = fieldMap.begin(); it != fieldMap.end(); ++it) {
|
|
|
|
if(it.data() == m_typeCombo->currentText()) {
|
|
|
|
field->setType(it.key());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(field->type() == Data::Field::Choice) {
|
|
|
|
const TQRegExp rx(TQString::fromLatin1("\\s*;\\s*"));
|
|
|
|
field->setAllowed(TQStringList::split(rx, m_allowEdit->text()));
|
|
|
|
field->setProperty(TQString::fromLatin1("minimum"), TQString());
|
|
|
|
field->setProperty(TQString::fromLatin1("maximum"), TQString());
|
|
|
|
} else if(field->type() == Data::Field::Rating) {
|
|
|
|
TQString v = field->property(TQString::fromLatin1("minimum"));
|
|
|
|
if(v.isEmpty()) {
|
|
|
|
field->setProperty(TQString::fromLatin1("minimum"), TQString::number(1));
|
|
|
|
}
|
|
|
|
v = field->property(TQString::fromLatin1("maximum"));
|
|
|
|
if(v.isEmpty()) {
|
|
|
|
field->setProperty(TQString::fromLatin1("maximum"), TQString::number(5));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(field->isSingleCategory()) {
|
|
|
|
field->setCategory(field->title());
|
|
|
|
} else {
|
|
|
|
TQString category = m_catCombo->currentText().simplifyWhiteSpace();
|
|
|
|
field->setCategory(category);
|
|
|
|
m_catCombo->setCurrentItem(category, true); // if it doesn't exist, it's added
|
|
|
|
}
|
|
|
|
|
|
|
|
field->setDescription(m_descEdit->text());
|
|
|
|
field->setDefaultValue(m_defaultEdit->text());
|
|
|
|
|
|
|
|
if(m_formatTitle->isChecked()) {
|
|
|
|
field->setFormatFlag(Data::Field::FormatTitle);
|
|
|
|
} else if(m_formatName->isChecked()) {
|
|
|
|
field->setFormatFlag(Data::Field::FormatName);
|
|
|
|
} else if(m_formatPlain->isChecked()) {
|
|
|
|
field->setFormatFlag(Data::Field::FormatPlain);
|
|
|
|
} else {
|
|
|
|
field->setFormatFlag(Data::Field::FormatNone);
|
|
|
|
}
|
|
|
|
|
|
|
|
int flags = 0;
|
|
|
|
if(m_complete->isChecked()) {
|
|
|
|
flags |= Data::Field::AllowCompletion;
|
|
|
|
}
|
|
|
|
if(m_grouped->isChecked()) {
|
|
|
|
flags |= Data::Field::AllowGrouped;
|
|
|
|
}
|
|
|
|
if(m_multiple->isChecked()) {
|
|
|
|
flags |= Data::Field::AllowMultiple;
|
|
|
|
}
|
|
|
|
field->setFlags(flags);
|
|
|
|
|
|
|
|
m_modified = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The purpose here is to first set the modified flag. Then, if the field being edited is one
|
|
|
|
// that exists in the collection already, a deep copy needs to be made.
|
|
|
|
void CollectionFieldsDialog::slotModified() {
|
|
|
|
// myDebug() << "CollectionFieldsDialog::slotModified()" << endl;
|
|
|
|
// if I'm just updating the values, I don't care
|
|
|
|
if(m_updatingValues) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_modified = true;
|
|
|
|
|
|
|
|
enableButtonOK(true);
|
|
|
|
enableButtonApply(true);
|
|
|
|
|
|
|
|
if(!m_currentField) {
|
|
|
|
myDebug() << "CollectionFieldsDialog::slotModified() - no current field!" << endl;
|
|
|
|
m_currentField = static_cast<FieldListBox*>(m_fieldsBox->selectedItem())->field();
|
|
|
|
}
|
|
|
|
|
|
|
|
// color the text
|
|
|
|
static_cast<FieldListBox*>(m_fieldsBox->selectedItem())->setColored(true);
|
|
|
|
|
|
|
|
// check if copy exists already
|
|
|
|
if(m_copiedFields.contains(m_currentField)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// or, check if is a new field, in which case no copy is needed
|
|
|
|
// check if copy exists already
|
|
|
|
if(m_newFields.contains(m_currentField)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentField = new Data::Field(*m_currentField);
|
|
|
|
m_copiedFields.append(m_currentField);
|
|
|
|
static_cast<FieldListBox*>(m_fieldsBox->selectedItem())->setField(m_currentField);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::updateTitle(const TQString& title_) {
|
|
|
|
// myDebug() << "CollectionFieldsDialog::updateTitle()" << endl;
|
|
|
|
if(m_currentField && m_currentField->title() != title_) {
|
|
|
|
m_fieldsBox->blockSignals(true);
|
|
|
|
FieldListBox* oldItem = findItem(m_fieldsBox, m_currentField);
|
|
|
|
if(!oldItem) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
oldItem->setText(title_);
|
|
|
|
// will always be colored since it's new
|
|
|
|
oldItem->setColored(true);
|
|
|
|
m_fieldsBox->triggerUpdate(true);
|
|
|
|
|
|
|
|
m_currentField->setTitle(title_);
|
|
|
|
m_fieldsBox->blockSignals(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotDefault() {
|
|
|
|
if(!m_currentField) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Data::FieldPtr defaultField = m_defaultCollection->fieldByName(m_currentField->name());
|
|
|
|
if(!defaultField) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString caption = i18n("Revert Field Properties");
|
|
|
|
TQString text = i18n("<qt><p>Do you really want to revert the properties for the <em>%1</em> "
|
|
|
|
"field back to their default values?</p></qt>").arg(m_currentField->title());
|
|
|
|
TQString dontAsk = TQString::fromLatin1("RevertFieldProperties");
|
|
|
|
int ret = KMessageBox::warningContinueCancel(this, text, caption, i18n("Revert"), dontAsk);
|
|
|
|
if(ret != KMessageBox::Continue) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now update all values with default
|
|
|
|
m_updatingValues = true;
|
|
|
|
m_titleEdit->setText(defaultField->title());
|
|
|
|
|
|
|
|
const Data::Field::FieldMap& fieldMap = Data::Field::typeMap();
|
|
|
|
m_typeCombo->setCurrentText(fieldMap[defaultField->type()]);
|
|
|
|
slotTypeChanged(fieldMap[defaultField->type()]); // just setting the text doesn't emit the activated signal
|
|
|
|
|
|
|
|
if(defaultField->type() == Data::Field::Choice) {
|
|
|
|
m_allowEdit->setText(defaultField->allowed().join(TQString::fromLatin1("; ")));
|
|
|
|
} else {
|
|
|
|
m_allowEdit->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_catCombo->setCurrentText(defaultField->category()); // have to do this here
|
|
|
|
m_descEdit->setText(defaultField->description());
|
|
|
|
m_defaultEdit->setText(defaultField->defaultValue());
|
|
|
|
|
|
|
|
switch(defaultField->formatFlag()) {
|
|
|
|
case Data::Field::FormatNone:
|
|
|
|
case Data::Field::FormatDate:
|
|
|
|
m_formatNone->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::FormatPlain:
|
|
|
|
m_formatPlain->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::FormatTitle:
|
|
|
|
m_formatTitle->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::FormatName:
|
|
|
|
m_formatName->setChecked(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int flags = defaultField->flags();
|
|
|
|
m_complete->setChecked(flags & Data::Field::AllowCompletion);
|
|
|
|
m_multiple->setChecked(flags & Data::Field::AllowMultiple);
|
|
|
|
m_grouped->setChecked(flags & Data::Field::AllowGrouped);
|
|
|
|
|
|
|
|
m_btnDelete->setEnabled(!(defaultField->flags() & Data::Field::NoDelete));
|
|
|
|
|
|
|
|
// m_titleEdit->setFocus();
|
|
|
|
// m_titleEdit->selectAll();
|
|
|
|
|
|
|
|
m_updatingValues = false;
|
|
|
|
slotModified();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotMoveUp() {
|
|
|
|
TQListBoxItem* item = m_fieldsBox->selectedItem();
|
|
|
|
if(item) {
|
|
|
|
FieldListBox* prev = static_cast<FieldListBox*>(item->prev()); // could be 0
|
|
|
|
if(prev) {
|
|
|
|
FieldListBox* newPrev = new FieldListBox(m_fieldsBox, prev->field(), item);
|
|
|
|
newPrev->setColored(prev->isColored());
|
|
|
|
delete prev;
|
|
|
|
m_fieldsBox->ensureCurrentVisible();
|
|
|
|
// since the current one doesn't get re-highlighted, need to highlighted doesn't get emitted
|
|
|
|
slotHighlightedChanged(m_fieldsBox->currentItem());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_reordered = true;
|
|
|
|
// don't call slotModified() since that creates a deep copy.
|
|
|
|
m_modified = true;
|
|
|
|
|
|
|
|
enableButtonOK(true);
|
|
|
|
enableButtonApply(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollectionFieldsDialog::slotMoveDown() {
|
|
|
|
FieldListBox* item = dynamic_cast<FieldListBox*>(m_fieldsBox->selectedItem());
|
|
|
|
if(item) {
|
|
|
|
TQListBoxItem* next = item->next(); // could be 0
|
|
|
|
if(next) {
|
|
|
|
FieldListBox* newItem = new FieldListBox(m_fieldsBox, item->field(), next);
|
|
|
|
newItem->setColored(item->isColored());
|
|
|
|
delete item;
|
|
|
|
m_fieldsBox->setSelected(newItem, true);
|
|
|
|
m_fieldsBox->ensureCurrentVisible();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_reordered = true;
|
|
|
|
// don't call slotModified() since that creates a deep copy.
|
|
|
|
m_modified = true;
|
|
|
|
|
|
|
|
enableButtonOK(true);
|
|
|
|
enableButtonApply(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::FieldListBox* CollectionFieldsDialog::findItem(const TQListBox* box_, Data::FieldPtr field_) {
|
|
|
|
// myDebug() << "CollectionFieldsDialog::findItem()" << endl;
|
|
|
|
for(TQListBoxItem* item = box_->firstItem(); item; item = item->next()) {
|
|
|
|
FieldListBox* textItem = static_cast<FieldListBox*>(item);
|
|
|
|
if(textItem->field() == field_) {
|
|
|
|
return textItem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CollectionFieldsDialog::slotShowExtendedProperties() {
|
|
|
|
if(!m_currentField) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the default value is included in properties, but it has a
|
|
|
|
// separate edit box
|
|
|
|
TQString dv = m_currentField->defaultValue();
|
|
|
|
StringMap props = m_currentField->propertyList();
|
|
|
|
props.remove(TQString::fromLatin1("default"));
|
|
|
|
|
|
|
|
StringMapDialog dlg(props, this, "ExtendedPropertiesDialog", true);
|
|
|
|
dlg.setCaption(i18n("Extended Field Properties"));
|
|
|
|
dlg.setLabels(i18n("Property"), i18n("Value"));
|
|
|
|
if(dlg.exec() == TQDialog::Accepted) {
|
|
|
|
props = dlg.stringMap();
|
|
|
|
if(!dv.isEmpty()) {
|
|
|
|
props.insert(TQString::fromLatin1("default"), dv);
|
|
|
|
}
|
|
|
|
m_currentField->setPropertyList(props);
|
|
|
|
slotModified();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CollectionFieldsDialog::checkValues() {
|
|
|
|
if(!m_currentField) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQString title = m_currentField->title();
|
|
|
|
// find total number of boxes with this title in case multiple new ones with same title were added
|
|
|
|
int titleCount = 0;
|
|
|
|
for(uint i = 0; i < m_fieldsBox->count(); ++i) {
|
|
|
|
if(m_fieldsBox->item(i)->text() == title) {
|
|
|
|
++titleCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if((m_coll->fieldByTitle(title) && m_coll->fieldNameByTitle(title) != m_currentField->name()) ||
|
|
|
|
titleCount > 1) {
|
|
|
|
// already have a field with this title
|
|
|
|
KMessageBox::sorry(this, i18n("A field with this title already exists. Please enter a different title."));
|
|
|
|
m_titleEdit->selectAll();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const TQString category = m_currentField->category();
|
|
|
|
if(category.isEmpty()) {
|
|
|
|
KMessageBox::sorry(this, i18n("<qt>The category may not be empty. Please enter a category.</qt>"));
|
|
|
|
m_catCombo->lineEdit()->selectAll();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Data::FieldVec fields = m_coll->fieldsByCategory(category);
|
|
|
|
if(!fields.isEmpty() && fields.begin()->isSingleCategory() && fields.begin()->name() != m_currentField->name()) {
|
|
|
|
// can't have this category, cause it conflicts with a single-category field
|
|
|
|
KMessageBox::sorry(this, i18n("<qt>A field may not be in the same category as a <em>Paragraph</em>, "
|
|
|
|
"<em>Table</em> or <em>Image</em> field. Please enter a different category.</qt>"));
|
|
|
|
m_catCombo->lineEdit()->selectAll();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the combobox is disabled for single-category fields
|
|
|
|
if(!m_catCombo->isEnabled() && m_coll->fieldByTitle(title) && m_coll->fieldNameByTitle(title) != m_currentField->name()) {
|
|
|
|
KMessageBox::sorry(this, i18n("A field's title may not be the same as an existing category. "
|
|
|
|
"Please enter a different title."));
|
|
|
|
m_titleEdit->selectAll();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for rating values outside bounds
|
|
|
|
if(m_currentField->type() == Data::Field::Rating) {
|
|
|
|
bool ok; // ok to ignore this here
|
|
|
|
int low = Tellico::toUInt(m_currentField->property(TQString::fromLatin1("minimum")), &ok);
|
|
|
|
int high = Tellico::toUInt(m_currentField->property(TQString::fromLatin1("maximum")), &ok);
|
|
|
|
while(low < 1 || low > 9 || high < 1 || high > 10 || low >= high) {
|
|
|
|
KMessageBox::sorry(this, i18n("The range for a rating field must be between 1 and 10, "
|
|
|
|
"and the lower bound must be less than the higher bound. "
|
|
|
|
"Please enter different low and high properties."));
|
|
|
|
if(slotShowExtendedProperties()) {
|
|
|
|
low = Tellico::toUInt(m_currentField->property(TQString::fromLatin1("minimum")), &ok);
|
|
|
|
high = Tellico::toUInt(m_currentField->property(TQString::fromLatin1("maximum")), &ok);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if(m_currentField->type() == Data::Field::Table) {
|
|
|
|
bool ok; // ok to ignore this here
|
|
|
|
int ncols = Tellico::toUInt(m_currentField->property(TQString::fromLatin1("columns")), &ok);
|
|
|
|
// also enforced in GUI::TableFieldWidget
|
|
|
|
if(ncols > 10) {
|
|
|
|
KMessageBox::sorry(this, i18n("Tables are limited to a maximum of ten columns."));
|
|
|
|
m_currentField->setProperty(TQString::fromLatin1("columns"), TQString::fromLatin1("10"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// only certain type changes are allowed
|
|
|
|
TQStringList CollectionFieldsDialog::newTypesAllowed(int type_ /*=0*/) {
|
|
|
|
// Undef means return all
|
|
|
|
if(type_ == Data::Field::Undef) {
|
|
|
|
return Data::Field::typeTitles();
|
|
|
|
}
|
|
|
|
|
|
|
|
const Data::Field::FieldMap& fieldMap = Data::Field::typeMap();
|
|
|
|
|
|
|
|
TQStringList newTypes;
|
|
|
|
switch(type_) {
|
|
|
|
case Data::Field::Line: // might not work if converted to a number or URL, but ok
|
|
|
|
case Data::Field::Number:
|
|
|
|
case Data::Field::URL:
|
|
|
|
newTypes += fieldMap[Data::Field::Line];
|
|
|
|
newTypes += fieldMap[Data::Field::Para];
|
|
|
|
newTypes += fieldMap[Data::Field::Number];
|
|
|
|
newTypes += fieldMap[Data::Field::URL];
|
|
|
|
newTypes += fieldMap[Data::Field::Table];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::Date:
|
|
|
|
newTypes += fieldMap[Data::Field::Line];
|
|
|
|
newTypes += fieldMap[Data::Field::Date];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::Bool: // doesn't really make sense, but can't hurt
|
|
|
|
newTypes += fieldMap[Data::Field::Line];
|
|
|
|
newTypes += fieldMap[Data::Field::Para];
|
|
|
|
newTypes += fieldMap[Data::Field::Bool];
|
|
|
|
newTypes += fieldMap[Data::Field::Number];
|
|
|
|
newTypes += fieldMap[Data::Field::URL];
|
|
|
|
newTypes += fieldMap[Data::Field::Table];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::Choice:
|
|
|
|
newTypes += fieldMap[Data::Field::Line];
|
|
|
|
newTypes += fieldMap[Data::Field::Para];
|
|
|
|
newTypes += fieldMap[Data::Field::Choice];
|
|
|
|
newTypes += fieldMap[Data::Field::Number];
|
|
|
|
newTypes += fieldMap[Data::Field::URL];
|
|
|
|
newTypes += fieldMap[Data::Field::Table];
|
|
|
|
newTypes += fieldMap[Data::Field::Rating];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::Table: // not really a good idea since the "::" will be exposed, but allow it
|
|
|
|
case Data::Field::Table2:
|
|
|
|
newTypes += fieldMap[Data::Field::Line];
|
|
|
|
newTypes += fieldMap[Data::Field::Number];
|
|
|
|
newTypes += fieldMap[Data::Field::Table];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::Para:
|
|
|
|
newTypes += fieldMap[Data::Field::Line];
|
|
|
|
newTypes += fieldMap[Data::Field::Para];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Data::Field::Rating:
|
|
|
|
newTypes += fieldMap[Data::Field::Choice];
|
|
|
|
newTypes += fieldMap[Data::Field::Rating];
|
|
|
|
break;
|
|
|
|
|
|
|
|
// these can never be changed
|
|
|
|
case Data::Field::Image:
|
|
|
|
case Data::Field::Dependent:
|
|
|
|
newTypes = fieldMap[static_cast<Data::Field::Type>(type_)];
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
myDebug() << "CollectionFieldsDialog::newTypesAllowed() - no match for " << type_ << endl;
|
|
|
|
newTypes = Data::Field::typeTitles();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return newTypes;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "collectionfieldsdialog.moc"
|