File indexing completed on 2024-04-28 05:08:16
0001 /*************************************************************************** 0002 Copyright (C) 2003-2009 Robby Stephenson <robby@periapsis.org> 0003 ***************************************************************************/ 0004 0005 /*************************************************************************** 0006 * * 0007 * This program is free software; you can redistribute it and/or * 0008 * modify it under the terms of the GNU General Public License as * 0009 * published by the Free Software Foundation; either version 2 of * 0010 * the License or (at your option) version 3 or any later version * 0011 * accepted by the membership of KDE e.V. (or its successor approved * 0012 * by the membership of KDE e.V.), which shall act as a proxy * 0013 * defined in Section 14 of version 3 of the license. * 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. * 0022 * * 0023 ***************************************************************************/ 0024 0025 #include "controller.h" 0026 #include "mainwindow.h" 0027 #include "groupview.h" 0028 #include "detailedlistview.h" 0029 #include "entryeditdialog.h" 0030 #include "entryview.h" 0031 #include "entryiconview.h" 0032 #include "entry.h" 0033 #include "entrygroup.h" 0034 #include "field.h" 0035 #include "filter.h" 0036 #include "tellico_kernel.h" 0037 #include "collection.h" 0038 #include "document.h" 0039 #include "borrower.h" 0040 #include "filterview.h" 0041 #include "loanview.h" 0042 #include "entryupdater.h" 0043 #include "entrymerger.h" 0044 #include "utils/cursorsaver.h" 0045 #include "gui/lineedit.h" 0046 #include "gui/tabwidget.h" 0047 #include "tellico_debug.h" 0048 0049 #include <KLocalizedString> 0050 #include <KMessageBox> 0051 #include <KActionMenu> 0052 0053 #include <QMenu> 0054 0055 using Tellico::Controller; 0056 0057 Controller* Controller::s_self = nullptr; 0058 0059 Controller::Controller(Tellico::MainWindow* parent_) 0060 : QObject(parent_), m_mainWindow(parent_), m_working(false) { 0061 } 0062 0063 Controller::~Controller() { 0064 } 0065 0066 void Controller::addObserver(Tellico::Observer* obs) { 0067 m_observers.append(obs); 0068 } 0069 0070 void Controller::removeObserver(Tellico::Observer* obs) { 0071 m_observers.removeAll(obs); 0072 } 0073 0074 QString Controller::groupBy() const { 0075 return m_mainWindow->m_groupView->groupBy(); 0076 } 0077 0078 QStringList Controller::expandedGroupBy() const { 0079 QStringList g; 0080 g << groupBy(); 0081 // special case for pseudo-group 0082 if(g[0] == Data::Collection::s_peopleGroupName) { 0083 g.clear(); 0084 Data::FieldList fields = Data::Document::self()->collection()->peopleFields(); 0085 foreach(Data::FieldPtr field, fields) { 0086 g << field->name(); 0087 } 0088 } 0089 // special case for no groups 0090 if(g[0].isEmpty()) { 0091 g.clear(); 0092 } 0093 return g; 0094 } 0095 0096 QStringList Controller::sortTitles() const { 0097 QStringList list; 0098 list << m_mainWindow->m_detailedView->sortColumnTitle1(); 0099 list << m_mainWindow->m_detailedView->sortColumnTitle2(); 0100 list << m_mainWindow->m_detailedView->sortColumnTitle3(); 0101 return list; 0102 } 0103 0104 QStringList Controller::visibleColumns() const { 0105 return m_mainWindow->m_detailedView->visibleColumns(); 0106 } 0107 0108 Tellico::Data::EntryList Controller::visibleEntries() { 0109 return m_mainWindow->m_detailedView->visibleEntries(); 0110 } 0111 0112 void Controller::slotCollectionAdded(Tellico::Data::CollPtr coll_) { 0113 MARK; 0114 // at start-up, this might get called too early, so check and bail 0115 if(!coll_ || !m_mainWindow->m_groupView) { 0116 return; 0117 } 0118 0119 // do this first because the group view will need it later 0120 m_mainWindow->readCollectionOptions(coll_); 0121 m_mainWindow->slotUpdateToolbarIcons(); 0122 m_mainWindow->updateEntrySources(); // has to be called before all the addCollection() 0123 // calls in the widgets since they may want menu updates 0124 0125 m_mainWindow->m_detailedView->addCollection(coll_); 0126 m_mainWindow->m_groupView->addCollection(coll_); 0127 m_mainWindow->m_editDialog->resetLayout(coll_); 0128 if(!coll_->filters().isEmpty()) { 0129 m_mainWindow->addFilterView(); 0130 m_mainWindow->m_filterView->addCollection(coll_); 0131 m_mainWindow->m_viewTabs->setTabBarHidden(false); 0132 } 0133 if(!coll_->borrowers().isEmpty()) { 0134 m_mainWindow->addLoanView(); 0135 m_mainWindow->m_loanView->addCollection(coll_); 0136 m_mainWindow->m_viewTabs->setTabBarHidden(false); 0137 } 0138 0139 m_mainWindow->slotStatusMsg(i18n("Ready.")); 0140 0141 m_selectedEntries.clear(); 0142 m_mainWindow->slotEntryCount(); 0143 0144 // there really should be a lot of signals to connect to, but right now, the only one 0145 // is used when a field is added on a merge 0146 connect(&*coll_, &Data::Collection::mergeAddedField, 0147 this, &Controller::slotFieldAdded); 0148 0149 emit collectionAdded(coll_->type()); 0150 0151 updateActions(); 0152 0153 connect(&*coll_, &Data::Collection::signalGroupsModified, 0154 m_mainWindow->m_groupView, &GroupView::slotModifyGroups); 0155 connect(&*coll_, &Data::Collection::signalRefreshField, 0156 this, &Controller::slotRefreshField); 0157 } 0158 0159 void Controller::slotCollectionModified(Tellico::Data::CollPtr coll_, bool structuralChange_) { 0160 Data::EntryList prevSelection = m_selectedEntries; 0161 blockAllSignals(true); 0162 m_mainWindow->m_groupView->removeCollection(coll_); 0163 if(m_mainWindow->m_filterView) { 0164 m_mainWindow->m_filterView->slotReset(); 0165 } 0166 if(m_mainWindow->m_loanView) { 0167 m_mainWindow->m_loanView->slotReset(); 0168 } 0169 // TODO: removing and adding the collection in the detailed view is overkill 0170 // find a more elegant way to refresh the view 0171 m_mainWindow->m_detailedView->removeCollection(coll_); 0172 blockAllSignals(false); 0173 0174 if(structuralChange_) { 0175 m_mainWindow->m_editDialog->resetLayout(coll_); 0176 } 0177 // the selected entries list gets cleared when the detailed list view removes the collection 0178 m_selectedEntries = prevSelection; 0179 m_mainWindow->m_editDialog->setContents(m_selectedEntries); 0180 m_mainWindow->m_detailedView->addCollection(coll_); 0181 m_mainWindow->m_groupView->addCollection(coll_); 0182 if(!coll_->filters().isEmpty()) { 0183 m_mainWindow->addFilterView(); 0184 m_mainWindow->m_filterView->addCollection(coll_); 0185 m_mainWindow->m_viewTabs->setTabBarHidden(false); 0186 } 0187 if(!coll_->borrowers().isEmpty()) { 0188 m_mainWindow->addLoanView(); 0189 m_mainWindow->m_loanView->addCollection(coll_); 0190 m_mainWindow->m_viewTabs->setTabBarHidden(false); 0191 } 0192 0193 m_mainWindow->slotStatusMsg(i18n("Ready.")); 0194 m_mainWindow->slotEntryCount(); 0195 0196 // https://bugs.kde.org/show_bug.cgi?id=386549 0197 // at some point, I need to revisit the ::setImagesAreAvailable() methodology 0198 // there are too many workarounds in the code for that 0199 m_mainWindow->m_detailedView->slotRefreshImages(); 0200 } 0201 0202 void Controller::slotCollectionDeleted(Tellico::Data::CollPtr coll_) { 0203 blockAllSignals(true); 0204 m_mainWindow->saveCollectionOptions(coll_); 0205 m_mainWindow->m_groupView->removeCollection(coll_); 0206 if(m_mainWindow->m_filterView) { 0207 m_mainWindow->m_filterView->slotReset(); 0208 } 0209 if(m_mainWindow->m_loanView) { 0210 m_mainWindow->m_loanView->slotReset(); 0211 } 0212 m_mainWindow->m_detailedView->removeCollection(coll_); 0213 m_mainWindow->m_entryView->clear(); 0214 blockAllSignals(false); 0215 0216 // disconnect all signals from the collection 0217 // this is needed because the Collection::appendCollection() and mergeCollection() 0218 // functions signal collection deleted then added for the same collection 0219 coll_->disconnect(); 0220 } 0221 0222 void Controller::slotFieldAdded(Tellico::Data::CollPtr coll_, Tellico::Data::FieldPtr field_) { 0223 addedField(coll_, field_); 0224 } 0225 0226 // TODO: should be adding entries to models rather than to widget observers 0227 void Controller::addedEntries(Tellico::Data::EntryList entries_) { 0228 blockAllSignals(true); 0229 foreach(Observer* obs, m_observers) { 0230 obs->addEntries(entries_); 0231 } 0232 m_mainWindow->slotQueueFilter(); 0233 blockAllSignals(false); 0234 } 0235 0236 void Controller::modifiedEntries(Tellico::Data::EntryList entries_) { 0237 // when a new document is being loaded, loans are added to borrowers, which 0238 // end up calling Entry::checkIn() which called Document::saveEntry() which calls here 0239 // ignore that 0240 if(!m_mainWindow->m_initialized) { 0241 return; 0242 } 0243 blockAllSignals(true); 0244 foreach(Observer* obs, m_observers) { 0245 obs->modifyEntries(entries_); 0246 } 0247 m_mainWindow->m_entryView->slotRefresh(); // special case 0248 blockAllSignals(false); 0249 } 0250 0251 void Controller::removedEntries(Tellico::Data::EntryList entries_) { 0252 blockAllSignals(true); 0253 foreach(Observer* obs, m_observers) { 0254 obs->removeEntries(entries_); 0255 } 0256 foreach(Data::EntryPtr entry, entries_) { 0257 m_selectedEntries.removeAll(entry); 0258 } 0259 m_mainWindow->slotEntryCount(); 0260 m_mainWindow->slotQueueFilter(); 0261 blockAllSignals(false); 0262 } 0263 0264 void Controller::addedField(Tellico::Data::CollPtr coll_, Tellico::Data::FieldPtr field_) { 0265 foreach(Observer* obs, m_observers) { 0266 obs->addField(coll_, field_); 0267 } 0268 m_mainWindow->m_entryView->slotRefresh(); 0269 m_mainWindow->slotUpdateCollectionToolBar(coll_); 0270 m_mainWindow->slotQueueFilter(); 0271 } 0272 0273 void Controller::removedField(Tellico::Data::CollPtr coll_, Tellico::Data::FieldPtr field_) { 0274 foreach(Observer* obs, m_observers) { 0275 obs->removeField(coll_, field_); 0276 } 0277 m_mainWindow->m_entryView->slotRefresh(); 0278 m_mainWindow->slotUpdateCollectionToolBar(coll_); 0279 m_mainWindow->slotQueueFilter(); 0280 } 0281 0282 void Controller::modifiedField(Tellico::Data::CollPtr coll_, Tellico::Data::FieldPtr oldField_, Tellico::Data::FieldPtr newField_) { 0283 foreach(Observer* obs, m_observers) { 0284 obs->modifyField(coll_, oldField_, newField_); 0285 } 0286 m_mainWindow->m_entryView->slotRefresh(); 0287 m_mainWindow->slotUpdateCollectionToolBar(coll_); 0288 m_mainWindow->slotQueueFilter(); 0289 } 0290 0291 void Controller::reorderedFields(Tellico::Data::CollPtr coll_) { 0292 m_mainWindow->m_editDialog->resetLayout(coll_); 0293 m_mainWindow->m_detailedView->reorderFields(coll_->fields()); 0294 m_mainWindow->slotUpdateCollectionToolBar(coll_); 0295 m_mainWindow->m_entryView->slotRefresh(); 0296 } 0297 0298 void Controller::slotClearSelection() { 0299 if(m_working) { 0300 return; 0301 } 0302 0303 m_working = true; 0304 blockAllSignals(true); 0305 0306 m_mainWindow->m_detailedView->clearSelection(); 0307 m_mainWindow->m_iconView->clearSelection(); 0308 m_mainWindow->m_groupView->clearSelection(); 0309 if(m_mainWindow->m_filterView) { 0310 m_mainWindow->m_filterView->clearSelection(); 0311 } 0312 if(m_mainWindow->m_loanView) { 0313 m_mainWindow->m_loanView->clearSelection(); 0314 } 0315 0316 blockAllSignals(false); 0317 0318 m_selectedEntries.clear(); 0319 updateActions(); 0320 m_mainWindow->slotEntryCount(); 0321 m_working = false; 0322 } 0323 0324 void Controller::slotUpdateSelection(const Tellico::Data::EntryList& entries_) { 0325 if(m_working) { 0326 return; 0327 } 0328 m_working = true; 0329 0330 m_selectedEntries = entries_; 0331 updateActions(); 0332 m_mainWindow->slotEntryCount(); 0333 m_working = false; 0334 } 0335 0336 void Controller::slotUpdateSelectedEntries(const QString& source_) { 0337 if(m_selectedEntries.isEmpty()) { 0338 return; 0339 } 0340 0341 // it deletes itself when done 0342 // signal mapper strings can't be empty, "_all" is set in mainwindow 0343 if(source_.isEmpty() || source_ == QLatin1String("_all")) { 0344 new EntryUpdater(m_selectedEntries.front()->collection(), m_selectedEntries, this); 0345 } else { 0346 new EntryUpdater(source_, m_selectedEntries.front()->collection(), m_selectedEntries, this); 0347 } 0348 } 0349 0350 void Controller::slotDeleteSelectedEntries() { 0351 if(m_selectedEntries.isEmpty()) { 0352 return; 0353 } 0354 0355 m_working = true; 0356 0357 // confirm delete 0358 if(m_selectedEntries.count() == 1) { 0359 QString str = i18n("Do you really want to delete this entry?"); 0360 QString dontAsk = QStringLiteral("DeleteEntry"); 0361 int ret = KMessageBox::warningContinueCancel(Kernel::self()->widget(), str, i18n("Delete Entry"), 0362 KStandardGuiItem::del(), 0363 KStandardGuiItem::cancel(), dontAsk); 0364 if(ret != KMessageBox::Continue) { 0365 m_working = false; 0366 return; 0367 } 0368 } else { 0369 QStringList names; 0370 foreach(Data::EntryPtr entry, m_selectedEntries) { 0371 names += entry->title(); 0372 } 0373 QString str = i18n("Do you really want to delete these entries?"); 0374 // historically called DeleteMultipleBooks, don't change 0375 QString dontAsk = QStringLiteral("DeleteMultipleBooks"); 0376 int ret = KMessageBox::warningContinueCancelList(Kernel::self()->widget(), str, names, 0377 i18n("Delete Multiple Entries"), 0378 KStandardGuiItem::del(), 0379 KStandardGuiItem::cancel(), dontAsk); 0380 if(ret != KMessageBox::Continue) { 0381 m_working = false; 0382 return; 0383 } 0384 } 0385 0386 GUI::CursorSaver cs; 0387 Kernel::self()->removeEntries(m_selectedEntries); 0388 updateActions(); 0389 0390 m_working = false; 0391 0392 // special case, the detailed list view selects the next item, so handle that 0393 // Data::EntryList newList; 0394 // for(GUI::ListViewItemListIt it(m_mainWindow->m_detailedView->selectedItems()); it.current(); ++it) { 0395 // newList.append(static_cast<EntryItem*>(it.current())->entry()); 0396 // } 0397 // slotUpdateSelection(m_mainWindow->m_detailedView, newList); 0398 slotClearSelection(); 0399 } 0400 0401 void Controller::slotMergeSelectedEntries() { 0402 // merge requires at least 2 entries 0403 if(m_selectedEntries.count() < 2) { 0404 return; 0405 } 0406 0407 new EntryMerger(m_selectedEntries, this); 0408 } 0409 0410 void Controller::slotRefreshField(Tellico::Data::FieldPtr field_) { 0411 // DEBUG_LINE; 0412 // group view only needs to refresh if it's the title 0413 if(field_->name() == QLatin1String("title")) { 0414 m_mainWindow->m_groupView->populateCollection(); 0415 } 0416 m_mainWindow->m_detailedView->slotRefresh(); 0417 m_mainWindow->m_entryView->slotRefresh(); 0418 } 0419 0420 void Controller::slotCopySelectedEntries() { 0421 if(m_selectedEntries.isEmpty()) { 0422 return; 0423 } 0424 0425 // keep copy of selected entries 0426 Data::EntryList old = m_selectedEntries; 0427 0428 GUI::CursorSaver cs; 0429 // need to create copies 0430 Data::EntryList entries; 0431 foreach(Data::EntryPtr it, m_selectedEntries) { 0432 entries.append(Data::EntryPtr(new Data::Entry(*it))); 0433 } 0434 Kernel::self()->addEntries(entries, false); 0435 slotUpdateSelection(old); 0436 } 0437 0438 void Controller::blockAllSignals(bool block_) const { 0439 // sanity check 0440 if(!m_mainWindow->m_initialized) { 0441 return; 0442 } 0443 m_mainWindow->m_detailedView->blockSignals(block_); 0444 m_mainWindow->m_groupView->blockSignals(block_); 0445 m_mainWindow->m_quickFilter->blockSignals(block_); 0446 if(m_mainWindow->m_loanView) { 0447 m_mainWindow->m_loanView->blockSignals(block_); 0448 } 0449 if(m_mainWindow->m_filterView) { 0450 m_mainWindow->m_filterView->blockSignals(block_); 0451 } 0452 m_mainWindow->m_editDialog->blockSignals(block_); 0453 m_mainWindow->m_iconView->blockSignals(block_); 0454 } 0455 0456 void Controller::slotUpdateFilter(Tellico::FilterPtr filter_) { 0457 blockAllSignals(true); 0458 0459 // the view takes over ownership of the filter 0460 if(filter_ && !filter_->isEmpty()) { 0461 // clear the icon view selection only 0462 // the detailed view takes care of itself 0463 m_mainWindow->m_iconView->clearSelection(); 0464 m_selectedEntries.clear(); 0465 } 0466 updateActions(); 0467 0468 m_mainWindow->m_detailedView->setFilter(filter_); // takes ownership 0469 if(!filter_ && m_mainWindow->m_filterView && !m_mainWindow->m_dontQueueFilter) { 0470 // for example, when quick filter clears the selection 0471 // the check against m_dontQueueFilter is to prevent the situation when the FilterView has an Entry selected 0472 // which sends an empty filter selection, which would then clear the whole FilterView selection 0473 m_mainWindow->m_filterView->clearSelection(); 0474 } 0475 0476 blockAllSignals(false); 0477 0478 m_mainWindow->slotEntryCount(); 0479 } 0480 0481 void Controller::clearFilter() { 0482 blockAllSignals(true); 0483 m_mainWindow->m_quickFilter->clear(); 0484 m_mainWindow->m_detailedView->setFilter(Tellico::FilterPtr()); 0485 blockAllSignals(false); 0486 } 0487 0488 void Controller::editEntry(Tellico::Data::EntryPtr entry_) const { 0489 m_mainWindow->slotShowEntryEditor(); 0490 m_mainWindow->m_editDialog->setContents(Data::EntryList() << entry_); 0491 } 0492 0493 void Controller::plugCollectionActions(QMenu* popup_) { 0494 if(!popup_) { 0495 return; 0496 } 0497 0498 popup_->addAction(m_mainWindow->action("coll_rename_collection")); 0499 popup_->addAction(m_mainWindow->action("coll_fields")); 0500 popup_->addAction(m_mainWindow->action("change_entry_grouping")); 0501 } 0502 0503 void Controller::plugEntryActions(QMenu* popup_) { 0504 if(!popup_) { 0505 return; 0506 } 0507 0508 // m_mainWindow->m_newEntry->plug(popup_); 0509 popup_->addAction(m_mainWindow->m_editEntry); 0510 popup_->addAction(m_mainWindow->m_copyEntry); 0511 popup_->addAction(m_mainWindow->m_deleteEntry); 0512 popup_->addAction(m_mainWindow->m_mergeEntry); 0513 popup_->addMenu(m_mainWindow->m_updateEntryMenu->menu()); 0514 // there's a bug in KActionMenu with KXMLGUIFactory::plugActionList 0515 // pluging the menu isn't enough to have the popup get populated 0516 plugUpdateMenu(popup_); 0517 popup_->addSeparator(); 0518 popup_->addAction(m_mainWindow->m_checkOutEntry); 0519 } 0520 0521 QMenu* Controller::plugSortActions(QMenu* popup_) { 0522 if(!popup_) { 0523 return nullptr; 0524 } 0525 0526 QMenu* sortMenu = popup_->addMenu(i18n("&Sort By")); 0527 sortMenu->setIcon(QIcon::fromTheme(QStringLiteral("view-sort"), 0528 QIcon::fromTheme(QStringLiteral("view-sort-ascending")))); 0529 foreach(Data::FieldPtr field, Data::Document::self()->collection()->fields()) { 0530 // not allowed to sort by Image, Table, Para, or URL 0531 if(field->type() == Data::Field::Image || 0532 field->type() == Data::Field::Table || 0533 field->type() == Data::Field::URL || 0534 field->type() == Data::Field::Para) { 0535 continue; 0536 } 0537 sortMenu->addAction(field->title())->setData(QVariant::fromValue(field)); 0538 } 0539 return sortMenu; 0540 } 0541 0542 void Controller::plugUpdateMenu(QMenu* popup_) { 0543 QMenu* updatePopup = nullptr; 0544 foreach(QAction* action, popup_->actions()) { 0545 if(action && action->text() == m_mainWindow->m_updateEntryMenu->text()) { 0546 updatePopup = action->menu(); 0547 break; 0548 } 0549 } 0550 0551 if(!updatePopup) { 0552 return; 0553 } 0554 0555 // I can't figure out why the actions get duplicated, but they do 0556 // so clear them all 0557 updatePopup->removeAction(m_mainWindow->m_updateAll); 0558 foreach(QAction* action, m_mainWindow->m_fetchActions) { 0559 updatePopup->removeAction(action); 0560 } 0561 0562 // clear separator, too 0563 updatePopup->clear(); 0564 0565 updatePopup->addAction(m_mainWindow->m_updateAll); 0566 updatePopup->addSeparator(); 0567 foreach(QAction* action, m_mainWindow->m_fetchActions) { 0568 updatePopup->addAction(action); 0569 } 0570 } 0571 0572 void Controller::updateActions() const { 0573 const bool emptySelection = m_selectedEntries.isEmpty(); 0574 m_mainWindow->stateChanged(QStringLiteral("empty_selection"), 0575 emptySelection ? KXMLGUIClient::StateNoReverse : KXMLGUIClient::StateReverse); 0576 foreach(QAction* action, m_mainWindow->m_fetchActions) { 0577 action->setEnabled(!emptySelection); 0578 } 0579 //only enable citation items when it's a bibliography 0580 const bool isBibtex = Kernel::self()->collectionType() == Data::Collection::Bibtex; 0581 if(isBibtex) { 0582 m_mainWindow->action("cite_clipboard")->setEnabled(!emptySelection); 0583 m_mainWindow->action("cite_lyxpipe")->setEnabled(!emptySelection); 0584 } 0585 m_mainWindow->m_checkInEntry->setEnabled(canCheckIn()); 0586 0587 if(m_selectedEntries.count() < 2) { 0588 m_mainWindow->m_editEntry->setText(i18n("&Edit Entry...")); 0589 m_mainWindow->m_copyEntry->setText(i18n("D&uplicate Entry")); 0590 m_mainWindow->m_updateEntryMenu->setText(i18n("&Update Entry")); 0591 m_mainWindow->m_deleteEntry->setText(i18n("&Delete Entry")); 0592 m_mainWindow->m_mergeEntry->setEnabled(false); 0593 } else { 0594 m_mainWindow->m_editEntry->setText(i18n("&Edit Entries...")); 0595 m_mainWindow->m_copyEntry->setText(i18n("D&uplicate Entries")); 0596 m_mainWindow->m_updateEntryMenu->setText(i18n("&Update Entries")); 0597 m_mainWindow->m_deleteEntry->setText(i18n("&Delete Entries")); 0598 m_mainWindow->m_mergeEntry->setEnabled(true); 0599 } 0600 } 0601 0602 void Controller::addedBorrower(Tellico::Data::BorrowerPtr borrower_) { 0603 m_mainWindow->addLoanView(); // just in case 0604 foreach(Observer* obs, m_observers) { 0605 obs->addBorrower(borrower_); 0606 } 0607 m_mainWindow->m_viewTabs->setTabBarHidden(false); 0608 } 0609 0610 void Controller::modifiedBorrower(Tellico::Data::BorrowerPtr borrower_) { 0611 foreach(Observer* obs, m_observers) { 0612 if(borrower_->isEmpty()) { 0613 obs->removeBorrower(borrower_); 0614 } else { 0615 obs->modifyBorrower(borrower_); 0616 } 0617 } 0618 hideTabs(); 0619 } 0620 0621 void Controller::addedFilter(Tellico::FilterPtr filter_) { 0622 m_mainWindow->addFilterView(); // just in case 0623 foreach(Observer* obs, m_observers) { 0624 obs->addFilter(filter_); 0625 } 0626 m_mainWindow->m_viewTabs->setTabBarHidden(false); 0627 } 0628 0629 void Controller::removedFilter(Tellico::FilterPtr filter_) { 0630 foreach(Observer* obs, m_observers) { 0631 obs->removeFilter(filter_); 0632 } 0633 hideTabs(); 0634 } 0635 0636 void Controller::slotCheckOut() { 0637 if(m_selectedEntries.isEmpty()) { 0638 return; 0639 } 0640 0641 Data::EntryList loanedEntries = m_selectedEntries; 0642 0643 // check to see if any of the entries are already on-loan, and warn user 0644 QMap<QString, Data::EntryPtr> alreadyLoaned; 0645 foreach(Data::BorrowerPtr borrower, Data::Document::self()->collection()->borrowers()) { 0646 foreach(Data::LoanPtr loan, borrower->loans()) { 0647 if(m_selectedEntries.contains(loan->entry())) { 0648 alreadyLoaned.insert(loan->entry()->title(), loan->entry()); 0649 } 0650 } 0651 } 0652 if(!alreadyLoaned.isEmpty()) { 0653 KMessageBox::informationList(Kernel::self()->widget(), 0654 i18n("The following items are already loaned, but Tellico " 0655 "does not currently support lending an item multiple " 0656 "times. They will be removed from the list of items " 0657 "to lend."), 0658 alreadyLoaned.keys()); 0659 QMap<QString, Data::EntryPtr>::const_iterator it = alreadyLoaned.constBegin(); 0660 QMap<QString, Data::EntryPtr>::const_iterator end = alreadyLoaned.constEnd(); 0661 for( ; it != end; ++it) { 0662 loanedEntries.removeAll(it.value()); 0663 } 0664 if(loanedEntries.isEmpty()) { 0665 return; 0666 } 0667 } 0668 0669 if(Kernel::self()->addLoans(loanedEntries)) { 0670 m_mainWindow->m_checkInEntry->setEnabled(true); 0671 } 0672 } 0673 0674 void Controller::slotCheckIn() { 0675 slotCheckIn(m_selectedEntries); 0676 } 0677 0678 void Controller::slotCheckIn(const Tellico::Data::EntryList& entries_) { 0679 if(entries_.isEmpty()) { 0680 return; 0681 } 0682 0683 Data::LoanList loans; 0684 foreach(Data::EntryPtr entry, entries_) { 0685 // these have to be in the loop since if a borrower gets empty 0686 // it will be deleted, so the vector could change, for every entry iterator 0687 Data::BorrowerList vec = Data::Document::self()->collection()->borrowers(); 0688 foreach(Data::BorrowerPtr borrower, vec) { 0689 Data::LoanPtr l = borrower->loan(entry); 0690 if(l) { 0691 loans.append(l); 0692 // assume it's only loaned once 0693 break; 0694 } 0695 } 0696 } 0697 0698 if(Kernel::self()->removeLoans(loans)) { 0699 m_mainWindow->m_checkInEntry->setEnabled(false); 0700 } 0701 hideTabs(); 0702 } 0703 0704 void Controller::hideTabs() const { 0705 if((!m_mainWindow->m_filterView || m_mainWindow->m_filterView->isEmpty()) && 0706 (!m_mainWindow->m_loanView || m_mainWindow->m_loanView->isEmpty())) { 0707 int idx = m_mainWindow->m_viewTabs->indexOf(m_mainWindow->m_groupView); 0708 m_mainWindow->m_viewTabs->setCurrentIndex(idx); 0709 m_mainWindow->m_viewTabs->setTabBarHidden(true); 0710 } 0711 } 0712 0713 bool Controller::canCheckIn() const { 0714 foreach(Data::EntryPtr entry, m_selectedEntries) { 0715 if(entry->field(QStringLiteral("loaned")) == QLatin1String("true")) { 0716 return true; 0717 } 0718 } 0719 return false; 0720 } 0721 0722 void Controller::updatedFetchers() { 0723 m_mainWindow->updateEntrySources(); 0724 }