~paulbrianstewart/ubuntu/oneiric/tellico/852247-Formatting-Fix

« back to all changes in this revision

Viewing changes to src/fetch/gcstarpluginfetcher.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Stephan Hermann
  • Date: 2008-01-31 19:33:05 UTC
  • mfrom: (0.1.13 upstream)
  • Revision ID: james.westby@ubuntu.com-20080131193305-9l01m5gfhykl6pkl
Tags: 1.3-1ubuntu1
* Merge from debian unstable, remaining changes:
  - debian/control: build-dep on kdepim-dev
  - debian/control: drop versioned python from tellico-data suggests
  - debian/rules: call dh_icons

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
    copyright            : (C) 2005-2006 by Robby Stephenson
 
3
    email                : robby@periapsis.org
 
4
 ***************************************************************************/
 
5
 
 
6
/***************************************************************************
 
7
 *                                                                         *
 
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;                            *
 
11
 *                                                                         *
 
12
 ***************************************************************************/
 
13
 
 
14
#include "gcstarpluginfetcher.h"
 
15
#include "messagehandler.h"
 
16
#include "fetchmanager.h"
 
17
#include "../collection.h"
 
18
#include "../entry.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"
 
27
 
 
28
#include <kconfig.h>
 
29
#include <kprocess.h>
 
30
#include <kprocio.h>
 
31
#include <kstandarddirs.h>
 
32
#include <kaccelmanager.h>
 
33
 
 
34
#include <qdir.h>
 
35
#include <qlayout.h>
 
36
#include <qlabel.h>
 
37
#include <qwhatsthis.h>
 
38
 
 
39
using Tellico::Fetch::GCstarPluginFetcher;
 
40
 
 
41
GCstarPluginFetcher::PluginMap GCstarPluginFetcher::pluginMap;
 
42
GCstarPluginFetcher::PluginParse GCstarPluginFetcher::pluginParse = NotYet;
 
43
 
 
44
//static
 
45
GCstarPluginFetcher::PluginList GCstarPluginFetcher::plugins(int collType_) {
 
46
  if(!pluginMap.contains(collType_)) {
 
47
    GUI::CursorSaver cs;
 
48
    QString gcstar = KStandardDirs::findExe(QString::fromLatin1("gcstar"));
 
49
 
 
50
    if(pluginParse == NotYet) {
 
51
      KProcIO proc;
 
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)) {
 
55
        QString output;
 
56
        proc.readln(output);
 
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;
 
67
          }
 
68
        }
 
69
      }
 
70
      // if still zero, then we should use old in future
 
71
      if(pluginParse == NotYet) {
 
72
        pluginParse = Old;
 
73
      }
 
74
    }
 
75
 
 
76
    if(pluginParse == New) {
 
77
      readPluginsNew(collType_, gcstar);
 
78
    } else {
 
79
      readPluginsOld(collType_, gcstar);
 
80
    }
 
81
  }
 
82
 
 
83
  return pluginMap.contains(collType_) ? pluginMap[collType_] : GCstarPluginFetcher::PluginList();
 
84
}
 
