themefile.cpp00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "themefile.h"
00025 #include "lineparser.h"
00026 #include "themelocale.h"
00027 #include <kdebug.h>
00028 #include <kurl.h>
00029 #include <kzip.h>
00030 #include <kapplication.h>
00031 #include <kmessagebox.h>
00032 #include <kstandarddirs.h>
00033 #include <klocale.h>
00034 #include <kio/netaccess.h>
00035 #include <qtextstream.h>
00036 #include <qfileinfo.h>
00037 #include <qdom.h>
00038 #include <qdir.h>
00039
00040 class ZipFile
00041 {
00042 public:
00043 ZipFile() :
00044 m_zip(0), m_file(0)
00045 {
00046 }
00047 void setFile(const QString& filename)
00048 {
00049 m_filename = filename;
00050 if(filename.isEmpty())
00051 return;
00052
00053 const KArchiveEntry* entry;
00054
00055 entry = m_dir->entry(filename);
00056 if(entry == 0 || !entry->isFile())
00057 {
00058 m_file = 0;
00059 return;
00060 }
00061 m_file = static_cast<const KArchiveFile*>(entry);
00062 }
00063 void setZip(const QString& zipfile)
00064 {
00065 closeZip();
00066
00067 m_zip = new KZip(zipfile);
00068
00069 if(!m_zip->open(IO_ReadOnly))
00070 {
00071 qDebug("Unable to open '%s' for reading.", zipfile.ascii());
00072 return;
00073 }
00074 m_dir = m_zip->directory();
00075 if(m_dir == 0)
00076 {
00077 qDebug("Error reading directory contents of file %s", zipfile.ascii());
00078 return;
00079 }
00080 }
00081
00082 virtual ~ZipFile()
00083 {
00084 closeZip();
00085 }
00086
00087 void closeZip()
00088 {
00089 if(m_zip)
00090 {
00091 m_zip->close();
00092 delete m_zip;
00093 }
00094 }
00095
00096 QByteArray data()
00097 {
00098 if(m_file)
00099 return m_file->data();
00100 else
00101 {
00102 if(!m_filename.isEmpty())
00103 qDebug("Error reading file %s from zip", m_filename.ascii());
00104 return QByteArray();
00105 }
00106 }
00107
00108 bool exists()
00109 {
00110 return (m_file != 0);
00111 }
00112
00113 private:
00114 KZip* m_zip;
00115 const KArchiveFile* m_file;
00116 QString m_filename;
00117 const KArchiveDirectory* m_dir;
00118 };
00119
00120 ThemeFile::ThemeFile(const KURL& url)
00121 : m_stream(0), m_locale(0), m_zip(0)
00122 {
00123 if(url.isValid())
00124 set(url);
00125 }
00126
00127 ThemeFile::~ThemeFile()
00128 {
00129 delete m_stream;
00130 delete m_locale;
00131 delete m_zip;
00132 }
00133
00134 bool ThemeFile::open()
00135 {
00136 bool result = false;
00137
00138 close();
00139
00140 if(m_zipTheme)
00141 {
00142 m_zip->setFile(m_theme);
00143 m_ba = m_zip->data();
00144 if(m_ba.size() > 0)
00145 {
00146 m_stream = new QTextStream(m_ba, IO_ReadOnly);
00147 result = true;
00148 }
00149 }
00150 else
00151 {
00152 m_fl.setName(m_file);
00153
00154 if(m_fl.open(IO_ReadOnly|IO_Translate))
00155 {
00156 m_stream = new QTextStream(&m_fl);
00157 result = true;
00158 }
00159 }
00160 return result;
00161 }
00162
00163 bool ThemeFile::nextLine(LineParser& parser)
00164 {
00165 parser.set("");
00166
00167 if(m_stream)
00168 {
00169 QString result = m_stream->readLine();
00170
00171 if(result.isNull())
00172 return false;
00173 parser.set(result);
00174 return true;
00175 }
00176 return false;
00177 }
00178
00179 bool ThemeFile::close()
00180 {
00181 if(m_stream)
00182 {
00183 delete m_stream;
00184 m_stream = 0;
00185 m_fl.close();
00186 m_ba.resize(0);
00187 return true;
00188 }
00189 return false;
00190 }
00191
00192 bool ThemeFile::isValid() const
00193 {
00194 return (exists() && !m_name.isEmpty() && !m_theme.isEmpty());
00195 }
00196
00197 bool ThemeFile::exists() const
00198 {
00199 QFileInfo file(m_file);
00200 return file.exists();
00201 }
00202
00203 QPixmap ThemeFile::icon() const
00204 {
00205 return QPixmap(readThemeFile(m_icon));
00206 }
00207
00208 bool ThemeFile::set(const KURL &url)
00209 {
00210 if(!url.isLocalFile() && !url.protocol().isEmpty())
00211 {
00212 if(KMessageBox::warningContinueCancel(kapp->activeWindow(),
00213 i18n("You are about to install and run %1 SuperKaramba theme. Since "
00214 "themes can contain executable code you should only install themes "
00215 "from sources that you trust. Continue?"), i18n("Executable Code Warning"), i18n("Install")
00216 .arg(url.prettyURL()))
00217 == KMessageBox::Cancel)
00218 {
00219 return false;
00220 }
00221
00222 QDir themeDir(locateLocal("appdata", "themes/", true));
00223 QFileInfo localFile = themeDir.filePath(url.fileName());
00224
00225 if(localFile.exists())
00226 {
00227 if(KMessageBox::warningContinueCancel(kapp->activeWindow(),
00228 i18n("%1 already exists. Do you want to overwrite it?")
00229 .arg(localFile.filePath()),i18n("File Exists"),i18n("Overwrite"))
00230 == KMessageBox::Cancel)
00231 {
00232 return false;
00233 }
00234 }
00235 if(!KIO::NetAccess::file_copy(url, localFile.filePath(), -1, true,
00236 false, kapp->mainWidget()))
00237 {
00238 return false;
00239 }
00240 m_file = localFile.filePath();
00241 }
00242 else
00243 {
00244 if(url.directory().isEmpty() || url.directory() == "/")
00245 m_file = canonicalFile(QDir::current().filePath(url.fileName()));
00246 else
00247 m_file = canonicalFile(url.path());
00248 if(!exists())
00249 return false;
00250 }
00251
00252 QFileInfo fi(m_file);
00253
00254 m_name = fi.baseName( TRUE );
00255 m_theme = m_name + ".theme";
00256 m_python = m_name;
00257 m_id = m_name;
00258
00259 if(isZipFile(m_file))
00260 {
00261 m_path = m_file;
00262 m_zipTheme = true;
00263 m_zip = new ZipFile();
00264 m_zip->setZip(m_file);
00265 }
00266 else
00267 {
00268 m_path = fi.dirPath(true) + "/";
00269 m_zipTheme = false;
00270 }
00271 parseXml();
00272
00273 QFileInfo fimo(m_python);
00274 if(m_python.isEmpty())
00275 fimo.setFile(m_theme);
00276 else
00277 fimo.setFile(m_python);
00278 m_mo = fimo.baseName( TRUE );
00279
00280 m_locale = new ThemeLocale(this);
00281 return isValid();
00282 }
00283
00284 void ThemeFile::parseXml()
00285 {
00286 if(!fileExists("maindata.xml"))
00287 return;
00288 QByteArray ba = readThemeFile("maindata.xml");
00289 QDomDocument doc("superkaramba_theme");
00290 doc.setContent(ba);
00291 QDomElement element = doc.documentElement();
00292
00293 QDomNode n = element.firstChild();
00294 while(!n.isNull())
00295 {
00296 QDomElement e = n.toElement();
00297 if(!e.isNull())
00298 {
00299 if(e.tagName() == "name")
00300 m_name = e.text();
00301 else if(e.tagName() == "themefile")
00302 m_theme = e.text();
00303 else if(e.tagName() == "python_module")
00304 {
00305 m_python = e.text();
00306 if(m_python.right(3).lower() == ".py")
00307 m_python.remove(m_python.length() - 3, 3);
00308 }
00309 else if(e.tagName() == "description")
00310 m_description = e.text();
00311 else if(e.tagName() == "author")
00312 m_author = e.text();
00313 else if(e.tagName() == "author_email")
00314 m_authorEmail = e.text();
00315 else if(e.tagName() == "homepage")
00316 m_homepage = e.text();
00317 else if(e.tagName() == "icon")
00318 m_icon = e.text();
00319 else if(e.tagName() == "version")
00320 m_version = e.text();
00321 else if(e.tagName() == "license")
00322 m_license = e.text();
00323 }
00324 n = n.nextSibling();
00325 }
00326 }
00327
00328 bool ThemeFile::canUninstall() const
00329 {
00330 QFileInfo fi(file());
00331 if(fi.permission(QFileInfo::WriteUser) ||
00332 fi.permission(QFileInfo::WriteGroup) ||
00333 fi.permission(QFileInfo::WriteOther))
00334 return true;
00335 return false;
00336 }
00337
00338 bool ThemeFile::isThemeFile(const QString& filename) const
00339 {
00340 QFileInfo fileInfo(filename);
00341
00342 return fileInfo.isRelative();
00343 }
00344
00345 bool ThemeFile::fileExists(const QString& filename) const
00346 {
00347 if(isThemeFile(filename))
00348 {
00349 if(isZipTheme())
00350 {
00351 m_zip->setFile(filename);
00352 return m_zip->exists();
00353 }
00354 else
00355 return QFileInfo(path() + "/" + filename).exists();
00356 }
00357 else
00358 return QFileInfo(filename).exists();
00359 }
00360
00361 QByteArray ThemeFile::readThemeFile(const QString& filename) const
00362 {
00363
00364
00365 QByteArray ba;
00366
00367 if(isZipTheme())
00368 {
00369 m_zip->setFile(filename);
00370 ba = m_zip->data();
00371 }
00372 else
00373 {
00374 QFile file(path() + "/" + filename);
00375
00376 if(file.open(IO_ReadOnly))
00377 {
00378 ba = file.readAll();
00379 file.close();
00380 }
00381 }
00382
00383
00384 return ba;
00385 }
00386
00387 bool ThemeFile::isZipFile(const QString& filename)
00388 {
00389 QFile file(filename);
00390
00391 if(file.open(IO_ReadOnly))
00392 {
00393 unsigned char buf[5];
00394
00395 if(file.readBlock((char*)buf, 4) == 4)
00396 {
00397 if(buf[0] == 'P' && buf[1] == 'K' && buf[2] == 3 && buf[3] == 4)
00398 return true;
00399 }
00400 }
00401 return false;
00402 }
00403
00404 bool ThemeFile::pythonModuleExists() const
00405 {
00406 return (!m_python.isEmpty() && fileExists(m_python + ".py"));
00407 }
00408
00409 QString ThemeFile::canonicalFile(const QString& file)
00410 {
00411
00412 QFileInfo fi(file);
00413 return QDir(fi.dir().canonicalPath()).filePath(fi.fileName());
00414 }
|