• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdepim API Reference
  • KDE Home
  • Contact Us
 

korganizer

  • sources
  • kde-4.12
  • kdepim
  • korganizer
  • plugins
  • picoftheday
picoftheday.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KOrganizer.
3  Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
4  Copyright (c) 2007 Loïc Corbasson <loic.corbasson@gmail.com>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License along
17  with this program; if not, write to the Free Software Foundation, Inc.,
18  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 
21 #include "picoftheday.h"
22 #include "configdialog.h"
23 
24 #include <KConfig>
25 #include <KDebug>
26 #include <KIO/Scheduler>
27 
28 #include <QDomDocument>
29 
30 class PicofthedayFactory : public DecorationFactory
31 {
32  public:
33  Decoration *createPluginFactory() { return new Picoftheday; }
34 };
35 
36 K_EXPORT_PLUGIN( PicofthedayFactory )
37 
38 Picoftheday::Picoftheday()
39 {
40  KConfig _config( QLatin1String("korganizerrc" ));
41  KConfigGroup config( &_config, "Picture of the Day Plugin" );
42  mThumbSize = config.readEntry( "InitialThumbnailSize", QSize( 120, 60 ) );
43 }
44 
45 Picoftheday::~Picoftheday()
46 {
47 }
48 
49 void Picoftheday::configure( QWidget *parent )
50 {
51  ConfigDialog dlg( parent );
52  dlg.exec();
53 }
54 
55 QString Picoftheday::info() const
56 {
57  return i18n( "<qt>This plugin provides the Wikipedia "
58  "<i>Picture of the Day</i>.</qt>" );
59 }
60 
61 Element::List Picoftheday::createDayElements( const QDate &date )
62 {
63  Element::List elements;
64 
65  POTDElement *element = new POTDElement( QLatin1String("main element"), date, mThumbSize );
66  elements.append( element );
67 
68  return elements;
69 }
70 
72 
73 POTDElement::POTDElement( const QString &id, const QDate &date,
74  const QSize &initialThumbSize )
75  : StoredElement( id ), mDate( date ), mThumbSize( initialThumbSize ),
76  mFirstStepCompleted( false ),
77  mSecondStepCompleted( false ),
78  mFirstStepJob( 0 ), mSecondStepJob( 0 ), mThirdStepJob( 0 )
79 {
80  setShortText( i18n( "Loading..." ) );
81  setLongText( i18n( "<qt>Loading <i>Picture of the Day</i>...</qt>" ) );
82 
83  mTimer = new QTimer( this );
84  mTimer->setSingleShot( true );
85 
86  step1StartDownload();
87 }
88 
90 void POTDElement::step1StartDownload()
91 {
92  // Start downloading the picture
93  if ( !mFirstStepCompleted && !mFirstStepJob ) {
94  KUrl url = KUrl( QLatin1String("http://en.wikipedia.org/w/index.php?title=Template:POTD/") +
95  mDate.toString( Qt::ISODate ) + QLatin1String("&action=raw") );
96  // The file at that URL contains the file name for the POTD
97 
98  mFirstStepJob = KIO::storedGet( url, KIO::NoReload, KIO::HideProgressInfo );
99  KIO::Scheduler::setJobPriority( mFirstStepJob, 1 );
100 
101  connect( mFirstStepJob, SIGNAL(result(KJob*)),
102  this, SLOT(step1Result(KJob*)) );
103  connect( this, SIGNAL(step1Success()),
104  this, SLOT(step2GetImagePage()) );
105  }
106 }
107 
112 void POTDElement::step1Result( KJob *job )
113 {
114  if ( job->error() ) {
115  kWarning() << "POTD:" << mDate << ": could not get POTD file name:" << job->errorString();
116  kDebug() << "POTD:" << mDate << ": file name:" << mFileName;
117  kDebug() << "POTD:" << mDate << ": full-size image:" << mFullSizeImageUrl.url();
118  kDebug() << "POTD:" << mDate << ": thumbnail:" << mThumbUrl.url();
119  mFirstStepCompleted = false;
120  return;
121  }
122 
123  // First step completed: we now know the POTD's file name
124  KIO::StoredTransferJob *const transferJob = static_cast<KIO::StoredTransferJob*>( job );
125  const QStringList lines =
126  QString::fromUtf8( transferJob->data().data(), transferJob->data().size() ).split( QLatin1Char('\n') );
127 
128  Q_FOREACH( const QString &line, lines ) {
129  if ( line.startsWith( QLatin1String("|image=") ) ) {
130  mFileName = line;
131  break;
132  }
133  }
134  mFileName = mFileName.remove( QLatin1String("|image=") ).replace( QLatin1Char(' '), QLatin1Char('_') );
135 
136  Q_FOREACH( const QString &line, lines ) {
137  if ( line.startsWith( QLatin1String("|texttitle=") ) ) {
138  mDescription = line;
139  break;
140  }
141  }
142  mDescription = mDescription.remove( QLatin1String("|texttitle=") );
143  if ( !mDescription.isEmpty() ) {
144  mLongText = mDescription;
145  } else {
146  mLongText = mFileName;
147  }
148  mLongText = i18n( "Wikipedia POTD: %1", mLongText );
149  emit gotNewLongText( mLongText );
150 
151  kDebug() << "FILENAME=" << mFileName;
152  kDebug() << "DESCRIPTION=" << mDescription;
153 
154  mFirstStepCompleted = true;
155  mFirstStepJob = 0;
156  emit step1Success();
157 }
158 
160 void POTDElement::step2GetImagePage()
161 {
162  if ( !mSecondStepCompleted && !mSecondStepJob ) {
163  mUrl = KUrl( QLatin1String("http://en.wikipedia.org/wiki/File:") + mFileName );
164  // We'll find the info to get the thumbnail we want on the POTD's image page
165 
166  emit gotNewUrl( mUrl );
167  mShortText = i18n( "Picture Page" );
168  emit gotNewShortText( mShortText );
169 
170  mSecondStepJob = KIO::storedGet( mUrl, KIO::NoReload, KIO::HideProgressInfo );
171  KIO::Scheduler::setJobPriority( mSecondStepJob, 1 );
172 
173  connect( mSecondStepJob, SIGNAL(result(KJob*)),
174  this, SLOT(step2Result(KJob*)) );
175  connect( this, SIGNAL(step2Success()), SLOT(step3GetThumbnail()) );
176  }
177 }
178 
183 void POTDElement::step2Result( KJob *job )
184 {
185  if ( job->error() ) {
186  kWarning() << "POTD:" << mDate << ": could not get POTD image page:" << job->errorString();
187  kDebug() << "POTD:" << mDate << ": file name:" << mFileName;
188  kDebug() << "POTD:" << mDate << ": full-size image:" << mFullSizeImageUrl.url();
189  kDebug() << "POTD:" << mDate << ": thumbnail:" << mThumbUrl.url();
190  mSecondStepCompleted = false;
191  return;
192  }
193 
194  // Get the image URL from the image page's source code
195  // and transform it to get an appropriate thumbnail size
196  KIO::StoredTransferJob *const transferJob = static_cast<KIO::StoredTransferJob*>( job );
197 
198  QDomDocument imgPage;
199  if ( !imgPage.setContent( QString::fromUtf8( transferJob->data().data(),
200  transferJob->data().size() ) ) ) {
201  kWarning() << "POTD:" << mDate << ": Wikipedia returned an invalid XML page for image"
202  << mFileName;
203  return;
204  }
205 
206  // We go through all links and stop at the first right-looking candidate
207  QDomNodeList links = imgPage.elementsByTagName( QLatin1String("a") );
208  for ( uint i=0; i<links.length(); ++i ) {
209  QString href = links.item(i).attributes().namedItem( QLatin1String("href") ).nodeValue();
210  if ( href.startsWith(
211  QLatin1String( "//upload.wikimedia.org/wikipedia/commons/" ) ) ) {
212  mFullSizeImageUrl = href;
213  break;
214  }
215  }
216 
217  // We get the image's width/height ratio
218  mHWRatio = 1.0;
219  QDomNodeList images = imgPage.elementsByTagName( QLatin1String("img") );
220  for ( uint i=0; i<links.length(); ++i ) {
221  QDomNamedNodeMap attr = images.item( i ).attributes();
222  QString src = attr.namedItem( QLatin1String("src") ).nodeValue();
223 
224  if ( src.startsWith( thumbnailUrl( mFullSizeImageUrl ).url() ) ) {
225  if ( ( attr.namedItem( QLatin1String("height") ).nodeValue().toInt() != 0 ) &&
226  ( attr.namedItem( QLatin1String("width") ).nodeValue().toInt() != 0 ) ) {
227  mHWRatio = attr.namedItem( QLatin1String("height") ).nodeValue().toFloat() /
228  attr.namedItem( QLatin1String("width") ).nodeValue().toFloat();
229  }
230  break;
231  }
232 
233  }
234  kDebug() << "POTD:" << mDate << ": h/w ratio:" << mHWRatio;
235  kDebug() << "POTD:" << mDate << ": got POTD image page source:" << mFullSizeImageUrl;
236 
237  if ( !mFullSizeImageUrl.isEmpty() ) {
238  mSecondStepCompleted = true;
239  mSecondStepJob = 0;
240  emit step2Success();
241  }
242 }
243 
244 KUrl POTDElement::thumbnailUrl( const KUrl &fullSizeUrl, const int width ) const
245 {
246  QString thumbUrl = fullSizeUrl.url();
247  if ( width != 0 ) {
248  thumbUrl.replace( QRegExp( QLatin1String("//upload.wikimedia.org/wikipedia/commons/(.*)/([^/]*)") ),
249  QLatin1String("//upload.wikimedia.org/wikipedia/commons/thumb/\\1/\\2/") +
250  QString::number( width ) + QLatin1String("px-\\2") );
251  } else { // This will not return a valid thumbnail URL, but will at least
252  // give some info (the beginning of the URL)
253  thumbUrl.replace( QRegExp( QLatin1String("//upload.wikimedia.org/wikipedia/commons/(.*)/([^/]*)") ),
254  QLatin1String("//upload.wikimedia.org/wikipedia/commons/thumb/\\1/\\2") );
255  }
256  thumbUrl.replace( QRegExp( QLatin1String("^file:////") ), QLatin1String("http://") );
257  return KUrl( thumbUrl );
258 }
259 
261 void POTDElement::step3GetThumbnail()
262 {
263  if ( mThirdStepJob ) {
264  mThirdStepJob->kill();
265  }
266  mThirdStepJob = 0;
267 
268  int thumbWidth = mThumbSize.width();
269  int thumbHeight = static_cast<int>( thumbWidth * mHWRatio );
270  if ( mThumbSize.height() < thumbHeight ) {
271  /* if the requested height is less than the requested width * ratio
272  we would download too much, as the downloaded picture would be
273  taller than requested, so we adjust the width of the picture to
274  be downloaded in consequence */
275  thumbWidth /= ( thumbHeight / mThumbSize.height() );
276  thumbHeight = static_cast<int>( thumbWidth * mHWRatio );
277  }
278  mDlThumbSize = QSize( thumbWidth, thumbHeight );
279  kDebug() << "POTD:" << mDate << ": will download thumbnail of size" << mDlThumbSize;
280  QString thumbUrl =
281  QUrl::fromPercentEncoding(
282  thumbnailUrl( mFullSizeImageUrl, thumbWidth ).url().toLatin1() );
283 
284  kDebug() << "POTD:" << mDate << ": got POTD thumbnail URL:" << thumbUrl;
285  mThumbUrl = thumbUrl;
286 
287  mThirdStepJob = KIO::storedGet( thumbUrl, KIO::NoReload, KIO::HideProgressInfo );
288  kDebug() << "POTD:" << mDate << ": get" << thumbUrl;//FIXME
289  KIO::Scheduler::setJobPriority( mThirdStepJob, 1 );
290 
291  connect( mThirdStepJob, SIGNAL(result(KJob*)),
292  this, SLOT(step3Result(KJob*)) );
293 }
294 
299 void POTDElement::step3Result( KJob *job )
300 {
301  if ( job != mThirdStepJob ) {
302  return;
303  }
304  mThirdStepJob = 0;
305 
306  if ( job->error() ) {
307  kWarning() << "POTD:" << mDate << ": could not get POTD:" << job->errorString();
308  kDebug() << "POTD:" << mDate << ": file name:" << mFileName;
309  kDebug() << "POTD:" << mDate << ": full-size image:" << mFullSizeImageUrl.url();
310  kDebug() << "POTD:" << mDate << ": thumbnail:" << mThumbUrl.url();
311  return;
312  }
313 
314  // Last step completed: we get the pixmap from the transfer job's data
315  KIO::StoredTransferJob* const transferJob = static_cast<KIO::StoredTransferJob*>( job );
316  if ( mPixmap.loadFromData( transferJob->data() ) ) {
317  kDebug() << "POTD:" << mDate << ": got POTD.";
318  emit gotNewPixmap( mPixmap.scaled( mThumbSize, Qt::KeepAspectRatio,
319  Qt::SmoothTransformation ) );
320  }
321 }
322 
323 QPixmap POTDElement::newPixmap( const QSize &size )
324 {
325  if ( ( mThumbSize.width() < size.width() ) || ( mThumbSize.height() < size.height() ) ) {
326  kDebug() << "POTD:" << mDate << ": called for a new pixmap size ("
327  << size << "instead of" << mThumbSize << ", stored pixmap:"
328  << mPixmap.size() << ")";
329  setThumbnailSize( size );
330 
331  if ( !mFirstStepCompleted ) {
332  step1StartDownload(); // First run, start from the beginning
333  } else if ( ( mDlThumbSize.width() < size.width() ) &&
334  ( mDlThumbSize.height() < size.height() ) ) {
335  if ( mThirdStepJob ) {
336  // Another download (for the old size) is already running;
337  // we'll run after that
338  disconnect( this, SIGNAL(step3Success()),
339  this, SLOT(step3GetThumbnail()) );
340  connect( this, SIGNAL(step3Success()), SLOT(step3GetThumbnail()) );
341  } else if ( mFirstStepJob || mSecondStepJob ) {
342  // The download process did not get to step 3 yet, and will download
343  // the correct size automagically
344  } else {
345  // We start a new thumbnail download a little later; the following code
346  // is to avoid too frequent transfers e.g. when resizing
347  mTimer->stop();
348  disconnect( mTimer, SIGNAL(timeout()),
349  this, SLOT(step3GetThumbnail()) );
350  connect( mTimer, SIGNAL(timeout()),
351  this, SLOT(step3GetThumbnail()) );
352  mTimer->setSingleShot( true );
353  mTimer->start( 1000 );
354  }
355  }
356  }
357 
358  /* else, either we already got a sufficiently big pixmap (stored in mPixmap),
359  or we will get one anytime soon (we are downloading it already) and we will
360  actualize what we return here later via gotNewPixmap */
361  if ( mPixmap.isNull() ) {
362  return QPixmap();
363  }
364  return mPixmap.scaled( size, Qt::KeepAspectRatio, Qt::SmoothTransformation );
365 }
366 
367 void POTDElement::setThumbnailSize( const QSize &size )
368 {
369  mThumbSize = size;
370 }
371 
372 #include "picoftheday.moc"
POTDElement
Definition: picoftheday.h:45
POTDElement::POTDElement
POTDElement(const QString &id, const QDate &date, const QSize &initialThumbSize)
Definition: picoftheday.cpp:73
picoftheday.h
QWidget
configdialog.h
POTDElement::step1StartDownload
void step1StartDownload()
First step of three in the download process.
Definition: picoftheday.cpp:90
POTDElement::step1Success
void step1Success() const
StoredElement
Picoftheday::configure
void configure(QWidget *parent)
Definition: picoftheday.cpp:49
POTDElement::gotNewShortText
void gotNewShortText(const QString &) const
ConfigDialog
Definition: datenums/configdialog.h:28
POTDElement::step3GetThumbnail
void step3GetThumbnail()
Third step of three in the downloading process.
Definition: picoftheday.cpp:261
POTDElement::gotNewPixmap
void gotNewPixmap(const QPixmap &) const
POTDElement::gotNewUrl
void gotNewUrl(const KUrl &) const
POTDElement::step2GetImagePage
void step2GetImagePage()
Second step of three in the download process.
Definition: picoftheday.cpp:160
Decoration
POTDElement::newPixmap
QPixmap newPixmap(const QSize &size)
Definition: picoftheday.cpp:323
POTDElement::gotNewLongText
void gotNewLongText(const QString &) const
K_EXPORT_PLUGIN
K_EXPORT_PLUGIN(KOrganizerFactory(createAboutData())) KOrganizerPart
Definition: korganizer_part.cpp:49
POTDElement::setThumbnailSize
void setThumbnailSize(const QSize &size)
Definition: picoftheday.cpp:367
POTDElement::step2Success
void step2Success() const
Picoftheday::info
QString info() const
Definition: picoftheday.cpp:55
Picoftheday::~Picoftheday
~Picoftheday()
Definition: picoftheday.cpp:45
POTDElement::thumbnailUrl
KUrl thumbnailUrl(const KUrl &fullSizeUrl, const int width=0) const
Returns the thumbnail URL for a given width corresponding to a full-size image URL.
Definition: picoftheday.cpp:244
KJob
POTDElement::step3Success
void step3Success() const
Picoftheday::createDayElements
Element::List createDayElements(const QDate &)
Definition: picoftheday.cpp:61
Picoftheday
Definition: picoftheday.h:29
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:56:19 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

korganizer

Skip menu "korganizer"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdepim API Reference

Skip menu "kdepim API Reference"
  • akonadi_next
  • akregator
  • blogilo
  • calendarsupport
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt2
  • kjots
  • kleopatra
  • kmail
  • knode
  • knotes
  • kontact
  • korgac
  • korganizer
  • ktimetracker
  • libkdepim
  • libkleo
  • libkpgp
  • mailcommon
  • messagelist
  • messageviewer

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal