1
/***************************************************************************
2
copyright : (C) 2005-2006 by Robby Stephenson
3
email : robby@periapsis.org
4
***************************************************************************/
6
/***************************************************************************
8
* This program is free software; you can redistribute it and/or modify *
9
* it under the terms of version 2 of the GNU General Public License as *
10
* published by the Free Software Foundation; *
12
***************************************************************************/
14
#include "gcstarpluginfetcher.h"
15
#include "messagehandler.h"
16
#include "fetchmanager.h"
17
#include "../collection.h"
19
#include "../translators/tellicoimporter.h"
20
#include "../gui/combobox.h"
21
#include "../gui/collectiontypecombo.h"
22
#include "../filehandler.h"
23
#include "../tellico_kernel.h"
24
#include "../tellico_debug.h"
25
#include "../latin1literal.h"
26
#include "../tellico_utils.h"
31
#include <kstandarddirs.h>
32
#include <kaccelmanager.h>
37
#include <qwhatsthis.h>
39
using Tellico::Fetch::GCstarPluginFetcher;
41
GCstarPluginFetcher::PluginMap GCstarPluginFetcher::pluginMap;
42
GCstarPluginFetcher::PluginParse GCstarPluginFetcher::pluginParse = NotYet;
45
GCstarPluginFetcher::PluginList GCstarPluginFetcher::plugins(int collType_) {
46
if(!pluginMap.contains(collType_)) {
48
QString gcstar = KStandardDirs::findExe(QString::fromLatin1("gcstar"));
50
if(pluginParse == NotYet) {
52
proc << gcstar << QString::fromLatin1("--version");
53
// wait 5 seconds at most, just a sanity thing, never want to block completely
54
if(proc.start(KProcess::Block) && proc.wait(5)) {
57
if(!output.isEmpty()) {
58
// always going to be x.y[.z] ?
59
QRegExp versionRx(QString::fromLatin1("(\\d+)\\.(\\d+)(?:\\.(\\d+))?"));
60
if(versionRx.search(output) > -1) {
61
int x = versionRx.cap(1).toInt();
62
int y = versionRx.cap(2).toInt();
63
int z = versionRx.cap(3).toInt(); // ok to be empty
64
myDebug() << QString::fromLatin1("GCstarPluginFetcher() - found %1.%2.%3").arg(x).arg(y).arg(z) << endl;
65
// --list-plugins argument was added for 1.3 release
66
pluginParse = (x >= 1 && y >=3) ? New : Old;
70
// if still zero, then we should use old in future
71
if(pluginParse == NotYet) {
76
if(pluginParse == New) {
77
readPluginsNew(collType_, gcstar);
79
readPluginsOld(collType_, gcstar);
83
return pluginMap.contains(collType_) ? pluginMap[collType_] : GCstarPluginFetcher::PluginList();
86
void GCstarPluginFetcher::readPluginsNew(int collType_, const QString& gcstar_) {
89
QString gcstarCollection = gcstarType(collType_);
90
if(gcstarCollection.isEmpty()) {
91
pluginMap.insert(collType_, plugins);
97
<< QString::fromLatin1("-x")
98
<< QString::fromLatin1("--list-plugins")
99
<< QString::fromLatin1("--collection") << gcstarCollection;
101
if(!proc.start(KProcess::Block)) {
102
myWarning() << "GCstarPluginFetcher::readPluginsNew() - can't start" << endl;
106
bool hasName = false;
109
for(int length = 0; length > -1; length = proc.readln(line)) {
117
// authors have \t at beginning
118
line = line.stripWhiteSpace();
120
info.insert(QString::fromLatin1("name"), line);
123
info.insert(QString::fromLatin1("author"), line);
125
// myDebug() << line << endl;
129
pluginMap.insert(collType_, plugins);
132
void GCstarPluginFetcher::readPluginsOld(int collType_, const QString& gcstar_) {
133
QDir dir(gcstar_, QString::fromLatin1("GC*.pm"));
134
dir.cd(QString::fromLatin1("../../lib/gcstar/GCPlugins/"));
136
QRegExp rx(QString::fromLatin1("get(Name|Author|Lang)\\s*\\{\\s*return\\s+['\"](.+)['\"]"));
141
QString dirName = gcstarType(collType_);
142
if(dirName.isEmpty()) {
143
pluginMap.insert(collType_, plugins);
147
QStringList files = dir.entryList();
148
for(QStringList::ConstIterator file = files.begin(); file != files.end(); ++file) {
150
u.setPath(dir.filePath(*file));
152
QString text = FileHandler::readTextFile(u);
153
for(int pos = rx.search(text);
155
pos = rx.search(text, pos+rx.matchedLength())) {
156
info.insert(rx.cap(1).lower(), rx.cap(2));
158
// only add if it has a name
159
if(info.contains(QString::fromLatin1("name"))) {
163
// inserting empty map is ok
164
pluginMap.insert(collType_, plugins);
167
QString GCstarPluginFetcher::gcstarType(int collType_) {
169
case Data::Collection::Book: return QString::fromLatin1("GCbooks");
170
case Data::Collection::Video: return QString::fromLatin1("GCfilms");
171
case Data::Collection::Game: return QString::fromLatin1("GCgames");
172
case Data::Collection::Album: return QString::fromLatin1("GCmusics");
173
case Data::Collection::Coin: return QString::fromLatin1("GCcoins");
174
case Data::Collection::Wine: return QString::fromLatin1("GCwines");
175
case Data::Collection::BoardGame: return QString::fromLatin1("GCboardgames");
181
GCstarPluginFetcher::GCstarPluginFetcher(QObject* parent_, const char* name_/*=0*/) : Fetcher(parent_, name_),
182
m_started(false), m_collType(-1), m_process(0) {
185
GCstarPluginFetcher::~GCstarPluginFetcher() {
189
QString GCstarPluginFetcher::defaultName() {
190
return i18n("GCstar Plugin");
193
QString GCstarPluginFetcher::source() const {
197
bool GCstarPluginFetcher::canFetch(int type_) const {
198
return m_collType == -1 ? false : m_collType == type_;
201
void GCstarPluginFetcher::readConfigHook(const KConfigGroup& config_) {
202
m_collType = config_.readNumEntry("CollectionType", -1);
203
m_plugin = config_.readEntry("Plugin");
206
void GCstarPluginFetcher::search(FetchKey key_, const QString& value_) {
210
if(key_ != Fetch::Title) {
211
myDebug() << "GCstarPluginFetcher::search() - only Title searches are supported" << endl;
216
QString gcstar = KStandardDirs::findExe(QString::fromLatin1("gcstar"));
217
if(gcstar.isEmpty()) {
218
myWarning() << "GCstarPluginFetcher::search() - gcstar not found!" << endl;
223
QString gcstarCollection = gcstarType(m_collType);
225
if(m_plugin.isEmpty()) {
226
myWarning() << "GCstarPluginFetcher::search() - no plugin name! " << endl;
231
m_process = new KProcess();
232
connect(m_process, SIGNAL(receivedStdout(KProcess*, char*, int)), SLOT(slotData(KProcess*, char*, int)));
233
connect(m_process, SIGNAL(receivedStderr(KProcess*, char*, int)), SLOT(slotError(KProcess*, char*, int)));
234
connect(m_process, SIGNAL(processExited(KProcess*)), SLOT(slotProcessExited(KProcess*)));
236
args << gcstar << QString::fromLatin1("-x")
237
<< QString::fromLatin1("--collection") << gcstarCollection
238
<< QString::fromLatin1("--export") << QString::fromLatin1("Tellico")
239
<< QString::fromLatin1("--website") << m_plugin
240
<< QString::fromLatin1("--download") << KProcess::quote(value_);
241
myLog() << "GCstarPluginFetcher::search() - " << args.join(QChar(' ')) << endl;
243
if(!m_process->start(KProcess::NotifyOnExit, KProcess::AllOutput)) {
244
myDebug() << "GCstarPluginFetcher::startSearch() - process failed to start" << endl;
249
void GCstarPluginFetcher::stop() {
261
emit signalDone(this);
264
void GCstarPluginFetcher::slotData(KProcess*, char* buffer_, int len_) {
265
QDataStream stream(m_data, IO_WriteOnly | IO_Append);
266
stream.writeRawBytes(buffer_, len_);
269
void GCstarPluginFetcher::slotError(KProcess*, char* buffer_, int len_) {
270
QString msg = QString::fromLocal8Bit(buffer_, len_);
271
msg.prepend(source() + QString::fromLatin1(": "));
272
myDebug() << "GCstarPluginFetcher::slotError() - " << msg << endl;
276
void GCstarPluginFetcher::slotProcessExited(KProcess*) {
277
// myDebug() << "GCstarPluginFetcher::slotProcessExited()" << endl;
278
if(!m_process->normalExit() || m_process->exitStatus()) {
279
myDebug() << "GCstarPluginFetcher::slotProcessExited() - "<< source() << ": process did not exit successfully" << endl;
280
if(!m_errors.isEmpty()) {
281
message(m_errors.join(QChar('\n')), MessageHandler::Error);
286
if(!m_errors.isEmpty()) {
287
message(m_errors.join(QChar('\n')), MessageHandler::Warning);
290
if(m_data.isEmpty()) {
291
myDebug() << "GCstarPluginFetcher::slotProcessExited() - "<< source() << ": no data" << endl;
296
Import::TellicoImporter imp(QString::fromUtf8(m_data, m_data.size()));
298
Data::CollPtr coll = imp.collection();
300
if(!imp.statusMessage().isEmpty()) {
301
message(imp.statusMessage(), MessageHandler::Status);
303
myDebug() << "GCstarPluginFetcher::slotProcessExited() - "<< source() << ": no collection pointer" << endl;
308
Data::EntryVec entries = coll->entries();
309
for(Data::EntryVec::Iterator entry = entries.begin(); entry != entries.end(); ++entry) {
311
switch(coll->type()) {
312
case Data::Collection::Book:
313
case Data::Collection::Bibtex:
314
desc = entry->field(QString::fromLatin1("author"))
316
+ entry->field(QString::fromLatin1("publisher"));
317
if(!entry->field(QString::fromLatin1("cr_year")).isEmpty()) {
318
desc += QChar('/') + entry->field(QString::fromLatin1("cr_year"));
319
} else if(!entry->field(QString::fromLatin1("pub_year")).isEmpty()){
320
desc += QChar('/') + entry->field(QString::fromLatin1("pub_year"));
324
case Data::Collection::Video:
325
desc = entry->field(QString::fromLatin1("studio"))
327
+ entry->field(QString::fromLatin1("director"))
329
+ entry->field(QString::fromLatin1("year"))
331
+ entry->field(QString::fromLatin1("medium"));
334
case Data::Collection::Album:
335
desc = entry->field(QString::fromLatin1("artist"))
337
+ entry->field(QString::fromLatin1("label"))
339
+ entry->field(QString::fromLatin1("year"));
342
case Data::Collection::Game:
343
desc = entry->field(QString::fromLatin1("platform"));
346
case Data::Collection::ComicBook:
347
desc = entry->field(QString::fromLatin1("publisher"))
349
+ entry->field(QString::fromLatin1("pub_year"));
352
case Data::Collection::BoardGame:
353
desc = entry->field(QString::fromLatin1("designer"))
355
+ entry->field(QString::fromLatin1("publisher"))
357
+ entry->field(QString::fromLatin1("year"));
363
SearchResult* r = new SearchResult(this, entry->title(), desc, entry->field(QString::fromLatin1("isbn")));
364
m_entries.insert(r->uid, entry);
365
emit signalResultFound(r);
367
stop(); // be sure to call this
370
Tellico::Data::EntryPtr GCstarPluginFetcher::fetchEntry(uint uid_) {
371
return m_entries[uid_];
374
void GCstarPluginFetcher::updateEntry(Data::EntryPtr entry_) {
375
// ry searching for title and rely on Collection::sameEntry() to figure things out
376
QString t = entry_->field(QString::fromLatin1("title"));
378
search(Fetch::Title, t);
382
myDebug() << "GCstarPluginFetcher::updateEntry() - insufficient info to search" << endl;
383
emit signalDone(this); // always need to emit this if not continuing with the search
386
Tellico::Fetch::ConfigWidget* GCstarPluginFetcher::configWidget(QWidget* parent_) const {
387
return new GCstarPluginFetcher::ConfigWidget(parent_, this);
390
GCstarPluginFetcher::ConfigWidget::ConfigWidget(QWidget* parent_, const GCstarPluginFetcher* fetcher_/*=0*/)
391
: Fetch::ConfigWidget(parent_), m_needPluginList(true) {
392
QGridLayout* l = new QGridLayout(optionsWidget(), 3, 4);
394
l->setColStretch(1, 10);
398
QLabel* label = new QLabel(i18n("Collection &type:"), optionsWidget());
399
l->addWidget(label, ++row, 0);
400
m_collCombo = new GUI::CollectionTypeCombo(optionsWidget());
401
connect(m_collCombo, SIGNAL(activated(int)), SLOT(slotSetModified()));
402
connect(m_collCombo, SIGNAL(activated(int)), SLOT(slotTypeChanged()));
403
l->addMultiCellWidget(m_collCombo, row, row, 1, 3);
404
QString w = i18n("Set the collection type of the data returned from the plugin.");
405
QWhatsThis::add(label, w);
406
QWhatsThis::add(m_collCombo, w);
407
label->setBuddy(m_collCombo);
409
label = new QLabel(i18n("&Plugin: "), optionsWidget());
410
l->addWidget(label, ++row, 0);
411
m_pluginCombo = new GUI::ComboBox(optionsWidget());
412
connect(m_pluginCombo, SIGNAL(activated(int)), SLOT(slotSetModified()));
413
connect(m_pluginCombo, SIGNAL(activated(int)), SLOT(slotPluginChanged()));
414
l->addMultiCellWidget(m_pluginCombo, row, row, 1, 3);
415
w = i18n("Select the GCstar plugin used for the data source.");
416
QWhatsThis::add(label, w);
417
QWhatsThis::add(m_pluginCombo, w);
418
label->setBuddy(m_pluginCombo);
420
label = new QLabel(i18n("Author: "), optionsWidget());
421
l->addWidget(label, ++row, 0);
422
m_authorLabel = new QLabel(optionsWidget());
423
l->addWidget(m_authorLabel, row, 1);
425
// label = new QLabel(i18n("Language: "), optionsWidget());
426
// l->addWidget(label, row, 2);
427
// m_langLabel = new QLabel(optionsWidget());
428
// l->addWidget(m_langLabel, row, 3);
430
if(fetcher_ && fetcher_->m_collType > -1) {
431
m_collCombo->setCurrentType(fetcher_->m_collType);
433
m_collCombo->setCurrentType(Kernel::self()->collectionType());
437
m_originalPluginName = fetcher_->m_plugin;
440
KAcceleratorManager::manage(optionsWidget());
443
GCstarPluginFetcher::ConfigWidget::~ConfigWidget() {
446
void GCstarPluginFetcher::ConfigWidget::saveConfig(KConfigGroup& config_) {
447
config_.writeEntry("CollectionType", m_collCombo->currentType());
448
config_.writeEntry("Plugin", m_pluginCombo->currentText());
451
QString GCstarPluginFetcher::ConfigWidget::preferredName() const {
452
return QString::fromLatin1("GCstar - ") + m_pluginCombo->currentText();
455
void GCstarPluginFetcher::ConfigWidget::slotTypeChanged() {
456
int collType = m_collCombo->currentType();
457
m_pluginCombo->clear();
458
QStringList pluginNames;
459
GCstarPluginFetcher::PluginList list = GCstarPluginFetcher::plugins(collType);
460
for(GCstarPluginFetcher::PluginList::ConstIterator it = list.begin(); it != list.end(); ++it) {
461
pluginNames << (*it)[QString::fromLatin1("name")].toString();
462
m_pluginCombo->insertItem(pluginNames.last(), *it);
465
emit signalName(preferredName());
468
void GCstarPluginFetcher::ConfigWidget::slotPluginChanged() {
469
PluginInfo info = m_pluginCombo->currentData().toMap();
470
m_authorLabel->setText(info[QString::fromLatin1("author")].toString());
471
// m_langLabel->setText(info[QString::fromLatin1("lang")].toString());
472
emit signalName(preferredName());
475
void GCstarPluginFetcher::ConfigWidget::showEvent(QShowEvent*) {
476
if(m_needPluginList) {
477
m_needPluginList = false;
478
slotTypeChanged(); // update plugin combo box
479
if(!m_originalPluginName.isEmpty()) {
480
m_pluginCombo->setCurrentText(m_originalPluginName);
486
#include "gcstarpluginfetcher.moc"