85
 
 
86
void GCstarPluginFetcher::readPluginsNew(int collType_, const QString& gcstar_) {
 
87
  PluginList plugins;
 
88
 
 
89
  QString gcstarCollection = gcstarType(collType_);
 
90
  if(gcstarCollection.isEmpty()) {
 
91
    pluginMap.insert(collType_, plugins);
 
92
    return;
 
93
  }
 
94
 
 
95
  KProcIO proc;
 
96
  proc << gcstar_
 
97
        << QString::fromLatin1("-x")
 
98
        << QString::fromLatin1("--list-plugins")
 
99
        << QString::fromLatin1("--collection") << gcstarCollection;
 
100
 
 
101
  if(!proc.start(KProcess::Block)) {
 
102
    myWarning() << "GCstarPluginFetcher::readPluginsNew() - can't start" << endl;
 
103
    return;
 
104
  }
 
105
 
 
106
  bool hasName = false;
 
107
  PluginInfo info;
 
108
  QString line;
 
109
  for(int length = 0; length > -1; length = proc.readln(line)) {
 
110
    if(line.isEmpty()) {
 
111
      if(hasName) {
 
112
        plugins << info;
 
113
      }
 
114
      hasName = false;
 
115
      info.clear();
 
116
    } else {
 
117
      // authors have \t at beginning
 
118
      line = line.stripWhiteSpace();
 
119
      if(!hasName) {
 
120
        info.insert(QString::fromLatin1("name"), line);
 
121
        hasName = true;
 
122
      } else {
 
123
        info.insert(QString::fromLatin1("author"), line);
 
124
      }
 
125
//      myDebug() << line << endl;
 
126
    }
 
127
  }
 
128
 
 
129
  pluginMap.insert(collType_, plugins);
 
130
}
 
131
 
 
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/"));
 
135
 
 
136
  QRegExp rx(QString::fromLatin1("get(Name|Author|Lang)\\s*\\{\\s*return\\s+['\"](.+)['\"]"));
 
137
  rx.setMinimal(true);
 
138
 
 
139
  PluginList plugins;
 
140
 
 
141
  QString dirName = gcstarType(collType_);
 
142
  if(dirName.isEmpty()) {
 
143
    pluginMap.insert(collType_, plugins);
 
144
    return;
 
145
  }
 
146
 
 
147
  QStringList files = dir.entryList();
 
148
  for(QStringList::ConstIterator file = files.begin(); file != files.end(); ++file) {
 
149
    KURL u;
 
150
    u.setPath(dir.filePath(*file));
 
151
    PluginInfo info;
 
152
    QString text = FileHandler::readTextFile(u);
 
153
    for(int pos = rx.search(text);
 
154
        pos > -1;
 
155
        pos = rx.search(text, pos+rx.matchedLength())) {
 
156
      info.insert(rx.cap(1).lower(), rx.cap(2));
 
157
    }
 
158
    // only add if it has a name
 
159
    if(info.contains(QString::fromLatin1("name"))) {
 
160
      plugins << info;
 
161
    }
 
162
  }
 
163
  // inserting empty map is ok
 
164
  pluginMap.insert(collType_, plugins);
 
165
}
 
166
 
 
167
QString GCstarPluginFetcher::gcstarType(int collType_) {
 
168
  switch(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");
 
176
    default: break;
 
177
  }
 
178
  return QString();
 
179
}
 
180
 
 
181
GCstarPluginFetcher::GCstarPluginFetcher(QObject* parent_, const char* name_/*=0*/) : Fetcher(parent_, name_),
 
182
    m_started(false), m_collType(-1), m_process(0) {
 
183
}
 
184
 
 
185
GCstarPluginFetcher::~GCstarPluginFetcher() {
 
186
  stop();
 
187
}
 
188
 
 
189
QString GCstarPluginFetcher::defaultName() {
 
190
  return i18n("GCstar Plugin");
 
191
}
 
192
 
 
193
QString GCstarPluginFetcher::source() const {
 
194
  return m_name;
 
195
}
 
196
 
 
197
bool GCstarPluginFetcher::canFetch(int type_) const {
 
198
  return m_collType == -1 ? false : m_collType == type_;
 
199
}
 
200
 
 
201
void GCstarPluginFetcher::readConfigHook(const KConfigGroup& config_) {
 
202
  m_collType = config_.readNumEntry("CollectionType", -1);
 
203
  m_plugin = config_.readEntry("Plugin");
 
204
}
 
