|
|
|
/***************************************************************************
|
|
|
|
copyright : (C) 2001-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 "entryeditdialog.h"
|
|
|
|
#include "gui/tabcontrol.h"
|
|
|
|
#include "collection.h"
|
|
|
|
#include "controller.h"
|
|
|
|
#include "field.h"
|
|
|
|
#include "entry.h"
|
|
|
|
#include "tellico_utils.h"
|
|
|
|
#include "tellico_kernel.h"
|
|
|
|
#include "tellico_debug.h"
|
|
|
|
#include "latin1literal.h"
|
|
|
|
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <tdeaccelmanager.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <tdeversion.h>
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
#include <tdeaccel.h>
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqstringlist.h>
|
|
|
|
#include <tqpushbutton.h>
|
|
|
|
#include <tqvaluevector.h>
|
|
|
|
#include <tqvbox.h>
|
|
|
|
#include <tqobjectlist.h>
|
|
|
|
#include <tqtabbar.h>
|
|
|
|
#include <tqstyle.h>
|
|
|
|
#include <tqapplication.h>
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// must be an even number
|
|
|
|
static const int NCOLS = 2; // number of columns of GUI::FieldWidgets
|
|
|
|
}
|
|
|
|
|
|
|
|
using Tellico::EntryEditDialog;
|
|
|
|
|
|
|
|
EntryEditDialog::EntryEditDialog(TQWidget* parent_, const char* name_)
|
|
|
|
: KDialogBase(parent_, name_, false, i18n("Edit Entry"), Help|User1|User2|User3|Apply|Close, User1, false,
|
|
|
|
KGuiItem(i18n("&New Entry"))),
|
|
|
|
m_currColl(0),
|
|
|
|
m_tabs(new GUI::TabControl(this)),
|
|
|
|
m_modified(false),
|
|
|
|
m_isOrphan(false),
|
|
|
|
m_isWorking(false),
|
|
|
|
m_needReset(false) {
|
|
|
|
setMainWidget(m_tabs);
|
|
|
|
|
|
|
|
m_prevBtn = User3;
|
|
|
|
m_nextBtn = User2;
|
|
|
|
m_newBtn = User1;
|
|
|
|
m_saveBtn = Apply;
|
|
|
|
KGuiItem save = KStdGuiItem::save();
|
|
|
|
save.setText(i18n("Sa&ve Entry"));
|
|
|
|
setButtonGuiItem(m_saveBtn, save);
|
|
|
|
enableButton(m_saveBtn, false);
|
|
|
|
|
|
|
|
connect(this, TQ_SIGNAL(applyClicked()), TQ_SLOT(slotHandleSave()));
|
|
|
|
connect(this, TQ_SIGNAL(user1Clicked()), TQ_SLOT(slotHandleNew()));
|
|
|
|
connect(this, TQ_SIGNAL(user2Clicked()), TQ_SLOT(slotGoNextEntry()));
|
|
|
|
connect(this, TQ_SIGNAL(user3Clicked()), TQ_SLOT(slotGoPrevEntry()));
|
|
|
|
|
|
|
|
KGuiItem prev;
|
|
|
|
prev.setIconName(TQString::fromLatin1(TQApplication::reverseLayout() ? "forward" : "back"));
|
|
|
|
prev.setToolTip(i18n("Go to the previous entry in the collection"));
|
|
|
|
prev.setWhatsThis(prev.toolTip());
|
|
|
|
|
|
|
|
KGuiItem next;
|
|
|
|
next.setIconName(TQString::fromLatin1(TQApplication::reverseLayout() ? "back" : "forward"));
|
|
|
|
next.setToolTip(i18n("Go to the next entry in the collection"));
|
|
|
|
next.setWhatsThis(next.toolTip());
|
|
|
|
|
|
|
|
setButtonGuiItem(m_nextBtn, next);
|
|
|
|
setButtonGuiItem(m_prevBtn, prev);
|
|
|
|
|
|
|
|
TDEAccel* accel = new TDEAccel(this);
|
|
|
|
accel->insert(TQString::fromLatin1("Go Prev"), TQString(), prev.toolTip(), TQt::Key_PageUp,
|
|
|
|
Controller::self(), TQ_SLOT(slotGoPrevEntry()));
|
|
|
|
accel->insert(TQString::fromLatin1("Go Next"), TQString(), next.toolTip(), TQt::Key_PageDown,
|
|
|
|
Controller::self(), TQ_SLOT(slotGoNextEntry()));
|
|
|
|
|
|
|
|
setHelp(TQString::fromLatin1("entry-editor"));
|
|
|
|
|
|
|
|
resize(configDialogSize(TQString::fromLatin1("Edit Dialog Options")));
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::slotClose() {
|
|
|
|
// check to see if an entry should be saved before hiding
|
|
|
|
// block signals so the entry view and selection isn't cleared
|
|
|
|
if(queryModified()) {
|
|
|
|
hide();
|
|
|
|
// blockSignals(true);
|
|
|
|
// slotHandleNew();
|
|
|
|
// blockSignals(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::slotReset() {
|
|
|
|
// myDebug() << "EntryEditDialog::slotReset()" << endl;
|
|
|
|
if(m_isWorking) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
enableButton(m_saveBtn, false);
|
|
|
|
setButtonText(m_saveBtn, i18n("Sa&ve Entry"));
|
|
|
|
m_currColl = 0;
|
|
|
|
m_currEntries.clear();
|
|
|
|
|
|
|
|
m_modified = false;
|
|
|
|
|
|
|
|
m_tabs->clear(); // GUI::FieldWidgets get deleted here
|
|
|
|
m_widgetDict.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::setLayout(Data::CollPtr coll_) {
|
|
|
|
if(!coll_ || m_isWorking) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// myDebug() << "EntryEditDialog::setLayout()" << endl;
|
|
|
|
|
|
|
|
actionButton(m_newBtn)->setIconSet(UserIconSet(coll_->typeName()));
|
|
|
|
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
if(m_tabs->count() > 0) {
|
|
|
|
// myDebug() << "EntryEditDialog::setLayout() - resetting contents." << endl;
|
|
|
|
slotReset();
|
|
|
|
}
|
|
|
|
m_isWorking = true;
|
|
|
|
|
|
|
|
m_currColl = coll_;
|
|
|
|
|
|
|
|
int maxHeight = 0;
|
|
|
|
TQPtrList<TQWidget> gridList;
|
|
|
|
bool noChoices = true;
|
|
|
|
|
|
|
|
bool focusedFirst = false;
|
|
|
|
TQStringList catList = m_currColl->fieldCategories();
|
|
|
|
for(TQStringList::ConstIterator catIt = catList.begin(); catIt != catList.end(); ++catIt) {
|
|
|
|
Data::FieldVec fields = m_currColl->fieldsByCategory(*catIt);
|
|
|
|
if(fields.isEmpty()) { // sanity check
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if this layout model is changed, be sure to check slotUpdateField()
|
|
|
|
TQWidget* page = new TQWidget(m_tabs);
|
|
|
|
// (parent, margin, spacing)
|
|
|
|
TQVBoxLayout* boxLayout = new TQVBoxLayout(page, 0, 0);
|
|
|
|
|
|
|
|
TQWidget* grid = new TQWidget(page);
|
|
|
|
gridList.append(grid);
|
|
|
|
// (parent, nrows, ncols, margin, spacing)
|
|
|
|
// spacing gets a bit weird, if there are absolutely no Choice fields,
|
|
|
|
// then spacing should be 5, which is set later
|
|
|
|
TQGridLayout* layout = new TQGridLayout(grid, 0, NCOLS, 8, 2);
|
|
|
|
// keramik styles make big widget, cut down the spacing a bit
|
|
|
|
if(TQCString(style().name()).lower().find("keramik", 0, false) > -1) {
|
|
|
|
layout->setSpacing(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
boxLayout->addWidget(grid, 0);
|
|
|
|
// those with multiple, get a stretch
|
|
|
|
if(fields.count() > 1 || !fields[0]->isSingleCategory()) {
|
|
|
|
boxLayout->addStretch(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// keep track of which should expand
|
|
|
|
TQValueVector<bool> expands(NCOLS, false);
|
|
|
|
TQValueVector<int> maxWidth(NCOLS, 0);
|
|
|
|
|
|
|
|
Data::FieldVec::Iterator it = fields.begin(); // needed later
|
|
|
|
for(int count = 0; it != fields.end(); ++it) {
|
|
|
|
Data::FieldPtr field = it;
|
|
|
|
// ReadOnly and Dependent fields don't get widgets
|
|
|
|
if(field->type() == Data::Field::ReadOnly || field->type() == Data::Field::Dependent) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(field->type() == Data::Field::Choice) {
|
|
|
|
noChoices = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
GUI::FieldWidget* widget = GUI::FieldWidget::create(field, grid);
|
|
|
|
if(!widget) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
connect(widget, TQ_SIGNAL(modified()), TQ_SLOT(slotSetModified()));
|
|
|
|
if(!focusedFirst && widget->isFocusEnabled()) {
|
|
|
|
widget->setFocus();
|
|
|
|
focusedFirst = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int r = count/NCOLS;
|
|
|
|
int c = count%NCOLS;
|
|
|
|
layout->addWidget(widget, r, c);
|
|
|
|
layout->setRowStretch(r, 1);
|
|
|
|
|
|
|
|
m_widgetDict.insert(TQString::number(m_currColl->id()) + field->name(), widget);
|
|
|
|
|
|
|
|
maxWidth[count%NCOLS] = TQMAX(maxWidth[count%NCOLS], widget->labelWidth());
|
|
|
|
if(widget->expands()) {
|
|
|
|
expands[count%NCOLS] = true;
|
|
|
|
}
|
|
|
|
widget->updateGeometry();
|
|
|
|
if(!field->isSingleCategory()) {
|
|
|
|
maxHeight = TQMAX(maxHeight, widget->minimumSizeHint().height());
|
|
|
|
}
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now, the labels in a column should all be the same width
|
|
|
|
it = fields.begin();
|
|
|
|
for(int count = 0; it != fields.end(); ++it) {
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(TQString::number(m_currColl->id()) + it->name());
|
|
|
|
if(widget) {
|
|
|
|
widget->setLabelWidth(maxWidth[count%NCOLS]);
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// update stretch factors for columns with a line edit
|
|
|
|
for(int col = 0; col < NCOLS; ++col) {
|
|
|
|
if(expands[col]) {
|
|
|
|
layout->setColStretch(col, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tabs->addTab(page, *catIt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, go through and set all the field widgets to the same height
|
|
|
|
for(TQPtrListIterator<TQWidget> it(gridList); it.current(); ++it) {
|
|
|
|
TQGridLayout* l = static_cast<TQGridLayout*>(it.current()->layout());
|
|
|
|
if(noChoices) {
|
|
|
|
l->setSpacing(5);
|
|
|
|
}
|
|
|
|
for(int row = 0; row < l->numRows() && it.current()->childrenListObject().count() > 1; ++row) {
|
|
|
|
l->addRowSpacing(row, maxHeight);
|
|
|
|
}
|
|
|
|
// I don't want anything to be hidden, Keramik has a bug if I don't do this
|
|
|
|
it.current()->setMinimumHeight(it.current()->sizeHint().height());
|
|
|
|
// the parent of the grid is the page that got added to the tabs
|
|
|
|
it.current()->parentWidget()->layout()->invalidate();
|
|
|
|
it.current()->parentWidget()->setMinimumHeight(it.current()->parentWidget()->sizeHint().height());
|
|
|
|
}
|
|
|
|
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
// this doesn't seem to work
|
|
|
|
// setSizePolicy(TQSizePolicy::MinimumExpanding, TQSizePolicy::Minimum);
|
|
|
|
// so do this instead
|
|
|
|
layout()->invalidate(); // needed so the sizeHint() gets recalculated
|
|
|
|
m_tabs->setMinimumHeight(m_tabs->minimumSizeHint().height());
|
|
|
|
m_tabs->setMinimumWidth(m_tabs->sizeHint().width());
|
|
|
|
|
|
|
|
// update keyboard accels
|
|
|
|
// only want to manage tabBar()
|
|
|
|
TDEAcceleratorManager::manage(m_tabs->tabBar());
|
|
|
|
|
|
|
|
m_tabs->setCurrentPage(0);
|
|
|
|
|
|
|
|
m_isWorking = false;
|
|
|
|
slotHandleNew();
|
|
|
|
m_modified = false; // because the year is inserted
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::slotHandleNew() {
|
|
|
|
if(!m_currColl || !queryModified()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tabs->setCurrentPage(0);
|
|
|
|
m_tabs->setFocusToFirstChild();
|
|
|
|
clear();
|
|
|
|
m_isWorking = true; // clear() will get called again
|
|
|
|
Controller::self()->slotClearSelection();
|
|
|
|
m_isWorking = false;
|
|
|
|
|
|
|
|
enableButton(m_prevBtn, false);
|
|
|
|
enableButton(m_nextBtn, false);
|
|
|
|
|
|
|
|
Data::EntryPtr entry = new Data::Entry(m_currColl);
|
|
|
|
m_currEntries.append(entry);
|
|
|
|
m_isOrphan = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::slotHandleSave() {
|
|
|
|
if(!m_currColl || m_isWorking) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_isWorking = true;
|
|
|
|
|
|
|
|
if(m_currEntries.isEmpty()) {
|
|
|
|
myDebug() << "EntryEditDialog::slotHandleSave() - creating new entry" << endl;
|
|
|
|
m_currEntries.append(new Data::Entry(m_currColl));
|
|
|
|
m_isOrphan = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// add a message box if multiple items are selected
|
|
|
|
if(m_currEntries.count() > 1) {
|
|
|
|
TQStringList names;
|
|
|
|
for(Data::EntryVec::ConstIterator entry = m_currEntries.constBegin(); entry != m_currEntries.constEnd(); ++entry) {
|
|
|
|
names += entry->title();
|
|
|
|
}
|
|
|
|
TQString str(i18n("Do you really want to modify these entries?"));
|
|
|
|
TQString dontAsk = TQString::fromLatin1("SaveMultipleBooks"); // don't change 'books', invisible anyway
|
|
|
|
int ret = KMessageBox::questionYesNoList(this, str, names, i18n("Modify Multiple Entries"),
|
|
|
|
KStdGuiItem::yes(), KStdGuiItem::no(), dontAsk);
|
|
|
|
if(ret != KMessageBox::Yes) {
|
|
|
|
m_isWorking = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GUI::CursorSaver cs;
|
|
|
|
|
|
|
|
Data::EntryVec oldEntries;
|
|
|
|
Data::FieldVec fields = m_currColl->fields();
|
|
|
|
Data::FieldVec fieldsRequiringValues;
|
|
|
|
// boolean to keep track if any field gets changed
|
|
|
|
bool modified = false;
|
|
|
|
for(Data::EntryVecIt entry = m_currEntries.begin(); entry != m_currEntries.end(); ++entry) {
|
|
|
|
// if the entry is owned, then we're modifying an existing entry, keep a copy of the old one
|
|
|
|
if(entry->isOwned()) {
|
|
|
|
oldEntries.append(new Data::Entry(*entry));
|
|
|
|
}
|
|
|
|
for(Data::FieldVec::Iterator fIt = fields.begin(); fIt != fields.end(); ++fIt) {
|
|
|
|
TQString key = TQString::number(m_currColl->id()) + fIt->name();
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(key);
|
|
|
|
if(widget && widget->isEnabled()) {
|
|
|
|
TQString temp = widget->text();
|
|
|
|
// ok to set field empty string, just not all of them
|
|
|
|
if(modified == false && entry->field(fIt) != temp) {
|
|
|
|
modified = true;
|
|
|
|
}
|
|
|
|
entry->setField(fIt, temp);
|
|
|
|
if(temp.isEmpty()) {
|
|
|
|
TQString prop = fIt->property(TQString::fromLatin1("required")).lower();
|
|
|
|
if(prop == Latin1Literal("1") || prop == Latin1Literal("true")) {
|
|
|
|
fieldsRequiringValues.append(fIt.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!fieldsRequiringValues.isEmpty()) {
|
|
|
|
GUI::CursorSaver cs2(TQt::arrowCursor);
|
|
|
|
TQString str = i18n("A value is required for the following fields. Do you want to continue?");
|
|
|
|
TQStringList titles;
|
|
|
|
for(Data::FieldVecIt it = fieldsRequiringValues.begin(); it != fieldsRequiringValues.end(); ++it) {
|
|
|
|
titles << it->title();
|
|
|
|
}
|
|
|
|
TQString dontAsk = TQString::fromLatin1("SaveWithoutRequired");
|
|
|
|
int ret = KMessageBox::questionYesNoList(this, str, titles, i18n("Modify Entries"),
|
|
|
|
KStdGuiItem::yes(), KStdGuiItem::no(), dontAsk);
|
|
|
|
if(ret != KMessageBox::Yes) {
|
|
|
|
m_isWorking = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if something was not empty, signal a save
|
|
|
|
if(modified) {
|
|
|
|
m_isOrphan = false;
|
|
|
|
if(oldEntries.isEmpty()) {
|
|
|
|
Kernel::self()->addEntries(m_currEntries, false);
|
|
|
|
} else {
|
|
|
|
Kernel::self()->modifyEntries(oldEntries, m_currEntries);
|
|
|
|
}
|
|
|
|
if(!m_currEntries.isEmpty() && !m_currEntries[0]->title().isEmpty()) {
|
|
|
|
setCaption(i18n("Edit Entry") + TQString::fromLatin1(" - ") + m_currEntries[0]->title());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_modified = false;
|
|
|
|
m_isWorking = false;
|
|
|
|
enableButton(m_saveBtn, false);
|
|
|
|
// slotHandleNew();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::clear() {
|
|
|
|
if(m_isWorking) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// myDebug() << "EntryEditDialog::clear()" << endl;
|
|
|
|
|
|
|
|
m_isWorking = true;
|
|
|
|
// clear the widgets
|
|
|
|
for(TQDictIterator<GUI::FieldWidget> it(m_widgetDict); it.current(); ++it) {
|
|
|
|
it.current()->setEnabled(true);
|
|
|
|
it.current()->clear();
|
|
|
|
it.current()->insertDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
setCaption(i18n("Edit Entry"));
|
|
|
|
|
|
|
|
if(m_isOrphan) {
|
|
|
|
if(m_currEntries.count() > 1) {
|
|
|
|
kdWarning() << "EntryEditDialog::clear() - is an orphan, but more than one" << endl;
|
|
|
|
}
|
|
|
|
m_isOrphan = false;
|
|
|
|
}
|
|
|
|
m_currEntries.clear();
|
|
|
|
|
|
|
|
setButtonText(m_saveBtn, i18n("Sa&ve Entry"));
|
|
|
|
enableButton(m_saveBtn, false);
|
|
|
|
|
|
|
|
m_modified = false;
|
|
|
|
m_isWorking = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::setContents(Data::EntryVec entries_) {
|
|
|
|
// this slot might get called if we try to save multiple items, so just return
|
|
|
|
if(m_isWorking) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(entries_.isEmpty()) {
|
|
|
|
// myDebug() << "EntryEditDialog::setContents() - empty list" << endl;
|
|
|
|
if(queryModified()) {
|
|
|
|
blockSignals(true);
|
|
|
|
slotHandleNew();
|
|
|
|
blockSignals(false);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// myDebug() << "EntryEditDialog::setContents() - " << entries_.count() << " entries" << endl;
|
|
|
|
|
|
|
|
// if some entries get selected in one view, then in another, don't reset
|
|
|
|
if(!m_needReset && entries_ == m_currEntries) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_needReset = false;
|
|
|
|
|
|
|
|
// first set contents to first item
|
|
|
|
setContents(entries_.front());
|
|
|
|
// something weird...if list count can actually be 1 before the setContents call
|
|
|
|
// and 0 after it. Why is that? It's const!
|
|
|
|
if(entries_.count() < 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// multiple entries, so don't set caption
|
|
|
|
setCaption(i18n("Edit Entries"));
|
|
|
|
|
|
|
|
m_currEntries = entries_;
|
|
|
|
m_isWorking = true;
|
|
|
|
blockSignals(true);
|
|
|
|
|
|
|
|
Data::EntryVec::ConstIterator entry;
|
|
|
|
Data::FieldVec fields = m_currColl->fields();
|
|
|
|
for(Data::FieldVec::Iterator fIt = fields.begin(); fIt != fields.end(); ++fIt) {
|
|
|
|
TQString key = TQString::number(m_currColl->id()) + fIt->name();
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(key);
|
|
|
|
if(!widget) { // probably read-only
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
widget->editMultiple(true);
|
|
|
|
|
|
|
|
TQString value = entries_[0]->field(fIt);
|
|
|
|
entry = entries_.constBegin();
|
|
|
|
for(++entry; entry != entries_.constEnd(); ++entry) { // skip checking the first one
|
|
|
|
if(entry->field(fIt) != value) {
|
|
|
|
widget->setEnabled(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // end field loop
|
|
|
|
|
|
|
|
blockSignals(false);
|
|
|
|
m_isWorking = false;
|
|
|
|
|
|
|
|
// can't go to next entry if multiple are selected
|
|
|
|
enableButton(m_prevBtn, false);
|
|
|
|
enableButton(m_nextBtn, false);
|
|
|
|
setButtonText(m_saveBtn, i18n("Sa&ve Entries"));
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::setContents(Data::EntryPtr entry_) {
|
|
|
|
bool ok = queryModified();
|
|
|
|
if(!ok || m_isWorking) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!entry_) {
|
|
|
|
myDebug() << "EntryEditDialog::setContents() - null entry pointer" << endl;
|
|
|
|
slotHandleNew();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// myDebug() << "EntryEditDialog::setContents() - " << entry_->title() << endl;
|
|
|
|
blockSignals(true);
|
|
|
|
clear();
|
|
|
|
blockSignals(false);
|
|
|
|
|
|
|
|
m_isWorking = true;
|
|
|
|
m_currEntries.append(entry_);
|
|
|
|
|
|
|
|
if(!entry_->title().isEmpty()) {
|
|
|
|
setCaption(i18n("Edit Entry") + TQString::fromLatin1(" - ") + entry_->title());
|
|
|
|
}
|
|
|
|
|
|
|
|
if(m_currColl != entry_->collection()) {
|
|
|
|
myDebug() << "EntryEditDialog::setContents() - collections don't match" << endl;
|
|
|
|
m_currColl = entry_->collection();
|
|
|
|
}
|
|
|
|
|
|
|
|
// m_tabs->showTab(0);
|
|
|
|
|
|
|
|
slotSetModified(false);
|
|
|
|
|
|
|
|
Data::FieldVec fields = m_currColl->fields();
|
|
|
|
for(Data::FieldVec::Iterator field = fields.begin(); field != fields.end(); ++field) {
|
|
|
|
TQString key = TQString::number(m_currColl->id()) + field->name();
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(key);
|
|
|
|
if(!widget) { // is probably read-only
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
widget->setText(entry_->field(field));
|
|
|
|
widget->setEnabled(true);
|
|
|
|
widget->editMultiple(false);
|
|
|
|
} // end field loop
|
|
|
|
|
|
|
|
enableButton(m_prevBtn, true);
|
|
|
|
enableButton(m_nextBtn, true);
|
|
|
|
if(entry_->isOwned()) {
|
|
|
|
setButtonText(m_saveBtn, i18n("Sa&ve Entry"));
|
|
|
|
enableButton(m_saveBtn, m_modified);
|
|
|
|
} else {
|
|
|
|
slotSetModified(true);
|
|
|
|
}
|
|
|
|
m_isWorking = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::removeField(Data::CollPtr, Data::FieldPtr field_) {
|
|
|
|
if(!field_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// myDebug() << "EntryEditDialog::removeField - name = " << field_->name() << endl;
|
|
|
|
TQString key = TQString::number(m_currColl->id()) + field_->name();
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(key);
|
|
|
|
if(widget) {
|
|
|
|
m_widgetDict.remove(key);
|
|
|
|
// if this is the last field in the category, need to remove the tab page
|
|
|
|
// this function is called after the field has been removed from the collection,
|
|
|
|
// so the category should be gone from the category list
|
|
|
|
if(m_currColl->fieldCategories().findIndex(field_->category()) == -1) {
|
|
|
|
// myDebug() << "last field in the category" << endl;
|
|
|
|
// fragile, widget's parent is the grid, whose parent is the tab page
|
|
|
|
TQWidget* w = widget->parentWidget()->parentWidget();
|
|
|
|
m_tabs->removePage(w);
|
|
|
|
delete w; // automatically deletes child widget
|
|
|
|
} else {
|
|
|
|
// much of this replicates code in setLayout()
|
|
|
|
TQGridLayout* layout = static_cast<TQGridLayout*>(widget->parentWidget()->layout());
|
|
|
|
delete widget; // automatically removes from layout
|
|
|
|
|
|
|
|
TQValueVector<bool> expands(NCOLS, false);
|
|
|
|
TQValueVector<int> maxWidth(NCOLS, 0);
|
|
|
|
|
|
|
|
Data::FieldVec vec = m_currColl->fieldsByCategory(field_->category());
|
|
|
|
Data::FieldVec::Iterator it = vec.begin();
|
|
|
|
for(int count = 0; it != vec.end(); ++it) {
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(TQString::number(m_currColl->id()) + it->name());
|
|
|
|
if(widget) {
|
|
|
|
layout->remove(widget);
|
|
|
|
layout->addWidget(widget, count/NCOLS, count%NCOLS);
|
|
|
|
|
|
|
|
maxWidth[count%NCOLS] = TQMAX(maxWidth[count%NCOLS], widget->labelWidth());
|
|
|
|
if(widget->expands()) {
|
|
|
|
expands[count%NCOLS] = true;
|
|
|
|
}
|
|
|
|
widget->updateGeometry();
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now, the labels in a column should all be the same width
|
|
|
|
it = vec.begin();
|
|
|
|
for(int count = 0; it != vec.end(); ++it) {
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(TQString::number(m_currColl->id()) + it->name());
|
|
|
|
if(widget) {
|
|
|
|
widget->setLabelWidth(maxWidth[count%NCOLS]);
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// update stretch factors for columns with a line edit
|
|
|
|
for(int col = 0; col < NCOLS; ++col) {
|
|
|
|
if(expands[col]) {
|
|
|
|
layout->setColStretch(col, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::updateCompletions(Data::EntryPtr entry_) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
if(m_currColl != entry_->collection()) {
|
|
|
|
myDebug() << "EntryEditDialog::updateCompletions - inconsistent collection pointers!" << endl;
|
|
|
|
// m_currColl = entry_->collection();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Data::FieldVec fields = m_currColl->fields();
|
|
|
|
for(Data::FieldVec::Iterator it = fields.begin(); it != fields.end(); ++it) {
|
|
|
|
if(it->type() != Data::Field::Line
|
|
|
|
|| !(it->flags() & Data::Field::AllowCompletion)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString key = TQString::number(m_currColl->id()) + it->name();
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict.find(key);
|
|
|
|
if(!widget) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(it->flags() & Data::Field::AllowMultiple) {
|
|
|
|
TQStringList items = entry_->fields(it, false);
|
|
|
|
for(TQStringList::ConstIterator it = items.begin(); it != items.end(); ++it) {
|
|
|
|
widget->addCompletionObjectItem(*it);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
widget->addCompletionObjectItem(entry_->field(it->name()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::slotSetModified(bool mod_/*=true*/) {
|
|
|
|
m_modified = mod_;
|
|
|
|
enableButton(m_saveBtn, mod_);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool EntryEditDialog::queryModified() {
|
|
|
|
// myDebug() << "EntryEditDialog::queryModified() - modified is " << (m_modified?"true":"false") << endl;
|
|
|
|
bool ok = true;
|
|
|
|
// assume that if the dialog is hidden, we shouldn't ask the user to modify changes
|
|
|
|
if(!isShown()) {
|
|
|
|
m_modified = false;
|
|
|
|
}
|
|
|
|
if(m_modified) {
|
|
|
|
TQString str(i18n("The current entry has been modified.\n"
|
|
|
|
"Do you want to enter the changes?"));
|
|
|
|
KGuiItem item = KStdGuiItem::save();
|
|
|
|
item.setText(i18n("Save Entry"));
|
|
|
|
int want_save = KMessageBox::warningYesNoCancel(this, str, i18n("Unsaved Changes"),
|
|
|
|
item, KStdGuiItem::discard());
|
|
|
|
switch(want_save) {
|
|
|
|
case KMessageBox::Yes:
|
|
|
|
slotHandleSave();
|
|
|
|
ok = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KMessageBox::No:
|
|
|
|
m_modified = false;
|
|
|
|
ok = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KMessageBox::Cancel:
|
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
// modified fields will always have the same name
|
|
|
|
void EntryEditDialog::modifyField(Data::CollPtr coll_, Data::FieldPtr oldField_, Data::FieldPtr newField_) {
|
|
|
|
// myDebug() << "EntryEditDialog::slotUpdateField() - " << newField_->name() << endl;
|
|
|
|
|
|
|
|
if(coll_ != m_currColl) {
|
|
|
|
myDebug() << "EntryEditDialog::slotUpdateField() - wrong collection pointer!" << endl;
|
|
|
|
m_currColl = coll_;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the field type changed, go ahead and redo the whole layout
|
|
|
|
// also if the category changed for a non-single field, since a new tab must be created
|
|
|
|
if(oldField_->type() != newField_->type()
|
|
|
|
|| (oldField_->category() != newField_->category() && !newField_->isSingleCategory())) {
|
|
|
|
bool modified = m_modified;
|
|
|
|
setLayout(coll_);
|
|
|
|
setContents(m_currEntries);
|
|
|
|
m_modified = modified;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString key = TQString::number(coll_->id()) + oldField_->name();
|
|
|
|
GUI::FieldWidget* widget = m_widgetDict[key];
|
|
|
|
if(widget) {
|
|
|
|
widget->updateField(oldField_, newField_);
|
|
|
|
// need to update label widths
|
|
|
|
if(newField_->title() != oldField_->title()) {
|
|
|
|
int maxWidth = 0;
|
|
|
|
TQObjectList* childList = widget->parentWidget()->queryList("Tellico::GUI::FieldWidget", 0, false, false);
|
|
|
|
TQObjectListIt it(*childList);
|
|
|
|
for(it.toFirst(); it.current(); ++it) {
|
|
|
|
maxWidth = TQMAX(maxWidth, static_cast<GUI::FieldWidget*>(it.current())->labelWidth());
|
|
|
|
}
|
|
|
|
for(it.toFirst(); it.current(); ++it) {
|
|
|
|
static_cast<GUI::FieldWidget*>(it.current())->setLabelWidth(maxWidth);
|
|
|
|
}
|
|
|
|
delete childList;
|
|
|
|
}
|
|
|
|
// this is very fragile!
|
|
|
|
// field widgets's parent is the grid, whose parent is the tab page
|
|
|
|
// this is for singleCategory fields
|
|
|
|
if(newField_->category() != oldField_->category()) {
|
|
|
|
m_tabs->setTabLabel(widget->parentWidget()->parentWidget(), newField_->category());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::addEntries(Data::EntryVec entries_) {
|
|
|
|
for(Data::EntryVecIt entry = entries_.begin(); entry != entries_.end(); ++entry) {
|
|
|
|
updateCompletions(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::modifyEntries(Data::EntryVec entries_) {
|
|
|
|
bool updateContents = false;
|
|
|
|
for(Data::EntryVecIt entry = entries_.begin(); entry != entries_.end(); ++entry) {
|
|
|
|
updateCompletions(entry);
|
|
|
|
if(!updateContents && m_currEntries.contains(entry)) {
|
|
|
|
updateContents = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(updateContents) {
|
|
|
|
m_needReset = true;
|
|
|
|
setContents(m_currEntries);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::slotGoPrevEntry() {
|
|
|
|
queryModified();
|
|
|
|
Controller::self()->slotGoPrevEntry();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EntryEditDialog::slotGoNextEntry() {
|
|
|
|
queryModified();
|
|
|
|
Controller::self()->slotGoNextEntry();
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "entryeditdialog.moc"
|