|
|
|
/***************************************************************************
|
|
|
|
copyright : (C) 2003-2008 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 "fetchdialog.h"
|
|
|
|
#include "fetch/fetchmanager.h"
|
|
|
|
#include "fetch/fetcher.h"
|
|
|
|
#include "entryview.h"
|
|
|
|
#include "isbnvalidator.h"
|
|
|
|
#include "upcvalidator.h"
|
|
|
|
#include "tellico_kernel.h"
|
|
|
|
#include "filehandler.h"
|
|
|
|
#include "collection.h"
|
|
|
|
#include "entry.h"
|
|
|
|
#include "document.h"
|
|
|
|
#include "tellico_debug.h"
|
|
|
|
#include "gui/combobox.h"
|
|
|
|
#include "gui/listview.h"
|
|
|
|
#include "tellico_utils.h"
|
|
|
|
#include "stringset.h"
|
|
|
|
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <klineedit.h>
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
#include <kstatusbar.h>
|
|
|
|
#include <tdehtmlview.h>
|
|
|
|
#include <kprogress.h>
|
|
|
|
#include <tdeconfig.h>
|
|
|
|
#include <kdialogbase.h>
|
|
|
|
#include <tdefiledialog.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <tdeaccelmanager.h>
|
|
|
|
#include <ktextedit.h>
|
|
|
|
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqhbox.h>
|
|
|
|
#include <tqvgroupbox.h>
|
|
|
|
#include <tqsplitter.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqwhatsthis.h>
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqvbox.h>
|
|
|
|
#include <tqtimer.h>
|
|
|
|
#include <tqimage.h>
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#ifdef ENABLE_WEBCAM
|
|
|
|
#include "barcode/barcode.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
static const int FETCH_STATUS_ID = 0;
|
|
|
|
static const int FETCH_PROGRESS_ID = 0;
|
|
|
|
static const int FETCH_MIN_WIDTH = 600;
|
|
|
|
|
|
|
|
static const char* FETCH_STRING_SEARCH = I18N_NOOP("&Search");
|
|
|
|
static const char* FETCH_STRING_STOP = I18N_NOOP("&Stop");
|
|
|
|
}
|
|
|
|
|
|
|
|
using Tellico::FetchDialog;
|
|
|
|
using barcodeRecognition::barcodeRecognitionThread;
|
|
|
|
|
|
|
|
class FetchDialog::SearchResultItem : public Tellico::GUI::ListViewItem {
|
|
|
|
friend class FetchDialog;
|
|
|
|
// always add to end
|
|
|
|
SearchResultItem(GUI::ListView* lv, Fetch::SearchResult* r)
|
|
|
|
: GUI::ListViewItem(lv, lv->lastItem()), m_result(r) {
|
|
|
|
setText(1, r->title);
|
|
|
|
setText(2, r->desc);
|
|
|
|
setPixmap(3, Fetch::Manager::self()->fetcherIcon(r->fetcher.data()));
|
|
|
|
setText(3, r->fetcher->source());
|
|
|
|
}
|
|
|
|
Fetch::SearchResult* m_result;
|
|
|
|
};
|
|
|
|
|
|
|
|
FetchDialog::FetchDialog(TQWidget* parent_, const char* name_)
|
|
|
|
: KDialogBase(parent_, name_, false, i18n("Internet Search"), 0),
|
|
|
|
m_timer(new TQTimer(this)), m_started(false) {
|
|
|
|
m_collType = Kernel::self()->collectionType();
|
|
|
|
|
|
|
|
TQWidget* mainWidget = new TQWidget(this, "FetchDialog mainWidget");
|
|
|
|
setMainWidget(mainWidget);
|
|
|
|
TQVBoxLayout* topLayout = new TQVBoxLayout(mainWidget, 0, KDialog::spacingHint());
|
|
|
|
|
|
|
|
TQVGroupBox* queryBox = new TQVGroupBox(i18n("Search Query"), mainWidget, "FetchDialog queryBox");
|
|
|
|
topLayout->addWidget(queryBox);
|
|
|
|
|
|
|
|
TQHBox* box1 = new TQHBox(queryBox, "FetchDialog box1");
|
|
|
|
box1->setSpacing(KDialog::spacingHint());
|
|
|
|
|
|
|
|
TQLabel* label = new TQLabel(i18n("Start the search", "S&earch:"), box1);
|
|
|
|
|
|
|
|
m_valueLineEdit = new KLineEdit(box1);
|
|
|
|
label->setBuddy(m_valueLineEdit);
|
|
|
|
TQWhatsThis::add(m_valueLineEdit, i18n("Enter a search value. An ISBN search must include the full ISBN."));
|
|
|
|
m_keyCombo = new GUI::ComboBox(box1);
|
|
|
|
Fetch::KeyMap map = Fetch::Manager::self()->keyMap();
|
|
|
|
for(Fetch::KeyMap::ConstIterator it = map.begin(); it != map.end(); ++it) {
|
|
|
|
m_keyCombo->insertItem(it.data(), it.key());
|
|
|
|
}
|
|
|
|
connect(m_keyCombo, TQT_SIGNAL(activated(int)), TQT_SLOT(slotKeyChanged(int)));
|
|
|
|
TQWhatsThis::add(m_keyCombo, i18n("Choose the type of search"));
|
|
|
|
|
|
|
|
m_searchButton = new KPushButton(box1);
|
|
|
|
m_searchButton->setGuiItem(KGuiItem(i18n(FETCH_STRING_STOP),
|
|
|
|
SmallIconSet(TQString::fromLatin1("cancel"))));
|
|
|
|
connect(m_searchButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotSearchClicked()));
|
|
|
|
TQWhatsThis::add(m_searchButton, i18n("Click to start or stop the search"));
|
|
|
|
|
|
|
|
// the search button's text changes from search to stop
|
|
|
|
// I don't want it resizing, so figure out the maximum size and set that
|
|
|
|
m_searchButton->polish();
|
|
|
|
int maxWidth = m_searchButton->sizeHint().width();
|
|
|
|
int maxHeight = m_searchButton->sizeHint().height();
|
|
|
|
m_searchButton->setGuiItem(KGuiItem(i18n(FETCH_STRING_SEARCH),
|
|
|
|
SmallIconSet(TQString::fromLatin1("edit-find"))));
|
|
|
|
maxWidth = TQMAX(maxWidth, m_searchButton->sizeHint().width());
|
|
|
|
maxHeight = TQMAX(maxHeight, m_searchButton->sizeHint().height());
|
|
|
|
m_searchButton->setMinimumWidth(maxWidth);
|
|
|
|
m_searchButton->setMinimumHeight(maxHeight);
|
|
|
|
|
|
|
|
TQHBox* box2 = new TQHBox(queryBox);
|
|
|
|
box2->setSpacing(KDialog::spacingHint());
|
|
|
|
|
|
|
|
m_multipleISBN = new TQCheckBox(i18n("&Multiple ISBN/UPC search"), box2);
|
|
|
|
TQWhatsThis::add(m_multipleISBN, i18n("Check this box to search for multiple ISBN or UPC values."));
|
|
|
|
connect(m_multipleISBN, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotMultipleISBN(bool)));
|
|
|
|
|
|
|
|
m_editISBN = new KPushButton(KGuiItem(i18n("Edit List..."), TQString::fromLatin1("text_block")), box2);
|
|
|
|
m_editISBN->setEnabled(false);
|
|
|
|
TQWhatsThis::add(m_editISBN, i18n("Click to open a text edit box for entering or editing multiple ISBN values."));
|
|
|
|
connect(m_editISBN, TQT_SIGNAL(clicked()), TQT_SLOT(slotEditMultipleISBN()));
|
|
|
|
|
|
|
|
// add for spacing
|
|
|
|
box2->setStretchFactor(new TQWidget(box2), 10);
|
|
|
|
|
|
|
|
label = new TQLabel(i18n("Search s&ource:"), box2);
|
|
|
|
m_sourceCombo = new KComboBox(box2);
|
|
|
|
label->setBuddy(m_sourceCombo);
|
|
|
|
Fetch::FetcherVec sources = Fetch::Manager::self()->fetchers(m_collType);
|
|
|
|
for(Fetch::FetcherVec::Iterator it = sources.begin(); it != sources.end(); ++it) {
|
|
|
|
m_sourceCombo->insertItem(Fetch::Manager::self()->fetcherIcon(it.data()), (*it).source());
|
|
|
|
}
|
|
|
|
connect(m_sourceCombo, TQT_SIGNAL(activated(const TQString&)), TQT_SLOT(slotSourceChanged(const TQString&)));
|
|
|
|
TQWhatsThis::add(m_sourceCombo, i18n("Select the database to search"));
|
|
|
|
|
|
|
|
TQSplitter* split = new TQSplitter(Qt::Vertical, mainWidget);
|
|
|
|
topLayout->addWidget(split);
|
|
|
|
|
|
|
|
m_listView = new GUI::ListView(split);
|
|
|
|
// topLayout->addWidget(m_listView);
|
|
|
|
// topLayout->setStretchFactor(m_listView, 1);
|
|
|
|
m_listView->setSorting(10); // greater than number of columns, so not sorting until user clicks column header
|
|
|
|
m_listView->setShowSortIndicator(true);
|
|
|
|
m_listView->setAllColumnsShowFocus(true);
|
|
|
|
m_listView->setSelectionMode(TQListView::Extended);
|
|
|
|
m_listView->addColumn(TQString(), 20); // will show a check mark when added
|
|
|
|
m_listView->setColumnAlignment(0, TQt::AlignHCenter); // align checkmark in middle
|
|
|
|
// m_listView->setColumnWidthMode(0, TQListView::Manual);
|
|
|
|
m_listView->addColumn(i18n("Title"));
|
|
|
|
m_listView->addColumn(i18n("Description"));
|
|
|
|
m_listView->addColumn(i18n("Source"));
|
|
|
|
m_listView->viewport()->installEventFilter(this);
|
|
|
|
|
|
|
|
connect(m_listView, TQT_SIGNAL(selectionChanged()), TQT_SLOT(slotShowEntry()));
|
|
|
|
// double clicking should add the entry
|
|
|
|
connect(m_listView, TQT_SIGNAL(doubleClicked(TQListViewItem*)), TQT_SLOT(slotAddEntry()));
|
|
|
|
TQWhatsThis::add(m_listView, i18n("As results are found, they are added to this list. Selecting one "
|
|
|
|
"will fetch the complete entry and show it in the view below."));
|
|
|
|
|
|
|
|
m_entryView = new EntryView(split, "entry_view");
|
|
|
|
// don't bother creating funky gradient images for compact view
|
|
|
|
m_entryView->setUseGradientImages(false);
|
|
|
|
// set the xslt file AFTER setting the gradient image option
|
|
|
|
m_entryView->setXSLTFile(TQString::fromLatin1("Compact.xsl"));
|
|
|
|
TQWhatsThis::add(m_entryView->view(), i18n("An entry may be shown here before adding it to the "
|
|
|
|
"current collection by selecting it in the list above"));
|
|
|
|
|
|
|
|
TQHBox* box3 = new TQHBox(mainWidget);
|
|
|
|
topLayout->addWidget(box3);
|
|
|
|
box3->setSpacing(KDialog::spacingHint());
|
|
|
|
|
|
|
|
m_addButton = new KPushButton(i18n("&Add Entry"), box3);
|
|
|
|
m_addButton->setEnabled(false);
|
|
|
|
m_addButton->setIconSet(UserIconSet(Kernel::self()->collectionTypeName()));
|
|
|
|
connect(m_addButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotAddEntry()));
|
|
|
|
TQWhatsThis::add(m_addButton, i18n("Add the selected entry to the current collection"));
|
|
|
|
|
|
|
|
m_moreButton = new KPushButton(KGuiItem(i18n("Get More Results"), SmallIconSet(TQString::fromLatin1("edit-find"))), box3);
|
|
|
|
m_moreButton->setEnabled(false);
|
|
|
|
connect(m_moreButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotMoreClicked()));
|
|
|
|
TQWhatsThis::add(m_moreButton, i18n("Fetch more results from the current data source"));
|
|
|
|
|
|
|
|
KPushButton* clearButton = new KPushButton(KStdGuiItem::clear(), box3);
|
|
|
|
connect(clearButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotClearClicked()));
|
|
|
|
TQWhatsThis::add(clearButton, i18n("Clear all search fields and results"));
|
|
|
|
|
|
|
|
TQHBox* bottombox = new TQHBox(mainWidget, "box");
|
|
|
|
topLayout->addWidget(bottombox);
|
|
|
|
bottombox->setSpacing(KDialog::spacingHint());
|
|
|
|
|
|
|
|
m_statusBar = new KStatusBar(bottombox, "statusbar");
|
|
|
|
m_statusBar->insertItem(TQString(), FETCH_STATUS_ID, 1, false);
|
|
|
|
m_statusBar->setItemAlignment(FETCH_STATUS_ID, AlignLeft | AlignVCenter);
|
|
|
|
m_progress = new TQProgressBar(m_statusBar, "progress");
|
|
|
|
m_progress->setTotalSteps(0);
|
|
|
|
m_progress->setFixedHeight(fontMetrics().height()+2);
|
|
|
|
m_progress->hide();
|
|
|
|
m_statusBar->addWidget(m_progress, 0, true);
|
|
|
|
|
|
|
|
KPushButton* closeButton = new KPushButton(KStdGuiItem::close(), bottombox);
|
|
|
|
connect(closeButton, TQT_SIGNAL(clicked()), TQT_SLOT(slotClose()));
|
|
|
|
|
|
|
|
connect(m_timer, TQT_SIGNAL(timeout()), TQT_SLOT(slotMoveProgress()));
|
|
|
|
|
|
|
|
setMinimumWidth(TQMAX(minimumWidth(), FETCH_MIN_WIDTH));
|
|
|
|
setStatus(i18n("Ready."));
|
|
|
|
|
|
|
|
resize(configDialogSize(TQString::fromLatin1("Fetch Dialog Options")));
|
|
|
|
|
|
|
|
TDEConfigGroup config(kapp->config(), "Fetch Dialog Options");
|
|
|
|
TQValueList<int> splitList = config.readIntListEntry("Splitter Sizes");
|
|
|
|
if(!splitList.empty()) {
|
|
|
|
split->setSizes(splitList);
|
|
|
|
}
|
|
|
|
|
|
|
|
connect(Fetch::Manager::self(), TQT_SIGNAL(signalResultFound(Tellico::Fetch::SearchResult*)),
|
|
|
|
TQT_SLOT(slotResultFound(Tellico::Fetch::SearchResult*)));
|
|
|
|
connect(Fetch::Manager::self(), TQT_SIGNAL(signalStatus(const TQString&)),
|
|
|
|
TQT_SLOT(slotStatus(const TQString&)));
|
|
|
|
connect(Fetch::Manager::self(), TQT_SIGNAL(signalDone()),
|
|
|
|
TQT_SLOT(slotFetchDone()));
|
|
|
|
|
|
|
|
// make sure to delete results afterwards
|
|
|
|
m_results.setAutoDelete(true);
|
|
|
|
|
|
|
|
TDEAcceleratorManager::manage(this);
|
|
|
|
// initialize combos
|
|
|
|
TQTimer::singleShot(0, this, TQT_SLOT(slotInit()));
|
|
|
|
|
|
|
|
#ifdef ENABLE_WEBCAM
|
|
|
|
// barcode recognition
|
|
|
|
m_barcodeRecognitionThread = new barcodeRecognitionThread();
|
|
|
|
if (m_barcodeRecognitionThread->isWebcamAvailable()) {
|
|
|
|
m_barcodePreview = new TQLabel(0);
|
|
|
|
m_barcodePreview->move( TQApplication::desktop()->width() - 350, 30 );
|
|
|
|
m_barcodePreview->setAutoResize( true );
|
|
|
|
m_barcodePreview->show();
|
|
|
|
} else {
|
|
|
|
m_barcodePreview = 0;
|
|
|
|
}
|
|
|
|
connect( m_barcodeRecognitionThread, TQT_SIGNAL(recognized(TQString)), this, TQT_SLOT(slotBarcodeRecognized(TQString)) );
|
|
|
|
connect( m_barcodeRecognitionThread, TQT_SIGNAL(gotImage(TQImage&)), this, TQT_SLOT(slotBarcodeGotImage(TQImage&)) );
|
|
|
|
m_barcodeRecognitionThread->start();
|
|
|
|
/* //DEBUG
|
|
|
|
TQImage img( "/home/sebastian/white.png", "PNG" );
|
|
|
|
m_barcodeRecognitionThread->recognizeBarcode( img );*/
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
FetchDialog::~FetchDialog() {
|
|
|
|
#ifdef ENABLE_WEBCAM
|
|
|
|
m_barcodeRecognitionThread->stop();
|
|
|
|
if (!m_barcodeRecognitionThread->wait( 1000 ))
|
|
|
|
m_barcodeRecognitionThread->terminate();
|
|
|
|
delete m_barcodeRecognitionThread;
|
|
|
|
if (m_barcodePreview)
|
|
|
|
delete m_barcodePreview;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// we might have downloaded a lot of images we don't need to keep
|
|
|
|
Data::EntryVec entriesToCheck;
|
|
|
|
for(TQMap<int, Data::EntryPtr>::Iterator it = m_entries.begin(); it != m_entries.end(); ++it) {
|
|
|
|
entriesToCheck.append(it.data());
|
|
|
|
}
|
|
|
|
// no additional entries to check images to keep though
|
|
|
|
Data::Document::self()->removeImagesNotInCollection(entriesToCheck, Data::EntryVec());
|
|
|
|
|
|
|
|
saveDialogSize(TQString::fromLatin1("Fetch Dialog Options"));
|
|
|
|
|
|
|
|
TDEConfigGroup config(kapp->config(), "Fetch Dialog Options");
|
|
|
|
config.writeEntry("Splitter Sizes", static_cast<TQSplitter*>(m_listView->parentWidget())->sizes());
|
|
|
|
config.writeEntry("Search Key", m_keyCombo->currentData().toInt());
|
|
|
|
config.writeEntry("Search Source", m_sourceCombo->currentText());
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotSearchClicked() {
|
|
|
|
m_valueLineEdit->selectAll();
|
|
|
|
if(m_started) {
|
|
|
|
setStatus(i18n("Cancelling the search..."));
|
|
|
|
Fetch::Manager::self()->stop();
|
|
|
|
slotFetchDone();
|
|
|
|
} else {
|
|
|
|
TQString value = m_valueLineEdit->text().simplifyWhiteSpace();
|
|
|
|
if(value != m_oldSearch) {
|
|
|
|
m_listView->clear();
|
|
|
|
m_entryView->clear();
|
|
|
|
}
|
|
|
|
m_resultCount = 0;
|
|
|
|
m_oldSearch = value;
|
|
|
|
m_started = true;
|
|
|
|
m_searchButton->setGuiItem(KGuiItem(i18n(FETCH_STRING_STOP),
|
|
|
|
SmallIconSet(TQString::fromLatin1("cancel"))));
|
|
|
|
startProgress();
|
|
|
|
setStatus(i18n("Searching..."));
|
|
|
|
kapp->processEvents();
|
|
|
|
Fetch::Manager::self()->startSearch(m_sourceCombo->currentText(),
|
|
|
|
static_cast<Fetch::FetchKey>(m_keyCombo->currentData().toInt()),
|
|
|
|
value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotClearClicked() {
|
|
|
|
slotFetchDone(false);
|
|
|
|
m_listView->clear();
|
|
|
|
m_entryView->clear();
|
|
|
|
Fetch::Manager::self()->stop();
|
|
|
|
m_multipleISBN->setChecked(false);
|
|
|
|
m_valueLineEdit->clear();
|
|
|
|
m_valueLineEdit->setFocus();
|
|
|
|
m_addButton->setEnabled(false);
|
|
|
|
m_moreButton->setEnabled(false);
|
|
|
|
m_isbnList.clear();
|
|
|
|
m_statusMessages.clear();
|
|
|
|
setStatus(i18n("Ready.")); // because slotFetchDone() writes text
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotStatus(const TQString& status_) {
|
|
|
|
m_statusMessages.push_back(status_);
|
|
|
|
// if the queue was empty, start the timer
|
|
|
|
if(m_statusMessages.count() == 1) {
|
|
|
|
// wait 2 seconds
|
|
|
|
TQTimer::singleShot(2000, this, TQT_SLOT(slotUpdateStatus()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotUpdateStatus() {
|
|
|
|
if(m_statusMessages.isEmpty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
setStatus(m_statusMessages.front());
|
|
|
|
m_statusMessages.pop_front();
|
|
|
|
if(!m_statusMessages.isEmpty()) {
|
|
|
|
// wait 2 seconds
|
|
|
|
TQTimer::singleShot(2000, this, TQT_SLOT(slotUpdateStatus()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::setStatus(const TQString& text_) {
|
|
|
|
m_statusBar->changeItem(TQChar(' ') + text_, FETCH_STATUS_ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotFetchDone(bool checkISBN /* = true */) {
|
|
|
|
// myDebug() << "FetchDialog::slotFetchDone()" << endl;
|
|
|
|
m_started = false;
|
|
|
|
m_searchButton->setGuiItem(KGuiItem(i18n(FETCH_STRING_SEARCH),
|
|
|
|
SmallIconSet(TQString::fromLatin1("edit-find"))));
|
|
|
|
stopProgress();
|
|
|
|
if(m_resultCount == 0) {
|
|
|
|
slotStatus(i18n("The search returned no items."));
|
|
|
|
} else {
|
|
|
|
/* TRANSLATORS: This is a plural form, you need to translate both lines (except "_n: ") */
|
|
|
|
slotStatus(i18n("The search returned 1 item.",
|
|
|
|
"The search returned %n items.",
|
|
|
|
m_resultCount));
|
|
|
|
}
|
|
|
|
m_moreButton->setEnabled(Fetch::Manager::self()->hasMoreResults());
|
|
|
|
|
|
|
|
// if we're not checking isbn values, then, ok to return
|
|
|
|
if(!checkISBN) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Fetch::FetchKey key = static_cast<Fetch::FetchKey>(m_keyCombo->currentData().toInt());
|
|
|
|
// no way to currently check EAN/UPC values for non-book items
|
|
|
|
if(m_collType & (Data::Collection::Book | Data::Collection::Bibtex) &&
|
|
|
|
m_multipleISBN->isChecked() &&
|
|
|
|
(key == Fetch::ISBN || key == Fetch::UPC)) {
|
|
|
|
TQStringList values = TQStringList::split(TQString::fromLatin1("; "),
|
|
|
|
m_oldSearch.simplifyWhiteSpace());
|
|
|
|
for(TQStringList::Iterator it = values.begin(); it != values.end(); ++it) {
|
|
|
|
*it = ISBNValidator::cleanValue(*it);
|
|
|
|
}
|
|
|
|
for(TQListViewItemIterator it(m_listView); it.current(); ++it) {
|
|
|
|
TQString i = ISBNValidator::cleanValue(static_cast<SearchResultItem*>(it.current())->m_result->isbn);
|
|
|
|
values.remove(i);
|
|
|
|
if(i.length() > 10 && i.startsWith(TQString::fromLatin1("978"))) {
|
|
|
|
values.remove(ISBNValidator::cleanValue(ISBNValidator::isbn10(i)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!values.isEmpty()) {
|
|
|
|
for(TQStringList::Iterator it = values.begin(); it != values.end(); ++it) {
|
|
|
|
ISBNValidator::staticFixup(*it);
|
|
|
|
}
|
|
|
|
// TODO dialog caption
|
|
|
|
KDialogBase* dlg = new KDialogBase(this, "isbn not found dialog", false, TQString(), KDialogBase::Ok);
|
|
|
|
TQWidget* box = new TQWidget(dlg);
|
|
|
|
TQVBoxLayout* lay = new TQVBoxLayout(box, KDialog::marginHint(), KDialog::spacingHint()*2);
|
|
|
|
TQHBoxLayout* lay2 = new TQHBoxLayout(lay);
|
|
|
|
TQLabel* lab = new TQLabel(box);
|
|
|
|
lab->setPixmap(TDEGlobal::iconLoader()->loadIcon(TQString::fromLatin1("messagebox_info"),
|
|
|
|
TDEIcon::NoGroup,
|
|
|
|
TDEIcon::SizeMedium));
|
|
|
|
lay2->addWidget(lab);
|
|
|
|
TQString s = i18n("No results were found for the following ISBN values:");
|
|
|
|
lay2->addWidget(new TQLabel(s, box), 10);
|
|
|
|
KTextEdit* edit = new KTextEdit(box, "isbn list edit");
|
|
|
|
lay->addWidget(edit);
|
|
|
|
edit->setText(values.join(TQChar('\n')));
|
|
|
|
TQWhatsThis::add(edit, s);
|
|
|
|
connect(dlg, TQT_SIGNAL(okClicked()), dlg, TQT_SLOT(deleteLater()));
|
|
|
|
dlg->setMainWidget(box);
|
|
|
|
dlg->setMinimumWidth(TQMAX(dlg->minimumWidth(), FETCH_MIN_WIDTH*2/3));
|
|
|
|
dlg->show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotResultFound(Tellico::Fetch::SearchResult* result_) {
|
|
|
|
m_results.append(result_);
|
|
|
|
(void) new SearchResultItem(m_listView, result_);
|
|
|
|
++m_resultCount;
|
|
|
|
adjustColumnWidth();
|
|
|
|
kapp->processEvents();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotAddEntry() {
|
|
|
|
GUI::CursorSaver cs;
|
|
|
|
Data::EntryVec vec;
|
|
|
|
for(TQListViewItemIterator it(m_listView, TQListViewItemIterator::Selected); it.current(); ++it) {
|
|
|
|
SearchResultItem* item = static_cast<SearchResultItem*>(it.current());
|
|
|
|
|
|
|
|
Fetch::SearchResult* r = item->m_result;
|
|
|
|
Data::EntryPtr entry = m_entries[r->uid];
|
|
|
|
if(!entry) {
|
|
|
|
setStatus(i18n("Fetching %1...").arg(r->title));
|
|
|
|
startProgress();
|
|
|
|
entry = r->fetchEntry();
|
|
|
|
if(!entry) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
m_entries.insert(r->uid, entry);
|
|
|
|
stopProgress();
|
|
|
|
setStatus(i18n("Ready."));
|
|
|
|
}
|
|
|
|
// add a copy, intentionally allowing multiple copies to be added
|
|
|
|
vec.append(new Data::Entry(*entry));
|
|
|
|
item->setPixmap(0, UserIcon(TQString::fromLatin1("checkmark")));
|
|
|
|
}
|
|
|
|
if(!vec.isEmpty()) {
|
|
|
|
Kernel::self()->addEntries(vec, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotMoreClicked() {
|
|
|
|
if(m_started) {
|
|
|
|
myDebug() << "FetchDialog::slotMoreClicked() - can't continue while running" << endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_started = true;
|
|
|
|
m_searchButton->setGuiItem(KGuiItem(i18n(FETCH_STRING_STOP),
|
|
|
|
SmallIconSet(TQString::fromLatin1("cancel"))));
|
|
|
|
startProgress();
|
|
|
|
setStatus(i18n("Searching..."));
|
|
|
|
kapp->processEvents();
|
|
|
|
Fetch::Manager::self()->continueSearch();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotShowEntry() {
|
|
|
|
// just in case
|
|
|
|
m_statusMessages.clear();
|
|
|
|
|
|
|
|
const GUI::ListViewItemList& items = m_listView->selectedItems();
|
|
|
|
if(items.isEmpty()) {
|
|
|
|
m_addButton->setEnabled(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_addButton->setEnabled(true);
|
|
|
|
if(items.count() > 1) {
|
|
|
|
m_entryView->clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SearchResultItem* item = static_cast<SearchResultItem*>(items.getFirst());
|
|
|
|
Fetch::SearchResult* r = item->m_result;
|
|
|
|
setStatus(i18n("Fetching %1...").arg(r->title));
|
|
|
|
Data::EntryPtr entry = m_entries[r->uid];
|
|
|
|
if(!entry) {
|
|
|
|
GUI::CursorSaver cs;
|
|
|
|
startProgress();
|
|
|
|
entry = r->fetchEntry();
|
|
|
|
if(entry) { // might conceivably be null
|
|
|
|
m_entries.insert(r->uid, entry);
|
|
|
|
}
|
|
|
|
stopProgress();
|
|
|
|
}
|
|
|
|
setStatus(i18n("Ready."));
|
|
|
|
|
|
|
|
m_entryView->showEntry(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::startProgress() {
|
|
|
|
m_progress->show();
|
|
|
|
m_timer->start(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotMoveProgress() {
|
|
|
|
m_progress->setProgress(m_progress->progress()+5);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::stopProgress() {
|
|
|
|
m_timer->stop();
|
|
|
|
m_progress->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotInit() {
|
|
|
|
if(!Fetch::Manager::self()->canFetch()) {
|
|
|
|
m_searchButton->setEnabled(false);
|
|
|
|
Kernel::self()->sorry(i18n("No Internet sources are available for your current collection type."), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
TDEConfigGroup config(kapp->config(), "Fetch Dialog Options");
|
|
|
|
int key = config.readNumEntry("Search Key", Fetch::FetchFirst);
|
|
|
|
// only change key if valid
|
|
|
|
if(key > Fetch::FetchFirst) {
|
|
|
|
m_keyCombo->setCurrentData(key);
|
|
|
|
}
|
|
|
|
slotKeyChanged(m_keyCombo->currentItem());
|
|
|
|
|
|
|
|
TQString source = config.readEntry("Search Source");
|
|
|
|
if(!source.isEmpty()) {
|
|
|
|
m_sourceCombo->setCurrentItem(source);
|
|
|
|
}
|
|
|
|
slotSourceChanged(m_sourceCombo->currentText());
|
|
|
|
|
|
|
|
m_valueLineEdit->setFocus();
|
|
|
|
m_searchButton->setDefault(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotKeyChanged(int idx_) {
|
|
|
|
int key = m_keyCombo->data(idx_).toInt();
|
|
|
|
if(key == Fetch::ISBN || key == Fetch::UPC || key == Fetch::LCCN) {
|
|
|
|
m_multipleISBN->setEnabled(true);
|
|
|
|
if(key == Fetch::ISBN) {
|
|
|
|
m_valueLineEdit->setValidator(new ISBNValidator(TQT_TQOBJECT(this)));
|
|
|
|
} else {
|
|
|
|
UPCValidator* upc = new UPCValidator(TQT_TQOBJECT(this));
|
|
|
|
connect(upc, TQT_SIGNAL(signalISBN()), TQT_SLOT(slotUPC2ISBN()));
|
|
|
|
m_valueLineEdit->setValidator(upc);
|
|
|
|
// only want to convert to ISBN if ISBN is accepted by the fetcher
|
|
|
|
Fetch::KeyMap map = Fetch::Manager::self()->keyMap(m_sourceCombo->currentText());
|
|
|
|
upc->setCheckISBN(map.contains(Fetch::ISBN));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m_multipleISBN->setChecked(false);
|
|
|
|
m_multipleISBN->setEnabled(false);
|
|
|
|
// slotMultipleISBN(false);
|
|
|
|
m_valueLineEdit->setValidator(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotSourceChanged(const TQString& source_) {
|
|
|
|
int curr = m_keyCombo->currentData().toInt();
|
|
|
|
m_keyCombo->clear();
|
|
|
|
Fetch::KeyMap map = Fetch::Manager::self()->keyMap(source_);
|
|
|
|
for(Fetch::KeyMap::ConstIterator it = map.begin(); it != map.end(); ++it) {
|
|
|
|
m_keyCombo->insertItem(it.data(), it.key());
|
|
|
|
}
|
|
|
|
m_keyCombo->setCurrentData(curr);
|
|
|
|
slotKeyChanged(m_keyCombo->currentItem());
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotMultipleISBN(bool toggle_) {
|
|
|
|
bool wasEnabled = m_valueLineEdit->isEnabled();
|
|
|
|
m_valueLineEdit->setEnabled(!toggle_);
|
|
|
|
if(!wasEnabled && m_valueLineEdit->isEnabled()) {
|
|
|
|
// if we enable it, it probably had multiple isbn values
|
|
|
|
// the validator doesn't like that, so only keep the first value
|
|
|
|
TQString val = m_valueLineEdit->text().section(';', 0, 0);
|
|
|
|
m_valueLineEdit->setText(val);
|
|
|
|
}
|
|
|
|
m_editISBN->setEnabled(toggle_);
|
|
|
|
if(toggle_) {
|
|
|
|
// if we're editing multiple values, it makes sense to popup the dialog now
|
|
|
|
slotEditMultipleISBN();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotEditMultipleISBN() {
|
|
|
|
KDialogBase dlg(this, "isbn edit dialog", true, i18n("Edit ISBN/UPC Values"),
|
|
|
|
KDialogBase::Ok|KDialogBase::Cancel);
|
|
|
|
TQVBox* box = new TQVBox(&dlg);
|
|
|
|
box->setSpacing(10);
|
|
|
|
TQString s = i18n("<qt>Enter the ISBN or UPC values, one per line.</qt>");
|
|
|
|
(void) new TQLabel(s, box);
|
|
|
|
m_isbnTextEdit = new KTextEdit(box, "isbn text edit");
|
|
|
|
m_isbnTextEdit->setText(m_isbnList.join(TQChar('\n')));
|
|
|
|
TQWhatsThis::add(m_isbnTextEdit, s);
|
Bring filenew, fileopen, fileprint, filequickprint, filesave, filesaveas, fileclose, editclear, editcopy, editcut, editdelete, editpaste, folder_new, and gohome icons into XDG compliance
10 years ago
|
|
|
KPushButton* fromFileBtn = new KPushButton(SmallIconSet(TQString::fromLatin1("document-open")),
|
|
|
|
i18n("&Load From File..."), box);
|
|
|
|
TQWhatsThis::add(fromFileBtn, i18n("<qt>Load the list from a text file.</qt>"));
|
|
|
|
connect(fromFileBtn, TQT_SIGNAL(clicked()), TQT_SLOT(slotLoadISBNList()));
|
|
|
|
dlg.setMainWidget(box);
|
|
|
|
dlg.setMinimumWidth(TQMAX(dlg.minimumWidth(), FETCH_MIN_WIDTH*2/3));
|
|
|
|
|
|
|
|
if(dlg.exec() == TQDialog::Accepted) {
|
|
|
|
m_isbnList = TQStringList::split('\n', m_isbnTextEdit->text());
|
|
|
|
const TQValidator* val = m_valueLineEdit->validator();
|
|
|
|
if(val) {
|
|
|
|
for(TQStringList::Iterator it = m_isbnList.begin(); it != m_isbnList.end(); ++it) {
|
|
|
|
val->fixup(*it);
|
|
|
|
if((*it).isEmpty()) {
|
|
|
|
it = m_isbnList.remove(it);
|
|
|
|
// this is next item, shift backward
|
|
|
|
--it;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(m_isbnList.count() > 100) {
|
|
|
|
Kernel::self()->sorry(i18n("<qt>An ISBN search can contain a maximum of 100 ISBN values. Only the "
|
|
|
|
"first 100 values in your list will be used.</qt>"), this);
|
|
|
|
}
|
|
|
|
while(m_isbnList.count() > 100) {
|
|
|
|
m_isbnList.pop_back();
|
|
|
|
}
|
|
|
|
m_valueLineEdit->setText(m_isbnList.join(TQString::fromLatin1("; ")));
|
|
|
|
}
|
|
|
|
m_isbnTextEdit = 0; // gets auto-deleted
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotLoadISBNList() {
|
|
|
|
if(!m_isbnTextEdit) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
KURL u = KFileDialog::getOpenURL(TQString(), TQString(), this);
|
|
|
|
if(u.isValid()) {
|
|
|
|
m_isbnTextEdit->setText(m_isbnTextEdit->text() + FileHandler::readTextFile(u));
|
|
|
|
m_isbnTextEdit->moveCursor(TQTextEdit::MoveEnd, false);
|
|
|
|
m_isbnTextEdit->scrollToBottom();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotUPC2ISBN() {
|
|
|
|
int key = m_keyCombo->currentData().toInt();
|
|
|
|
if(key == Fetch::UPC) {
|
|
|
|
m_keyCombo->setCurrentData(Fetch::ISBN);
|
|
|
|
slotKeyChanged(m_keyCombo->currentItem());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FetchDialog::eventFilter(TQObject* obj_, TQEvent* ev_) {
|
|
|
|
if(TQT_BASE_OBJECT(obj_) == TQT_BASE_OBJECT(m_listView->viewport()) && ev_->type() == TQEvent::Resize) {
|
|
|
|
adjustColumnWidth();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::adjustColumnWidth() {
|
|
|
|
if(!m_listView || m_listView->childCount() == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sum1 = 0;
|
|
|
|
int sum2 = 0;
|
|
|
|
int w3 = 0;
|
|
|
|
for(TQListViewItemIterator it(m_listView); it.current(); ++it) {
|
|
|
|
sum1 += it.current()->width(m_listView->fontMetrics(), m_listView, 1);
|
|
|
|
sum2 += it.current()->width(m_listView->fontMetrics(), m_listView, 2);
|
|
|
|
w3 = TQMAX(w3, it.current()->width(m_listView->fontMetrics(), m_listView, 3));
|
|
|
|
}
|
|
|
|
// try to be smart about column width
|
|
|
|
// column 0 is fixed, the checkmark icon, give it 20
|
|
|
|
const int w0 = 20;
|
|
|
|
// column 3 is the source, say max is 25% of viewport
|
|
|
|
const int vw = m_listView->visibleWidth();
|
|
|
|
w3 = static_cast<int>(TQMIN(1.1 * w3, 0.25 * vw));
|
|
|
|
// scale averages of col 1 and col 2
|
|
|
|
const int avg1 = sum1 / m_listView->childCount();
|
|
|
|
const int avg2 = sum2 / m_listView->childCount();
|
|
|
|
const int w2 = (vw - w0 - w3) * avg2 / (avg1 + avg2);
|
|
|
|
const int w1 = vw - w0 - w3 - w2;
|
|
|
|
m_listView->setColumnWidth(1, w1);
|
|
|
|
m_listView->setColumnWidth(2, w2);
|
|
|
|
m_listView->setColumnWidth(3, w3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotResetCollection() {
|
|
|
|
if(m_collType == Kernel::self()->collectionType()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_collType = Kernel::self()->collectionType();
|
|
|
|
m_sourceCombo->clear();
|
|
|
|
Fetch::FetcherVec sources = Fetch::Manager::self()->fetchers(m_collType);
|
|
|
|
for(Fetch::FetcherVec::Iterator it = sources.begin(); it != sources.end(); ++it) {
|
|
|
|
m_sourceCombo->insertItem(Fetch::Manager::self()->fetcherIcon(it.data()), (*it).source());
|
|
|
|
}
|
|
|
|
|
|
|
|
m_addButton->setIconSet(UserIconSet(Kernel::self()->collectionTypeName()));
|
|
|
|
|
|
|
|
if(Fetch::Manager::self()->canFetch()) {
|
|
|
|
m_searchButton->setEnabled(true);
|
|
|
|
} else {
|
|
|
|
m_searchButton->setEnabled(false);
|
|
|
|
Kernel::self()->sorry(i18n("No Internet sources are available for your current collection type."), this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotBarcodeRecognized( TQString string )
|
|
|
|
{
|
|
|
|
// attention: this slot is called in the context of another thread => do not use GUI-functions!
|
|
|
|
TQCustomEvent *e = new TQCustomEvent( TQEvent::User );
|
|
|
|
TQString *data = new TQString( string );
|
|
|
|
e->setData( data );
|
|
|
|
tqApp->postEvent( this, e ); // the event loop will call FetchDialog::customEvent() in the context of the GUI thread
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::slotBarcodeGotImage( TQImage &img )
|
|
|
|
{
|
|
|
|
// attention: this slot is called in the context of another thread => do not use GUI-functions!
|
|
|
|
TQCustomEvent *e = new TQCustomEvent( TQEvent::User+1 );
|
|
|
|
TQImage *data = new TQImage( img.copy() );
|
|
|
|
e->setData( data );
|
|
|
|
tqApp->postEvent( this, e ); // the event loop will call FetchDialog::customEvent() in the context of the GUI thread
|
|
|
|
}
|
|
|
|
|
|
|
|
void FetchDialog::customEvent( TQCustomEvent *e )
|
|
|
|
{
|
|
|
|
if (!e)
|
|
|
|
return;
|
|
|
|
if ((e->type() == TQEvent::User) && e->data()) {
|
|
|
|
// slotBarcodeRecognized() queued call
|
|
|
|
TQString temp = *(TQString*)(e->data());
|
|
|
|
delete (TQString*)(e->data());
|
|
|
|
tqApp->beep();
|
|
|
|
m_valueLineEdit->setText( temp );
|
|
|
|
m_searchButton->animateClick();
|
|
|
|
}
|
|
|
|
if ((e->type() == TQEvent::User+1) && e->data()) {
|
|
|
|
// slotBarcodegotImage() queued call
|
|
|
|
TQImage temp = *(TQImage*)(e->data());
|
|
|
|
delete (TQImage*)(e->data());
|
|
|
|
m_barcodePreview->setPixmap( temp );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "fetchdialog.moc"
|