205
 
 
206
void GCstarPluginFetcher::search(FetchKey key_, const QString& value_) {
 
207
  m_started = true;
 
208
  m_data.truncate(0);
 
209
 
 
210
  if(key_ != Fetch::Title) {
 
211
    myDebug() << "GCstarPluginFetcher::search() - only Title searches are supported" << endl;
 
212
    stop();
 
213
    return;
 
214
  }
 
215
 
 
216
  QString gcstar = KStandardDirs::findExe(QString::fromLatin1("gcstar"));
 
217
  if(gcstar.isEmpty()) {
 
218
    myWarning() << "GCstarPluginFetcher::search() - gcstar not found!" << endl;
 
219
    stop();
 
220
    return;
 
221
  }
 
222
 
 
223
  QString gcstarCollection = gcstarType(m_collType);
 
224
 
 
225
  if(m_plugin.isEmpty()) {
 
226
    myWarning() << "GCstarPluginFetcher::search() - no plugin name! " << endl;
 
227
    stop();
 
228
    return;
 
229
  }
 
230
 
 
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*)));
 
235
  QStringList args;
 
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;
 
242
  *m_process << args;
 
243
  if(!m_process->start(KProcess::NotifyOnExit, KProcess::AllOutput)) {
 
244
    myDebug() << "GCstarPluginFetcher::startSearch() - process failed to start" << endl;
 
245
    stop();
 
246
  }
 
247
}
 
248
 
 
249
void GCstarPluginFetcher::stop() {
 
250
  if(!m_started) {
 
251
    return;
 
252
  }
 
253
  if(m_process) {
 
254
    m_process->kill();
 
255
    delete m_process;
 
256
    m_process = 0;
 
257
  }
 
258
  m_data.truncate(0);
 
259
  m_started = false;
 
260
  m_errors.clear();
 
261
  emit signalDone(this);
 
262
}
 
263
 
 
264
void GCstarPluginFetcher::slotData(KProcess*, char* buffer_, int len_) {
 
265
  QDataStream stream(m_data, IO_WriteOnly | IO_Append);
 
266
  stream.writeRawBytes(buffer_, len_);
 
267
}
 
268
 
 
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;
 
273
  m_errors << msg;
 
274
}
 
275
 
 
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);
 
282
    }
 
283
    stop();
 
284
    return;
 
285
  }
 
286
  if(!m_errors.isEmpty()) {
 
287
    message(m_errors.join(QChar('\n')), MessageHandler::Warning);
 
288
  }
 
289
 
 
290
  if(m_data.isEmpty()) {
 
291
    myDebug() << "GCstarPluginFetcher::slotProcessExited() - "<< source() << ": no data" << endl;
 
292
    stop();
 
293
    return;
 
294
  }
 
295
 
 
296
  Import::TellicoImporter imp(QString::fromUtf8(m_data, m_data.size()));
 
297
 
 
298
  Data::CollPtr coll = imp.collection();
 
299
  if(!coll) {
 
300
    if(!imp.statusMessage().isEmpty()) {
 
301
      message(imp.statusMessage(), MessageHandler::Status);
 
302
    }
 
303
    myDebug() << "GCstarPluginFetcher::slotProcessExited() - "<< source() << ": no collection pointer" << endl;
 
304
    stop();
 
305
    return;
 
306
  }
 
307
 
 
308
  Data::EntryVec entries = coll->entries();
 
