|
|
|
/***************************************************************************
|
|
|
|
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 "controller.h"
|
|
|
|
#include "mainwindow.h"
|
|
|
|
#include "groupview.h"
|
|
|
|
#include "detailedlistview.h"
|
|
|
|
#include "entryeditdialog.h"
|
|
|
|
#include "viewstack.h"
|
|
|
|
#include "entryview.h"
|
|
|
|
#include "entryiconview.h"
|
|
|
|
#include "entry.h"
|
|
|
|
#include "field.h"
|
|
|
|
#include "filter.h"
|
|
|
|
#include "filterdialog.h"
|
|
|
|
#include "tellico_kernel.h"
|
|
|
|
#include "latin1literal.h"
|
|
|
|
#include "collection.h"
|
|
|
|
#include "document.h"
|
|
|
|
#include "borrower.h"
|
|
|
|
#include "filterview.h"
|
|
|
|
#include "loanview.h"
|
|
|
|
#include "entryitem.h"
|
|
|
|
#include "gui/tabcontrol.h"
|
|
|
|
#include "calendarhandler.h"
|
|
|
|
#include "tellico_debug.h"
|
|
|
|
#include "groupiterator.h"
|
|
|
|
#include "tellico_utils.h"
|
|
|
|
#include "entryupdater.h"
|
|
|
|
#include "entrymerger.h"
|
|
|
|
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <tdeaction.h>
|
|
|
|
#include <tdetoolbarbutton.h>
|
|
|
|
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
|
|
|
|
using Tellico::Controller;
|
|
|
|
|
|
|
|
Controller* Controller::s_self = 0;
|
|
|
|
|
|
|
|
Controller::Controller(MainWindow* parent_, const char* name_)
|
|
|
|
: TQObject(parent_, name_), m_mainWindow(parent_), m_working (false), m_widgetWithSelection(0) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::addObserver(Observer* obs) {
|
|
|
|
m_observers.push_back(obs);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::removeObserver(Observer* obs) {
|
|
|
|
m_observers.remove(obs);
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::GroupIterator Controller::groupIterator() const {
|
|
|
|
return GroupIterator(m_mainWindow->m_groupView);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Controller::groupBy() const {
|
|
|
|
return m_mainWindow->m_groupView->groupBy();
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList Controller::expandedGroupBy() const {
|
|
|
|
TQStringList g = groupBy();
|
|
|
|
// special case for pseudo-group
|
|
|
|
if(g[0] == Data::Collection::s_peopleGroupName) {
|
|
|
|
g.clear();
|
|
|
|
Data::FieldVec fields = Data::Document::self()->collection()->peopleFields();
|
|
|
|
for(Data::FieldVec::Iterator it = fields.begin(); it != fields.end(); ++it) {
|
|
|
|
g << it->name();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// special case for no groups
|
|
|
|
if(g[0].isEmpty()) {
|
|
|
|
g.clear();
|
|
|
|
}
|
|
|
|
return g;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList Controller::sortTitles() const {
|
|
|
|
TQStringList list;
|
|
|
|
list << m_mainWindow->m_detailedView->sortColumnTitle1();
|
|
|
|
list << m_mainWindow->m_detailedView->sortColumnTitle2();
|
|
|
|
list << m_mainWindow->m_detailedView->sortColumnTitle3();
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStringList Controller::visibleColumns() const {
|
|
|
|
return m_mainWindow->m_detailedView->visibleColumns();
|
|
|
|
}
|
|
|
|
|
|
|
|
Tellico::Data::EntryVec Controller::visibleEntries() {
|
|
|
|
return m_mainWindow->m_detailedView->visibleEntries();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotCollectionAdded(Data::CollPtr coll_) {
|
|
|
|
// myDebug() << "Controller::slotCollectionAdded()" << endl;
|
|
|
|
// at start-up, this might get called too early, so check and bail
|
|
|
|
if(!m_mainWindow->m_groupView) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// do this first because the group view will need it later
|
|
|
|
m_mainWindow->readCollectionOptions(coll_);
|
|
|
|
m_mainWindow->slotUpdateToolbarIcons();
|
|
|
|
m_mainWindow->updateEntrySources(); // has to be called before all the addCollection()
|
|
|
|
// calls in the widgets since they may want menu updates
|
|
|
|
|
|
|
|
// blockAllSignals(true);
|
|
|
|
m_mainWindow->m_detailedView->addCollection(coll_);
|
|
|
|
m_mainWindow->m_groupView->addCollection(coll_);
|
|
|
|
m_mainWindow->m_editDialog->setLayout(coll_);
|
|
|
|
if(!coll_->filters().isEmpty()) {
|
|
|
|
m_mainWindow->addFilterView();
|
|
|
|
m_mainWindow->m_filterView->addCollection(coll_);
|
|
|
|
m_mainWindow->m_viewTabs->setTabBarHidden(false);
|
|
|
|
}
|
|
|
|
if(!coll_->borrowers().isEmpty()) {
|
|
|
|
m_mainWindow->addLoanView();
|
|
|
|
m_mainWindow->m_loanView->addCollection(coll_);
|
|
|
|
m_mainWindow->m_viewTabs->setTabBarHidden(false);
|
|
|
|
}
|
|
|
|
// blockAllSignals(false);
|
|
|
|
|
|
|
|
m_mainWindow->slotStatusMsg(i18n("Ready."));
|
|
|
|
|
|
|
|
m_selectedEntries.clear();
|
|
|
|
m_mainWindow->slotEntryCount();
|
|
|
|
|
|
|
|
emit collectionAdded(coll_->type());
|
|
|
|
|
|
|
|
updateActions();
|
|
|
|
|
|
|
|
connect(coll_, TQT_SIGNAL(signalGroupsModified(Tellico::Data::CollPtr, PtrVector<Tellico::Data::EntryGroup>)),
|
|
|
|
m_mainWindow->m_groupView, TQT_SLOT(slotModifyGroups(Tellico::Data::CollPtr, PtrVector<Tellico::Data::EntryGroup>)));
|
|
|
|
|
|
|
|
connect(coll_, TQT_SIGNAL(signalRefreshField(Tellico::Data::FieldPtr)),
|
|
|
|
this, TQT_SLOT(slotRefreshField(Tellico::Data::FieldPtr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotCollectionModified(Data::CollPtr coll_) {
|
|
|
|
// easiest thing is to signal collection deleted, then added?
|
|
|
|
// FIXME: Signals for delete collection and then added are yucky
|
|
|
|
slotCollectionDeleted(coll_);
|
|
|
|
slotCollectionAdded(coll_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotCollectionDeleted(Data::CollPtr coll_) {
|
|
|
|
// myDebug() << "Controller::slotCollectionDeleted()" << endl;
|
|
|
|
|
|
|
|
blockAllSignals(true);
|
|
|
|
m_mainWindow->saveCollectionOptions(coll_);
|
|
|
|
m_mainWindow->m_groupView->removeCollection(coll_);
|
|
|
|
if(m_mainWindow->m_filterView) {
|
|
|
|
m_mainWindow->m_filterView->clear();
|
|
|
|
}
|
|
|
|
if(m_mainWindow->m_loanView) {
|
|
|
|
m_mainWindow->m_loanView->clear();
|
|
|
|
}
|
|
|
|
m_mainWindow->m_detailedView->removeCollection(coll_);
|
|
|
|
m_mainWindow->m_viewStack->clear();
|
|
|
|
blockAllSignals(false);
|
|
|
|
|
|
|
|
// disconnect all signals from the collection
|
|
|
|
// this is needed because the Collection::appendCollection() and mergeCollection()
|
|
|
|
// functions signal collection deleted then added for the same collection
|
|
|
|
coll_->disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::addedEntries(Data::EntryVec entries_) {
|
|
|
|
blockAllSignals(true);
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->addEntries(entries_);
|
|
|
|
}
|
|
|
|
m_mainWindow->slotQueueFilter();
|
|
|
|
blockAllSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::modifiedEntries(Data::EntryVec entries_) {
|
|
|
|
// when a new document is being loaded, loans are added to borrowers, which
|
|
|
|
// end up calling Entry::checkIn() which called Document::saveEntry() which calls here
|
|
|
|
// ignore that
|
|
|
|
if(!m_mainWindow->m_initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
blockAllSignals(true);
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->modifyEntries(entries_);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_viewStack->entryView()->slotRefresh(); // special case
|
|
|
|
m_mainWindow->slotQueueFilter();
|
|
|
|
blockAllSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::removedEntries(Data::EntryVec entries_) {
|
|
|
|
blockAllSignals(true);
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->removeEntries(entries_);
|
|
|
|
}
|
|
|
|
for(Data::EntryVecIt it = entries_.begin(); it != entries_.end(); ++it) {
|
|
|
|
m_selectedEntries.remove(it);
|
|
|
|
m_currentEntries.remove(it);
|
|
|
|
}
|
|
|
|
if(m_currentEntries.isEmpty()) {
|
|
|
|
m_mainWindow->m_viewStack->entryView()->clear();
|
|
|
|
}
|
|
|
|
m_mainWindow->slotEntryCount();
|
|
|
|
m_mainWindow->slotQueueFilter();
|
|
|
|
blockAllSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::addedField(Data::CollPtr coll_, Data::FieldPtr field_) {
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->addField(coll_, field_);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_viewStack->refresh();
|
|
|
|
m_mainWindow->slotUpdateCollectionToolBar(coll_);
|
|
|
|
m_mainWindow->slotQueueFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::removedField(Data::CollPtr coll_, Data::FieldPtr field_) {
|
|
|
|
// myDebug() << "Controller::removedField() - " << field_->name() << endl;
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->removeField(coll_, field_);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_viewStack->refresh();
|
|
|
|
m_mainWindow->slotUpdateCollectionToolBar(coll_);
|
|
|
|
m_mainWindow->slotQueueFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::modifiedField(Data::CollPtr coll_, Data::FieldPtr oldField_, Data::FieldPtr newField_) {
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->modifyField(coll_, oldField_, newField_);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_viewStack->refresh();
|
|
|
|
m_mainWindow->slotUpdateCollectionToolBar(coll_);
|
|
|
|
m_mainWindow->slotQueueFilter();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::reorderedFields(Data::CollPtr coll_) {
|
|
|
|
m_mainWindow->m_editDialog->setLayout(coll_);
|
|
|
|
m_mainWindow->m_detailedView->reorderFields(coll_->fields());
|
|
|
|
m_mainWindow->slotUpdateCollectionToolBar(coll_);
|
|
|
|
m_mainWindow->m_viewStack->refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotClearSelection() {
|
|
|
|
if(m_working) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_working = true;
|
|
|
|
blockAllSignals(true);
|
|
|
|
|
|
|
|
m_mainWindow->m_detailedView->clearSelection();
|
|
|
|
m_mainWindow->m_groupView->clearSelection();
|
|
|
|
if(m_mainWindow->m_loanView) {
|
|
|
|
m_mainWindow->m_loanView->clearSelection();
|
|
|
|
}
|
|
|
|
// m_mainWindow->m_editDialog->clear(); let this stay
|
|
|
|
// m_mainWindow->m_viewStack->clear(); let this stay
|
|
|
|
|
|
|
|
blockAllSignals(false);
|
|
|
|
|
|
|
|
m_selectedEntries.clear();
|
|
|
|
updateActions();
|
|
|
|
m_mainWindow->slotEntryCount();
|
|
|
|
m_working = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotUpdateSelection(TQWidget* widget_, const Data::EntryVec& entries_) {
|
|
|
|
if(m_working) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_working = true;
|
|
|
|
|
|
|
|
if(widget_) {
|
|
|
|
m_widgetWithSelection = widget_;
|
|
|
|
}
|
|
|
|
// myDebug() << "Controller::slotUpdateSelection() entryList - " << entries_.count() << endl;
|
|
|
|
|
|
|
|
blockAllSignals(true);
|
|
|
|
// in the list view and group view, if entries are selected in one, clear selection in other
|
|
|
|
if(m_widgetWithSelection != m_mainWindow->m_detailedView) {
|
|
|
|
m_mainWindow->m_detailedView->clearSelection();
|
|
|
|
}
|
|
|
|
if(m_widgetWithSelection != m_mainWindow->m_groupView) {
|
|
|
|
m_mainWindow->m_groupView->clearSelection();
|
|
|
|
}
|
|
|
|
if(m_mainWindow->m_filterView && m_widgetWithSelection != m_mainWindow->m_filterView) {
|
|
|
|
m_mainWindow->m_filterView->clearSelection();
|
|
|
|
}
|
|
|
|
if(m_mainWindow->m_loanView && m_widgetWithSelection != m_mainWindow->m_loanView) {
|
|
|
|
m_mainWindow->m_loanView->clearSelection();
|
|
|
|
}
|
|
|
|
if(m_widgetWithSelection != m_mainWindow->m_editDialog) {
|
|
|
|
m_mainWindow->m_editDialog->setContents(entries_);
|
|
|
|
}
|
|
|
|
// only show first one
|
|
|
|
if(m_widgetWithSelection && m_widgetWithSelection != m_mainWindow->m_viewStack->iconView()) {
|
|
|
|
if(entries_.count() > 1) {
|
|
|
|
m_mainWindow->m_viewStack->showEntries(entries_);
|
|
|
|
} else if(entries_.count() > 0) {
|
|
|
|
m_mainWindow->m_viewStack->showEntry(entries_[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
blockAllSignals(false);
|
|
|
|
|
|
|
|
m_selectedEntries = entries_;
|
|
|
|
updateActions();
|
|
|
|
m_mainWindow->slotEntryCount();
|
|
|
|
m_working = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotGoPrevEntry() {
|
|
|
|
goEntrySibling(PrevEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotGoNextEntry() {
|
|
|
|
goEntrySibling(NextEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::goEntrySibling(EntryDirection dir_) {
|
|
|
|
// if there are currently multiple selected, then do nothing
|
|
|
|
if(m_selectedEntries.count() != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// find the widget that has an entry selected
|
|
|
|
GUI::ListView* view = ::tqqt_cast<GUI::ListView*>(m_widgetWithSelection);
|
|
|
|
if(!view) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GUI::ListViewItemList items = view->selectedItems();
|
|
|
|
if(items.count() != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
GUI::ListViewItem* item = items.first();
|
|
|
|
if(item->isEntryItem()) {
|
|
|
|
bool looped = false;
|
|
|
|
// check sanity
|
|
|
|
if(m_selectedEntries.front() != static_cast<EntryItem*>(item)->entry()) {
|
|
|
|
myDebug() << "Controller::slotGoNextEntry() - entries don't match!" << endl;
|
|
|
|
}
|
|
|
|
GUI::ListViewItem* nextItem = static_cast<GUI::ListViewItem*>(dir_ == PrevEntry
|
|
|
|
? item->itemAbove()
|
|
|
|
: item->itemBelow());
|
|
|
|
if(!nextItem) {
|
|
|
|
// cycle through
|
|
|
|
nextItem = static_cast<GUI::ListViewItem*>(dir_ == PrevEntry
|
|
|
|
? view->lastItem()
|
|
|
|
: view->firstChild());
|
|
|
|
looped = true;
|
|
|
|
}
|
|
|
|
while(!nextItem->isVisible()) {
|
|
|
|
nextItem = static_cast<GUI::ListViewItem*>(dir_ == PrevEntry
|
|
|
|
? nextItem->itemAbove()
|
|
|
|
: nextItem->itemBelow());
|
|
|
|
}
|
|
|
|
while(nextItem && !nextItem->isEntryItem()) {
|
|
|
|
nextItem->setOpen(true); // have to be open to find the next one
|
|
|
|
nextItem = static_cast<GUI::ListViewItem*>(dir_ == PrevEntry
|
|
|
|
? nextItem->itemAbove()
|
|
|
|
: nextItem->itemBelow());
|
|
|
|
if(!nextItem && !looped) {
|
|
|
|
// cycle through
|
|
|
|
nextItem = static_cast<GUI::ListViewItem*>(dir_ == PrevEntry
|
|
|
|
? view->lastItem()
|
|
|
|
: view->firstChild());
|
|
|
|
looped = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(nextItem) {
|
|
|
|
Data::EntryPtr e = static_cast<EntryItem*>(nextItem)->entry();
|
|
|
|
view->blockSignals(true);
|
|
|
|
view->setSelected(item, false);
|
|
|
|
view->setSelected(nextItem, true);
|
|
|
|
view->ensureItemVisible(nextItem);
|
|
|
|
view->blockSignals(false);
|
|
|
|
slotUpdateSelection(view, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotUpdateCurrent(const Data::EntryVec& entries_) {
|
|
|
|
if(m_working) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_working = true;
|
|
|
|
|
|
|
|
blockAllSignals(true);
|
|
|
|
m_mainWindow->m_viewStack->showEntries(entries_);
|
|
|
|
blockAllSignals(false);
|
|
|
|
|
|
|
|
m_currentEntries = entries_;
|
|
|
|
m_working = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotUpdateSelectedEntries(const TQString& source_) {
|
|
|
|
if(m_selectedEntries.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// it deletes itself when done
|
|
|
|
// signal mapper strings can't be empty, "_all" is set in mainwindow
|
|
|
|
if(source_.isEmpty() || source_ == Latin1Literal("_all")) {
|
|
|
|
new EntryUpdater(m_selectedEntries.front()->collection(), m_selectedEntries, this);
|
|
|
|
} else {
|
|
|
|
new EntryUpdater(source_, m_selectedEntries.front()->collection(), m_selectedEntries, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotDeleteSelectedEntries() {
|
|
|
|
if(m_selectedEntries.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_working = true;
|
|
|
|
|
|
|
|
// confirm delete
|
|
|
|
if(m_selectedEntries.count() == 1) {
|
|
|
|
TQString str = i18n("Do you really want to delete this entry?");
|
|
|
|
TQString dontAsk = TQString::fromLatin1("DeleteEntry");
|
|
|
|
int ret = KMessageBox::warningContinueCancel(Kernel::self()->widget(), str, i18n("Delete Entry"),
|
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
|
|
|
KGuiItem(i18n("&Delete"), TQString::fromLatin1("edit-delete")), dontAsk);
|
|
|
|
if(ret != KMessageBox::Continue) {
|
|
|
|
m_working = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TQStringList names;
|
|
|
|
for(Data::EntryVecIt entry = m_selectedEntries.begin(); entry != m_selectedEntries.end(); ++entry) {
|
|
|
|
names += entry->title();
|
|
|
|
}
|
|
|
|
TQString str = i18n("Do you really want to delete these entries?");
|
|
|
|
// historically called DeleteMultipleBooks, don't change
|
|
|
|
TQString dontAsk = TQString::fromLatin1("DeleteMultipleBooks");
|
|
|
|
int ret = KMessageBox::warningContinueCancelList(Kernel::self()->widget(), str, names,
|
|
|
|
i18n("Delete Multiple Entries"),
|
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
|
|
|
KGuiItem(i18n("&Delete"), TQString::fromLatin1("edit-delete")), dontAsk);
|
|
|
|
if(ret != KMessageBox::Continue) {
|
|
|
|
m_working = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GUI::CursorSaver cs;
|
|
|
|
Kernel::self()->removeEntries(m_selectedEntries);
|
|
|
|
updateActions();
|
|
|
|
|
|
|
|
m_working = false;
|
|
|
|
|
|
|
|
// special case, the detailed list view selects the next item, so handle that
|
|
|
|
// Data::EntryList newList;
|
|
|
|
// for(GUI::ListViewItemListIt it(m_mainWindow->m_detailedView->selectedItems()); it.current(); ++it) {
|
|
|
|
// newList.append(static_cast<EntryItem*>(it.current())->entry());
|
|
|
|
// }
|
|
|
|
// slotUpdateSelection(m_mainWindow->m_detailedView, newList);
|
|
|
|
slotClearSelection();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotMergeSelectedEntries() {
|
|
|
|
// merge requires at least 2 entries
|
|
|
|
if(m_selectedEntries.count() < 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
new EntryMerger(m_selectedEntries, this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotRefreshField(Data::FieldPtr field_) {
|
|
|
|
// myDebug() << "Controller::slotRefreshField()" << endl;
|
|
|
|
// group view only needs to refresh if it's the title
|
|
|
|
if(field_->name() == Latin1Literal("title")) {
|
|
|
|
m_mainWindow->m_groupView->populateCollection();
|
|
|
|
}
|
|
|
|
m_mainWindow->m_detailedView->slotRefresh();
|
|
|
|
m_mainWindow->m_viewStack->refresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotCopySelectedEntries() {
|
|
|
|
if(m_selectedEntries.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// keep copy of selected entries
|
|
|
|
Data::EntryVec old = m_selectedEntries;
|
|
|
|
|
|
|
|
GUI::CursorSaver cs;
|
|
|
|
// need to create copies
|
|
|
|
Data::EntryVec entries;
|
|
|
|
for(Data::EntryVecIt it = m_selectedEntries.begin(); it != m_selectedEntries.end(); ++it) {
|
|
|
|
entries.append(new Data::Entry(*it));
|
|
|
|
}
|
|
|
|
Kernel::self()->addEntries(entries, false);
|
|
|
|
slotUpdateSelection(0, old);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::blockAllSignals(bool block_) const {
|
|
|
|
// sanity check
|
|
|
|
if(!m_mainWindow->m_initialized) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_mainWindow->m_detailedView->blockSignals(block_);
|
|
|
|
m_mainWindow->m_groupView->blockSignals(block_);
|
|
|
|
if(m_mainWindow->m_loanView) {
|
|
|
|
m_mainWindow->m_loanView->blockSignals(block_);
|
|
|
|
}
|
|
|
|
if(m_mainWindow->m_filterView) {
|
|
|
|
m_mainWindow->m_filterView->blockSignals(block_);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_editDialog->blockSignals(block_);
|
|
|
|
m_mainWindow->m_viewStack->iconView()->blockSignals(block_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotUpdateFilter(FilterPtr filter_) {
|
|
|
|
// myDebug() << "Controller::slotUpdateFilter()" << endl;
|
|
|
|
blockAllSignals(true);
|
|
|
|
|
|
|
|
// the view takes over ownership of the filter
|
|
|
|
if(filter_ && !filter_->isEmpty()) {
|
|
|
|
// clear the icon view selection only
|
|
|
|
// the detailed view takes care of itself
|
|
|
|
m_mainWindow->m_viewStack->iconView()->clearSelection();
|
|
|
|
m_selectedEntries.clear();
|
|
|
|
}
|
|
|
|
updateActions();
|
|
|
|
|
|
|
|
m_mainWindow->m_detailedView->setFilter(filter_); // takes ownership
|
|
|
|
|
|
|
|
blockAllSignals(false);
|
|
|
|
|
|
|
|
m_mainWindow->slotEntryCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::editEntry(Data::EntryPtr) const {
|
|
|
|
m_mainWindow->slotShowEntryEditor();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::plugCollectionActions(TQPopupMenu* popup_) {
|
|
|
|
if(!popup_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_mainWindow->action("coll_rename_collection")->plug(popup_);
|
|
|
|
m_mainWindow->action("coll_fields")->plug(popup_);
|
|
|
|
m_mainWindow->action("change_entry_grouping")->plug(popup_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::plugEntryActions(TQPopupMenu* popup_) {
|
|
|
|
if(!popup_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// m_mainWindow->m_newEntry->plug(popup_);
|
|
|
|
m_mainWindow->m_editEntry->plug(popup_);
|
|
|
|
m_mainWindow->m_copyEntry->plug(popup_);
|
|
|
|
m_mainWindow->m_deleteEntry->plug(popup_);
|
|
|
|
m_mainWindow->m_mergeEntry->plug(popup_);
|
|
|
|
m_mainWindow->m_updateEntryMenu->plug(popup_);
|
|
|
|
// there's a bug in TDEActionMenu with KXMLGUIFactory::plugActionList
|
|
|
|
// pluging the menu action isn't enough to have the popup get populated
|
|
|
|
plugUpdateMenu(popup_);
|
|
|
|
popup_->insertSeparator();
|
|
|
|
m_mainWindow->m_checkOutEntry->plug(popup_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::plugUpdateMenu(TQPopupMenu* popup_) {
|
|
|
|
TQPopupMenu* updatePopup = 0;
|
|
|
|
const uint count = popup_->count();
|
|
|
|
for(uint i = 0; i < count; ++i) {
|
|
|
|
TQMenuItem* item = popup_->findItem(popup_->idAt(i));
|
|
|
|
if(item && item->text() == m_mainWindow->m_updateEntryMenu->text()) {
|
|
|
|
updatePopup = item->popup();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!updatePopup) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// I can't figure out why the actions get duplicated, but they do
|
|
|
|
// so clear them all
|
|
|
|
m_mainWindow->m_updateAll->unplug(updatePopup);
|
|
|
|
for(TQPtrListIterator<TDEAction> it(m_mainWindow->m_fetchActions); it.current(); ++it) {
|
|
|
|
it.current()->unplug(updatePopup);
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear separator, too
|
|
|
|
updatePopup->clear();
|
|
|
|
|
|
|
|
m_mainWindow->m_updateAll->plug(updatePopup);
|
|
|
|
updatePopup->insertSeparator();
|
|
|
|
for(TQPtrListIterator<TDEAction> it(m_mainWindow->m_fetchActions); it.current(); ++it) {
|
|
|
|
it.current()->plug(updatePopup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::updateActions() const {
|
|
|
|
bool emptySelection = m_selectedEntries.isEmpty();
|
|
|
|
m_mainWindow->stateChanged(TQString::fromLatin1("empty_selection"),
|
|
|
|
emptySelection ? KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse);
|
|
|
|
for(TQPtrListIterator<TDEAction> it(m_mainWindow->m_fetchActions); it.current(); ++it) {
|
|
|
|
it.current()->setEnabled(!emptySelection);
|
|
|
|
}
|
|
|
|
//only enable citation items when it's a bibliography
|
|
|
|
bool isBibtex = Kernel::self()->collectionType() == Data::Collection::Bibtex;
|
|
|
|
if(isBibtex) {
|
|
|
|
m_mainWindow->action("cite_clipboard")->setEnabled(!emptySelection);
|
|
|
|
m_mainWindow->action("cite_lyxpipe")->setEnabled(!emptySelection);
|
|
|
|
m_mainWindow->action("cite_openoffice")->setEnabled(!emptySelection);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_checkInEntry->setEnabled(canCheckIn());
|
|
|
|
|
|
|
|
if(m_selectedEntries.count() < 2) {
|
|
|
|
m_mainWindow->m_editEntry->setText(i18n("&Edit Entry..."));
|
|
|
|
m_mainWindow->m_copyEntry->setText(i18n("D&uplicate Entry"));
|
|
|
|
m_mainWindow->m_updateEntryMenu->setText(i18n("&Update Entry"));
|
|
|
|
m_mainWindow->m_deleteEntry->setText(i18n("&Delete Entry"));
|
|
|
|
m_mainWindow->m_mergeEntry->setEnabled(false);
|
|
|
|
} else {
|
|
|
|
m_mainWindow->m_editEntry->setText(i18n("&Edit Entries..."));
|
|
|
|
m_mainWindow->m_copyEntry->setText(i18n("D&uplicate Entries"));
|
|
|
|
m_mainWindow->m_updateEntryMenu->setText(i18n("&Update Entries"));
|
|
|
|
m_mainWindow->m_deleteEntry->setText(i18n("&Delete Entries"));
|
|
|
|
m_mainWindow->m_mergeEntry->setEnabled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::addedBorrower(Data::BorrowerPtr borrower_) {
|
|
|
|
m_mainWindow->addLoanView(); // just in case
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->addBorrower(borrower_);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_viewTabs->setTabBarHidden(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::modifiedBorrower(Data::BorrowerPtr borrower_) {
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->modifyBorrower(borrower_);
|
|
|
|
}
|
|
|
|
hideTabs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::addedFilter(FilterPtr filter_) {
|
|
|
|
m_mainWindow->addFilterView(); // just in case
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->addFilter(filter_);
|
|
|
|
}
|
|
|
|
m_mainWindow->m_viewTabs->setTabBarHidden(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::removedFilter(FilterPtr filter_) {
|
|
|
|
for(ObserverVec::Iterator it = m_observers.begin(); it != m_observers.end(); ++it) {
|
|
|
|
it->removeFilter(filter_);
|
|
|
|
}
|
|
|
|
hideTabs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotCheckOut() {
|
|
|
|
if(m_selectedEntries.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Data::EntryVec loanedEntries = m_selectedEntries;
|
|
|
|
|
|
|
|
// check to see if any of the entries are already on-loan, and warn user
|
|
|
|
TQMap<TQString, Data::EntryPtr> alreadyLoaned;
|
|
|
|
const Data::BorrowerVec& borrowers = Data::Document::self()->collection()->borrowers();
|
|
|
|
for(Data::BorrowerVec::ConstIterator it = borrowers.begin(); it != borrowers.end(); ++it) {
|
|
|
|
const Data::LoanVec& loans = it->loans();
|
|
|
|
for(Data::LoanVec::ConstIterator it2 = loans.begin(); it2 != loans.end(); ++it2) {
|
|
|
|
if(m_selectedEntries.contains(it2->entry())) {
|
|
|
|
alreadyLoaned.insert(it2->entry()->title(), it2->entry());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!alreadyLoaned.isEmpty()) {
|
|
|
|
KMessageBox::informationList(Kernel::self()->widget(),
|
|
|
|
i18n("The following items are already loaned, but Tellico "
|
|
|
|
"does not currently support lending an item multiple "
|
|
|
|
"times. They will be removed from the list of items "
|
|
|
|
"to lend."),
|
|
|
|
alreadyLoaned.keys());
|
|
|
|
TQMapConstIterator<TQString, Data::EntryPtr> it = alreadyLoaned.constBegin();
|
|
|
|
TQMapConstIterator<TQString, Data::EntryPtr> end = alreadyLoaned.constEnd();
|
|
|
|
for( ; it != end; ++it) {
|
|
|
|
loanedEntries.remove(it.data());
|
|
|
|
}
|
|
|
|
if(loanedEntries.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Kernel::self()->addLoans(loanedEntries)) {
|
|
|
|
m_mainWindow->m_checkInEntry->setEnabled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotCheckIn() {
|
|
|
|
slotCheckIn(m_selectedEntries);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::slotCheckIn(const Data::EntryVec& entries_) {
|
|
|
|
if(entries_.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Data::LoanVec loans;
|
|
|
|
for(Data::EntryVec::ConstIterator it = entries_.begin(); it != entries_.end(); ++it) {
|
|
|
|
// these have to be in the loop since if a borrower gets empty
|
|
|
|
// it will be deleted, so the vector could change, for every entry iterator
|
|
|
|
Data::BorrowerVec vec = Data::Document::self()->collection()->borrowers();
|
|
|
|
// vec.end() must be in the loop, do NOT cache the value, it could change!
|
|
|
|
for(Data::BorrowerVec::Iterator bIt = vec.begin(); bIt != vec.end(); ++bIt) {
|
|
|
|
Data::LoanPtr l = bIt->loan(it.data());
|
|
|
|
if(l) {
|
|
|
|
loans.append(l);
|
|
|
|
// assume it's only loaned once
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Kernel::self()->removeLoans(loans)) {
|
|
|
|
m_mainWindow->m_checkInEntry->setEnabled(false);
|
|
|
|
}
|
|
|
|
hideTabs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::hideTabs() const {
|
|
|
|
if((!m_mainWindow->m_filterView || m_mainWindow->m_filterView->childCount() == 0) &&
|
|
|
|
(!m_mainWindow->m_loanView || m_mainWindow->m_loanView->childCount() == 0)) {
|
|
|
|
m_mainWindow->m_viewTabs->showPage(m_mainWindow->m_groupView);
|
|
|
|
m_mainWindow->m_viewTabs->setTabBarHidden(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline
|
|
|
|
bool Controller::canCheckIn() const {
|
|
|
|
for(Data::EntryVec::ConstIterator entry = m_selectedEntries.begin(); entry != m_selectedEntries.end(); ++entry) {
|
|
|
|
if(entry->field(TQString::fromLatin1("loaned")) == Latin1Literal("true")) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::updatedFetchers() {
|
|
|
|
m_mainWindow->updateEntrySources();
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "controller.moc"
|