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

kopete/kopete

  • sources
  • kde-4.12
  • kdenetwork
  • kopete
  • kopete
  • chatwindow
kopetechatwindowstylemanager.cpp
Go to the documentation of this file.
1  /*
2  kopetechatwindowstylemanager.cpp - Manager all chat window styles
3 
4  Copyright (c) 2005 by MichaĆ«l Larouche <larouche@kde.org>
5 
6  Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
7 
8  *************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  *************************************************************************
16 */
17 
18 #include "kopetechatwindowstylemanager.h"
19 
20 // Qt includes
21 #include <QStack>
22 #include <QFileInfo>
23 
24 // KDE includes
25 #include <kstandarddirs.h>
26 #include <kdirlister.h>
27 #include <kdebug.h>
28 #include <kurl.h>
29 #include <kglobal.h>
30 #include <karchive.h>
31 #include <kzip.h>
32 #include <ktar.h>
33 #include <kmimetype.h>
34 #include <kio/netaccess.h>
35 #include <ksharedconfig.h>
36 #include <kconfiggroup.h>
37 
38 #include "kopetechatwindowstyle.h"
39 
40 class ChatWindowStyleManager::Private
41 {
42 public:
43  Private()
44  : styleDirLister(0)
45  {}
46 
47  ~Private()
48  {
49  if(styleDirLister)
50  {
51  styleDirLister->deleteLater();
52  }
53 
54  qDeleteAll(stylePool);
55  }
56 
57  KDirLister *styleDirLister;
58  QStringList availableStyles;
59 
60  // key = style name, value = ChatWindowStyle instance
61  QHash<QString, ChatWindowStyle*> stylePool;
62 
63  QStack<KUrl> styleDirs;
64 };
65 
66 ChatWindowStyleManager *ChatWindowStyleManager::self()
67 {
68  static ChatWindowStyleManager s;
69  return &s;
70 }
71 
72 ChatWindowStyleManager::ChatWindowStyleManager(QObject *parent)
73  : QObject(parent), d(new Private())
74 {
75  kDebug(14000) ;
76  loadStyles();
77 }
78 
79 ChatWindowStyleManager::~ChatWindowStyleManager()
80 {
81  kDebug(14000) ;
82  delete d;
83 }
84 
85 void ChatWindowStyleManager::loadStyles()
86 {
87  // Make sure there exists a directory where chat styles can be installed to and it will be watched for changes
88  KStandardDirs::locateLocal( "appdata", QLatin1String( "styles/" ) );
89 
90  QStringList chatStyles = KGlobal::dirs()->findDirs( "appdata", QLatin1String( "styles" ) );
91  foreach(const QString &styleDir, chatStyles)
92  {
93  kDebug(14000) << styleDir;
94  d->styleDirs.push( KUrl(styleDir) );
95  }
96 
97  d->styleDirLister = new KDirLister(this);
98  d->styleDirLister->setDirOnlyMode(true);
99 
100  connect(d->styleDirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewStyles(KFileItemList)));
101  connect(d->styleDirLister, SIGNAL(completed()), this, SLOT(slotDirectoryFinished()));
102 
103  if( !d->styleDirs.isEmpty() )
104  d->styleDirLister->openUrl(d->styleDirs.pop(), KDirLister::Keep);
105 }
106 
107 QStringList ChatWindowStyleManager::getAvailableStyles() const
108 {
109  return d->availableStyles;
110 }
111 
112 int ChatWindowStyleManager::installStyle(const QString &styleBundlePath)
113 {
114  QString localStyleDir;
115  QStringList chatStyles = KGlobal::dirs()->findDirs( "appdata", QLatin1String( "styles" ) );
116  // findDirs returns preferred paths first, let's check if one of them is writable
117  foreach(const QString& styleDir, chatStyles)
118  {
119  if(QFileInfo(styleDir).isWritable())
120  {
121  localStyleDir = styleDir;
122  break;
123  }
124  }
125  if( localStyleDir.isEmpty() ) // none of dirs is writable
126  {
127  return StyleNoDirectoryValid;
128  }
129 
130  KArchiveEntry *currentEntry = 0L;
131  KArchiveDirectory* currentDir = 0L;
132  KArchive *archive = 0L;
133 
134  // Find mimetype for current bundle. ZIP and KTar need separate constructor
135  QString currentBundleMimeType = KMimeType::findByPath(styleBundlePath, 0, false)->name();
136  if(currentBundleMimeType == "application/zip")
137  {
138  archive = new KZip(styleBundlePath);
139  }
140  else if( currentBundleMimeType == "application/x-compressed-tar" || currentBundleMimeType == "application/x-bzip-compressed-tar" || currentBundleMimeType == "application/x-gzip" || currentBundleMimeType == "application/x-bzip" )
141  {
142  archive = new KTar(styleBundlePath);
143  }
144  else
145  {
146  return StyleCannotOpen;
147  }
148 
149  if ( !archive->open(QIODevice::ReadOnly) )
150  {
151  delete archive;
152 
153  return StyleCannotOpen;
154  }
155 
156  const KArchiveDirectory* rootDir = archive->directory();
157 
158  // Ok where we go to check if the archive is valid.
159  // Each time we found a correspondance to a theme bundle, we add a point to validResult.
160  // A valid style bundle must have:
161  // -a Contents, Contents/Resources, Co/Res/Incoming, Co/Res/Outgoing dirs
162  // main.css, Footer.html, Header.html, Status.html files in Contents/Resources.
163  // So for a style bundle to be valid, it must have a result greather than 8, because we test for 8 required entry.
164  int validResult = 0;
165  const QStringList entries = rootDir->entries();
166  // Will be reused later.
167  QStringList::ConstIterator entriesIt;
168  for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
169  {
170  currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
171 // kDebug() << "Current entry name: " << currentEntry->name();
172  if (currentEntry->isDirectory())
173  {
174  currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
175  if (currentDir)
176  {
177  if( currentDir->entry(QString::fromUtf8("Contents")) )
178  {
179 // kDebug() << "Contents found";
180  validResult += 1;
181  }
182  if( currentDir->entry(QString::fromUtf8("Contents/Resources")) )
183  {
184 // kDebug() << "Contents/Resources found";
185  validResult += 1;
186  }
187  if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming")) )
188  {
189 // kDebug() << "Contents/Resources/Incoming found";
190  validResult += 1;
191  }
192  if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing")) )
193  {
194 // kDebug() << "Contents/Resources/Outgoing found";
195  validResult += 1;
196  }
197  if( currentDir->entry(QString::fromUtf8("Contents/Resources/main.css")) )
198  {
199 // kDebug() << "Contents/Resources/main.css found";
200  validResult += 1;
201  }
202  if( currentDir->entry(QString::fromUtf8("Contents/Resources/Footer.html")) )
203  {
204 // kDebug() << "Contents/Resources/Footer.html found";
205  validResult += 1;
206  }
207  if( currentDir->entry(QString::fromUtf8("Contents/Resources/Status.html")) )
208  {
209 // kDebug() << "Contents/Resources/Status.html found";
210  validResult += 1;
211  }
212  if( currentDir->entry(QString::fromUtf8("Contents/Resources/Header.html")) )
213  {
214 // kDebug() << "Contents/Resources/Header.html found";
215  validResult += 1;
216  }
217  if( currentDir->entry(QString::fromUtf8("Contents/Resources/Incoming/Content.html")) )
218  {
219 // kDebug() << "Contents/Resources/Incoming/Content.html found";
220  validResult += 1;
221  }
222  if( currentDir->entry(QString::fromUtf8("Contents/Resources/Outgoing/Content.html")) )
223  {
224 // kDebug() << "Contents/Resources/Outgoing/Content.html found";
225  validResult += 1;
226  }
227  }
228  }
229  }
230 // kDebug() << "Valid result: " << QString::number(validResult);
231  // The archive is a valid style bundle.
232  if(validResult >= 8)
233  {
234  bool installOk = false;
235  for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
236  {
237  currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
238  if(currentEntry && currentEntry->isDirectory())
239  {
240  // Ignore this MacOS X "garbage" directory in zip.
241  if(currentEntry->name() == QString::fromUtf8("__MACOSX"))
242  {
243  continue;
244  }
245  else
246  {
247  currentDir = dynamic_cast<KArchiveDirectory*>(currentEntry);
248  if(currentDir)
249  {
250  currentDir->copyTo(localStyleDir + currentDir->name());
251  installOk = true;
252  }
253  }
254  }
255  }
256 
257  archive->close();
258  delete archive;
259 
260  if(installOk)
261  return StyleInstallOk;
262  else
263  return StyleUnknow;
264  }
265  else
266  {
267  archive->close();
268  delete archive;
269 
270  return StyleNotValid;
271  }
272 
273  if(archive)
274  {
275  archive->close();
276  delete archive;
277  }
278 
279  return StyleUnknow;
280 }
281 
282 bool ChatWindowStyleManager::removeStyle(const QString &styleName)
283 {
284  kDebug(14000) << styleName;
285  // Find for the current style in avaiableStyles map.
286  int foundStyleIdx = d->availableStyles.indexOf(styleName);
287 
288  if(foundStyleIdx != -1)
289  {
290  d->availableStyles.removeAt(foundStyleIdx);
291 
292  // Remove and delete style from pool if needed.
293  if( d->stylePool.contains(styleName) )
294  {
295  ChatWindowStyle *deletedStyle = d->stylePool[styleName];
296  d->stylePool.remove(styleName);
297  delete deletedStyle;
298  }
299 
300  QStringList styleDirs = KGlobal::dirs()->findDirs("appdata", QString("styles/%1").arg(styleName));
301  if(styleDirs.isEmpty())
302  {
303  kDebug(14000) << "Failed to find style" << styleName;
304  return false;
305  }
306 
307  // attempt to delete all dirs with this style
308  int numDeleted = 0;
309  foreach( const QString& stylePath, styleDirs )
310  {
311  KUrl urlStyle(stylePath);
312  // Do the actual deletion of the directory style.
313  if(KIO::NetAccess::del( urlStyle, 0 ))
314  numDeleted++;
315  }
316  return numDeleted == styleDirs.count();
317  }
318  else
319  {
320  return false;
321  }
322 }
323 
324 ChatWindowStyle *ChatWindowStyleManager::getValidStyleFromPool(const QString &styleName)
325 {
326  ChatWindowStyle *style = 0;
327  style = getStyleFromPool( styleName );
328  if ( style )
329  return style;
330 
331  kDebug(14000) << "Trying default style";
332  // Try default style
333  style = getStyleFromPool( "Kopete" );
334  if ( style )
335  return style;
336 
337  kDebug(14000) << "Trying first valid style";
338  // Try first valid style
339  foreach ( const QString& name, d->availableStyles )
340  {
341  style = getStyleFromPool( name );
342  if ( style )
343  return style;
344  }
345 
346  kDebug(14000) << "Valid style not found!";
347  return 0;
348 }
349 
350 ChatWindowStyle *ChatWindowStyleManager::getStyleFromPool(const QString &styleName)
351 {
352  if( d->stylePool.contains(styleName) )
353  {
354  kDebug(14000) << styleName << " was on the pool";
355 
356  // NOTE: This is a hidden config switch for style developers
357  // Check in the config if the cache is disabled.
358  // if the cache is disabled, reload the style every time it's getted.
359  KConfigGroup config(KGlobal::config(), "KopeteStyleDebug");
360  bool disableCache = config.readEntry("disableStyleCache", false);
361  if(disableCache)
362  {
363  d->stylePool[styleName]->reload();
364  }
365 
366  return d->stylePool[styleName];
367  }
368 
369  // Build a chat window style and list its variants, then add it to the pool.
370  ChatWindowStyle *style = new ChatWindowStyle(styleName, ChatWindowStyle::StyleBuildNormal);
371  if ( !style->isValid() )
372  {
373  kDebug(14000) << styleName << " is invalid style!";
374  delete style;
375  return 0;
376  }
377 
378  d->stylePool.insert(styleName, style);
379  kDebug(14000) << styleName << " is just created";
380 
381  return style;
382 }
383 
384 void ChatWindowStyleManager::slotNewStyles(const KFileItemList &dirList)
385 {
386  foreach(const KFileItem &item, dirList)
387  {
388  // Ignore data dir(from deprecated XSLT themes)
389  if( !item.url().fileName().contains(QString::fromUtf8("data")) )
390  {
391  kDebug(14000) << "Listing: " << item.url().fileName();
392  // If the style path is already in the pool, that's mean the style was updated on disk
393  // Reload the style
394  QString styleName = item.url().fileName();
395  if( d->stylePool.contains(styleName) )
396  {
397  kDebug(14000) << "Updating style: " << styleName;
398 
399  d->stylePool[styleName]->reload();
400 
401  // Add to avaialble if required.
402  if( d->availableStyles.indexOf(styleName) == -1 )
403  d->availableStyles.append(styleName);
404  }
405  else
406  {
407  // TODO: Use name from Info.plist
408  d->availableStyles.append(styleName);
409  }
410  }
411  }
412 }
413 
414 void ChatWindowStyleManager::slotDirectoryFinished()
415 {
416  // Start another scanning if the directories stack is not empty
417  if( !d->styleDirs.isEmpty() )
418  {
419  kDebug(14000) << "Starting another directory.";
420  d->styleDirLister->openUrl(d->styleDirs.pop(), KDirLister::Keep);
421  }
422  else
423  {
424  emit loadStylesFinished();
425  }
426 }
427 
428 #include "kopetechatwindowstylemanager.moc"
ChatWindowStyle
This class represent a single chat window style.
Definition: kopetechatwindowstyle.h:30
ChatWindowStyleManager::self
static ChatWindowStyleManager * self()
Singleton access to this class.
Definition: kopetechatwindowstylemanager.cpp:66
ChatWindowStyleManager::StyleInstallOk
Definition: kopetechatwindowstylemanager.h:58
kopetechatwindowstylemanager.h
ChatWindowStyleManager::StyleNoDirectoryValid
Definition: kopetechatwindowstylemanager.h:58
ChatWindowStyleManager::loadStyles
void loadStyles()
List all availables styles.
Definition: kopetechatwindowstylemanager.cpp:85
ChatWindowStyleManager::StyleNotValid
Definition: kopetechatwindowstylemanager.h:58
kopetechatwindowstyle.h
ChatWindowStyleManager::installStyle
int installStyle(const QString &styleBundlePath)
Install a new style into user style directory Note that you must pass a path to a archive...
Definition: kopetechatwindowstylemanager.cpp:112
QObject
ChatWindowStyleManager::removeStyle
bool removeStyle(const QString &styleName)
Remove a style from user style directory.
Definition: kopetechatwindowstylemanager.cpp:282
ChatWindowStyleManager::StyleCannotOpen
Definition: kopetechatwindowstylemanager.h:58
ChatWindowStyle::isValid
bool isValid() const
Checks if the style is valid.
Definition: kopetechatwindowstyle.cpp:99
ChatWindowStyleManager::getStyleFromPool
ChatWindowStyle * getStyleFromPool(const QString &styleName)
Get a instance of a ChatWindowStyle from the pool.
Definition: kopetechatwindowstylemanager.cpp:350
ChatWindowStyleManager::loadStylesFinished
void loadStylesFinished()
This signal is emitted when all styles finished to list.
ChatWindowStyleManager::getAvailableStyles
QStringList getAvailableStyles() const
Get all available styles.
Definition: kopetechatwindowstylemanager.cpp:107
ChatWindowStyleManager::StyleUnknow
Definition: kopetechatwindowstylemanager.h:58
ChatWindowStyleManager::getValidStyleFromPool
ChatWindowStyle * getValidStyleFromPool(const QString &styleName)
Get a instance of a ChatWindowStyle from the pool.
Definition: kopetechatwindowstylemanager.cpp:324
ChatWindowStyleManager::~ChatWindowStyleManager
~ChatWindowStyleManager()
Destructor.
Definition: kopetechatwindowstylemanager.cpp:79
ChatWindowStyleManager
Sigleton class that handle Chat Window styles.
Definition: kopetechatwindowstylemanager.h:46
ChatWindowStyle::StyleBuildNormal
Definition: kopetechatwindowstyle.h:46
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:53:40 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kopete/kopete

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

kdenetwork API Reference

Skip menu "kdenetwork API Reference"
  • kget
  • kopete
  •   kopete
  •   libkopete
  • krdc
  • krfb

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