You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/kopete/chatwindow/kopetechatwindowstylemanage...

391 lines
11 KiB

/*
kopetechatwindowstylemanager.cpp - Manager all chat window styles
Copyright (c) 2005 by Michaël Larouche <michael.larouche@kdemail.net>
Kopete (c) 2002-2005 by the Kopete developers <kopete-devel@kde.org>
*************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
*************************************************************************
*/
#include "kopetechatwindowstylemanager.h"
// TQt includes
#include <tqvaluestack.h>
// KDE includes
#include <kstandarddirs.h>
#include <kdirlister.h>
#include <kdebug.h>
#include <kurl.h>
#include <kglobal.h>
#include <karchive.h>
#include <kzip.h>
#include <ktar.h>
#include <kmimetype.h>
#include <kio/netaccess.h>
#include <kstaticdeleter.h>
#include <kconfig.h>
#include <kglobal.h>
#include "kopetechatwindowstyle.h"
class ChatWindowStyleManager::Private
{
public:
Private()
: styleDirLister(0)
{}
~Private()
{
if(styleDirLister)
{
styleDirLister->deleteLater();
}
TQMap<TQString, ChatWindowStyle*>::Iterator styleIt, styleItEnd = stylePool.end();
for(styleIt = stylePool.begin(); styleIt != styleItEnd; ++styleIt)
{
delete styleIt.data();
}
}
KDirLister *styleDirLister;
StyleList availableStyles;
// key = style path, value = ChatWindowStyle instance
TQMap<TQString, ChatWindowStyle*> stylePool;
TQValueStack<KURL> styleDirs;
};
static KStaticDeleter<ChatWindowStyleManager> ChatWindowStyleManagerstaticDeleter;
ChatWindowStyleManager *ChatWindowStyleManager::s_self = 0;
ChatWindowStyleManager *ChatWindowStyleManager::self()
{
if( !s_self )
{
ChatWindowStyleManagerstaticDeleter.setObject( s_self, new ChatWindowStyleManager() );
}
return s_self;
}
ChatWindowStyleManager::ChatWindowStyleManager(TQObject *parent, const char *name)
: TQObject(parent, name), d(new Private())
{
kdDebug(14000) << k_funcinfo << endl;
loadStyles();
}
ChatWindowStyleManager::~ChatWindowStyleManager()
{
kdDebug(14000) << k_funcinfo << endl;
delete d;
}
void ChatWindowStyleManager::loadStyles()
{
TQStringList chatStyles = TDEGlobal::dirs()->findDirs( "appdata", TQString::fromUtf8( "styles" ) );
TQString localStyleDir( locateLocal( "appdata", TQString::fromUtf8("styles/"),true) );
if( !chatStyles.contains(localStyleDir))
chatStyles<<localStyleDir;
TQStringList::const_iterator it;
for(it = chatStyles.constBegin(); it != chatStyles.constEnd(); ++it)
{
kdDebug(14000) << k_funcinfo << *it << endl;
d->styleDirs.push( KURL(*it) );
}
d->styleDirLister = new KDirLister(this);
d->styleDirLister->setDirOnlyMode(true);
connect(d->styleDirLister, TQT_SIGNAL(newItems(const KFileItemList &)), this, TQT_SLOT(slotNewStyles(const KFileItemList &)));
connect(d->styleDirLister, TQT_SIGNAL(completed()), this, TQT_SLOT(slotDirectoryFinished()));
if( !d->styleDirs.isEmpty() )
d->styleDirLister->openURL(d->styleDirs.pop(), true);
}
ChatWindowStyleManager::StyleList ChatWindowStyleManager::getAvailableStyles()
{
return d->availableStyles;
}
int ChatWindowStyleManager::installStyle(const TQString &styleBundlePath)
{
TQString localStyleDir( locateLocal( "appdata", TQString::fromUtf8("styles/") ) );
KArchiveEntry *currentEntry = 0L;
KArchiveDirectory* currentDir = 0L;
KArchive *archive = 0L;
if( localStyleDir.isEmpty() )
{
return StyleNoDirectoryValid;
}
// Find mimetype for current bundle. ZIP and KTar need separate constructor
TQString currentBundleMimeType = KMimeType::findByPath(styleBundlePath, 0, false)->name();
if(currentBundleMimeType == "application/x-zip")
{
archive = new KZip(styleBundlePath);
}
else if( currentBundleMimeType == "application/x-tgz" || currentBundleMimeType == "application/x-tbz" || currentBundleMimeType == "application/x-gzip" || currentBundleMimeType == "application/x-bzip2" )
{
archive = new KTar(styleBundlePath);
}
else
{
return StyleCannotOpen;
}
if ( !archive->open(IO_ReadOnly) )
{
delete archive;
return StyleCannotOpen;
}
const KArchiveDirectory* rootDir = archive->directory();
// Ok where we go to check if the archive is valid.
// Each time we found a correspondance to a theme bundle, we add a point to validResult.
// A valid style bundle must have:
// -a Contents, Contents/Resources, Co/Res/Incoming, Co/Res/Outgoing dirs
// main.css, Footer.html, Header.html, Status.html files in Contents/Ressources.
// So for a style bundle to be valid, it must have a result greather than 8, because we test for 8 required entry.
int validResult = 0;
TQStringList entries = rootDir->entries();
// Will be reused later.
TQStringList::Iterator entriesIt, entriesItEnd = entries.end();
for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
{
currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
// kdDebug() << k_funcinfo << "Current entry name: " << currentEntry->name() << endl;
if (currentEntry->isDirectory())
{
currentDir = dynamic_cast<KArchiveDirectory*>( currentEntry );
if (currentDir)
{
if( currentDir->entry(TQString::fromUtf8("Contents")) )
{
// kdDebug() << k_funcinfo << "Contents found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/Incoming")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/Incoming found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/Outgoing")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/Outgoing found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/main.css")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/main.css found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/Footer.html")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/Footer.html found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/Status.html")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/Status.html found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/Header.html")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/Header.html found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/Incoming/Content.html")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/Incoming/Content.html found" << endl;
validResult += 1;
}
if( currentDir->entry(TQString::fromUtf8("Contents/Resources/Outgoing/Content.html")) )
{
// kdDebug() << k_funcinfo << "Contents/Resources/Outgoing/Content.html found" << endl;
validResult += 1;
}
}
}
}
// kdDebug() << k_funcinfo << "Valid result: " << TQString::number(validResult) << endl;
// The archive is a valid style bundle.
if(validResult >= 8)
{
bool installOk = false;
for(entriesIt = entries.begin(); entriesIt != entries.end(); ++entriesIt)
{
currentEntry = const_cast<KArchiveEntry*>(rootDir->entry(*entriesIt));
if(currentEntry && currentEntry->isDirectory())
{
// Ignore this MacOS X "garbage" directory in zip.
if(currentEntry->name() == TQString::fromUtf8("__MACOSX"))
{
continue;
}
else
{
currentDir = dynamic_cast<KArchiveDirectory*>(currentEntry);
if(currentDir)
{
currentDir->copyTo(localStyleDir + currentDir->name());
installOk = true;
}
}
}
}
archive->close();
delete archive;
if(installOk)
return StyleInstallOk;
else
return StyleUnknow;
}
else
{
archive->close();
delete archive;
return StyleNotValid;
}
if(archive)
{
archive->close();
delete archive;
}
return StyleUnknow;
}
bool ChatWindowStyleManager::removeStyle(const TQString &stylePath)
{
// Find for the current style in avaiableStyles map.
KURL urlStyle(stylePath);
TQString styleName=urlStyle.fileName();
StyleList::Iterator foundStyle = d->availableStyles.find(styleName);
// TQMap iterator return end() if it found no item.
if(foundStyle != d->availableStyles.end())
{
d->availableStyles.remove(foundStyle);
// Remove and delete style from pool if needed.
if( d->stylePool.contains(stylePath) )
{
ChatWindowStyle *deletedStyle = d->stylePool[stylePath];
d->stylePool.remove(stylePath);
delete deletedStyle;
}
// Do the actual deletion of the directory style.
return TDEIO::NetAccess::del( urlStyle, 0 );
}
else
{
return false;
}
}
ChatWindowStyle *ChatWindowStyleManager::getStyleFromPool(const TQString &stylePath)
{
if( d->stylePool.contains(stylePath) )
{
// NOTE: This is a hidden config switch for style developers
// Check in the config if the cache is disabled.
// if the cache is disabled, reload the style everytime it's getted.
TDEConfig *config = TDEGlobal::config();
config->setGroup("KopeteStyleDebug");
bool disableCache = config->readBoolEntry("disableStyleCache", false);
if(disableCache)
{
d->stylePool[stylePath]->reload();
}
return d->stylePool[stylePath];
}
else
{
// Build a chat window style and list its variants, then add it to the pool.
ChatWindowStyle *style = new ChatWindowStyle(stylePath, ChatWindowStyle::StyleBuildNormal);
d->stylePool.insert(stylePath, style);
return style;
}
return 0;
}
void ChatWindowStyleManager::slotNewStyles(const KFileItemList &dirList)
{
KFileItem *item;
TQPtrListIterator<KFileItem> it( dirList );
while( (item = it.current()) != 0 )
{
// Ignore data dir(from deprecated XSLT themes)
if( !item->url().fileName().contains(TQString::fromUtf8("data")) )
{
kdDebug(14000) << k_funcinfo << "Listing: " << item->url().fileName() << endl;
// If the style path is already in the pool, that's mean the style was updated on disk
// Reload the style
if( d->stylePool.contains(item->url().path()) )
{
kdDebug(14000) << k_funcinfo << "Updating style: " << item->url().path() << endl;
d->stylePool[item->url().path()]->reload();
// Add to avaialble if required.
if( !d->availableStyles.contains(item->url().fileName()) )
d->availableStyles.insert(item->url().fileName(), item->url().path());
}
else
{
// TODO: Use name from Info.plist
d->availableStyles.insert(item->url().fileName(), item->url().path());
}
}
++it;
}
}
void ChatWindowStyleManager::slotDirectoryFinished()
{
// Start another scanning if the directories stack is not empty
if( !d->styleDirs.isEmpty() )
{
kdDebug(14000) << k_funcinfo << "Starting another directory." << endl;
d->styleDirLister->openURL(d->styleDirs.pop(), true);
}
else
{
emit loadStylesFinished();
}
}
#include "kopetechatwindowstylemanager.moc"