309
  for(Data::EntryVec::Iterator entry = entries.begin(); entry != entries.end(); ++entry) {
 
310
    QString desc;
 
311
    switch(coll->type()) {
 
312
      case Data::Collection::Book:
 
313
      case Data::Collection::Bibtex:
 
314
        desc = entry->field(QString::fromLatin1("author"))
 
315
               + QChar('/')
 
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"));
 
321
        }
 
322
        break;
 
323
 
 
324
      case Data::Collection::Video:
 
325
        desc = entry->field(QString::fromLatin1("studio"))
 
326
               + QChar('/')
 
327
               + entry->field(QString::fromLatin1("director"))
 
328
               + QChar('/')
 
329
               + entry->field(QString::fromLatin1("year"))
 
330
               + QChar('/')
 
331
               + entry->field(QString::fromLatin1("medium"));
 
332
        break;
 
333
 
 
334
      case Data::Collection::Album:
 
335
        desc = entry->field(QString::fromLatin1("artist"))
 
336
               + QChar('/')
 
337
               + entry->field(QString::fromLatin1("label"))
 
338
               + QChar('/')
 
339
               + entry->field(QString::fromLatin1("year"));
 
340
        break;
 
341
 
 
342
      case Data::Collection::Game:
 
343
        desc = entry->field(QString::fromLatin1("platform"));
 
344
        break;
 
345
 
 
346
      case Data::Collection::ComicBook:
 
347
        desc = entry->field(QString::fromLatin1("publisher"))
 
348
               + QChar('/')
 
349
               + entry->field(QString::fromLatin1("pub_year"));
 
350
        break;
 
351
 
 
352
     case Data::Collection::BoardGame:
 
353
       desc = entry->field(QString::fromLatin1("designer"))
 
354
              + QChar('/')
 
355
              + entry->field(QString::fromLatin1("publisher"))
 
356
              + QChar('/')
 
357
              + entry->field(QString::fromLatin1("year"));
 
358
       break;
 
359
 
 
360
      default:
 
361
        break;
 
362
    }
 
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);
 
366
  }
 
367
  stop(); // be sure to call this
 
368
}
 
369
 
 
370
Tellico::Data::EntryPtr GCstarPluginFetcher::fetchEntry(uint uid_) {
 
371
  return m_entries[uid_];
 
372
}
 
373
 
 
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"));
 
377
  if(!t.isEmpty()) {
 
378
    search(Fetch::Title, t);
 
379
    return;
 
380
  }
 
381
 
 
382
  myDebug() << "GCstarPluginFetcher::updateEntry() - insufficient info to search" << endl;
 
383
  emit signalDone(this); // always need to emit this if not continuing with the search
 
384
}
 
385
 
 
386
Tellico::Fetch::ConfigWidget* GCstarPluginFetcher::configWidget(QWidget* parent_) const {
 
387
  return new GCstarPluginFetcher::ConfigWidget(parent_, this);
 
388
}
 
389
 
 
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);
 
393
  l->setSpacing(4);
 
394
  l->setColStretch(1, 10);
 
395
 
 
396
  int row = -1;
 
397
 
 
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);
 
408
 
 
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);
 
419
 
 
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);
 
424
 
 
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);
 
429
 
 
430
  if(fetcher_ && fetcher_->m_collType > -1) {
 
431
    m_collCombo->setCurrentType(fetcher_->m_collType);
 
432
  } else {
 
433
    m_collCombo->setCurrentType(Kernel::self()->collectionType());
 
434
  }
 
435
 
 
436
  if(fetcher_) {
 
437
    m_originalPluginName = fetcher_->m_plugin;
 
438
  }
 
439
 
 
440
  KAcceleratorManager::manage(optionsWidget());
 
441
}
 
442
 
 
443
GCstarPluginFetcher::ConfigWidget::~ConfigWidget() {
 
444
}
 
445
 
 
446
void GCstarPluginFetcher::ConfigWidget::saveConfig(KConfigGroup& config_) {
 
447
  config_.writeEntry("CollectionType", m_collCombo->currentType());
 
448
  config_.writeEntry("Plugin", m_pluginCombo->currentText());
 
449
}
 
450
 
 
451
QString GCstarPluginFetcher::ConfigWidget::preferredName() const {
 
452
  return QString::fromLatin1("GCstar - ") + m_pluginCombo->currentText();
 
453
}
 
454
 
 
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);
 
463
  }
 
464
  slotPluginChanged();
 
465
  emit signalName(preferredName());
 
466
}
 
467
 
 
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());
 
473
}
 
474
 
 
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);
 
481
      slotPluginChanged();
 
482
    }
 
483
  }
 
484
}
 
485
 
 
486
#include "gcstarpluginfetcher.moc"