Plasma
bundle.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "bundle.h"
00024
00025 #include <QBuffer>
00026 #include <QDebug>
00027 #include <QDir>
00028 #include <QFile>
00029 #include <QXmlStreamReader>
00030
00031 #include <KIO/CopyJob>
00032 #include <KIO/Job>
00033
00034 #include <plasma/packagemetadata.h>
00035 #include <plasma/package.h>
00036
00037 void recursive_print(const KArchiveDirectory *dir, const QString &path)
00038 {
00039 QStringList l = dir->entries();
00040 QStringList::Iterator it = l.begin();
00041 for (; it != l.end(); ++it)
00042 {
00043 const KArchiveEntry* entry = dir->entry((*it));
00044 printf("mode=%07o %s %s size: %lld pos: %lld %s%s isdir=%d%s",
00045 entry->permissions(),
00046 entry->user().toLatin1().constData(),
00047 entry->group().toLatin1().constData(),
00048 entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->size(),
00049 entry->isDirectory() ? 0 : ((KArchiveFile*)entry)->position(),
00050 path.toLatin1().constData(),
00051 (*it).toLatin1().constData(), entry->isDirectory(),
00052 entry->symLinkTarget().isEmpty() ? "" :
00053 QString(" symlink: %1").arg(
00054 entry->symLinkTarget()).toLatin1().constData());
00055
00056
00057
00058 printf("\n");
00059 if (entry->isDirectory())
00060 recursive_print((KArchiveDirectory *)entry, path+(*it)+'/');
00061 }
00062 }
00063
00064
00065 static const KArchiveDirectory *recursiveFind(const KArchiveDirectory *dir)
00066 {
00067 QStringList l = dir->entries();
00068 QStringList::Iterator it;
00069 for (it = l.begin(); it != l.end(); ++it) {
00070 const KArchiveEntry* entry = dir->entry((*it));
00071 if (entry->isDirectory()) {
00072 QString name = *it;
00073 if (name.startsWith(QLatin1String("__MACOSX"))) {
00074
00075 continue;
00076 } else if (name.endsWith(QLatin1String(".wdgt"))) {
00077
00078 return static_cast<const KArchiveDirectory*>(entry);
00079 } else {
00080 const KArchiveDirectory *fd =
00081 recursiveFind(static_cast<const KArchiveDirectory*>(entry));
00082 if (fd)
00083 return fd;
00084 }
00085 }
00086 }
00087 return 0;
00088 }
00089
00090 Bundle::Bundle(const QString &path)
00091 : PackageStructure(0, "MacDashboard"),
00092 m_isValid(false),
00093 m_width(0), m_height(0)
00094 {
00095 setContentsPrefix(QString());
00096 QFile f(path);
00097 f.open(QIODevice::ReadOnly);
00098 m_data = f.readAll();
00099 f.close();
00100 initTempDir();
00101 open();
00102 }
00103
00104 Bundle::Bundle(const QByteArray &data)
00105 : PackageStructure(0, "MacDashboard"),
00106 m_isValid(false),
00107 m_width(0),
00108 m_height(0)
00109 {
00110 setContentsPrefix(QString());
00111 m_data = data;
00112 initTempDir();
00113 open();
00114 }
00115
00116 Bundle::Bundle(QObject *parent, QVariantList args)
00117 : PackageStructure(0, "MacDashboard"),
00118 m_isValid(false),
00119 m_tempDir(0),
00120 m_width(0),
00121 m_height(0)
00122 {
00123 setContentsPrefix(QString());
00124 }
00125
00126 Bundle::~Bundle()
00127 {
00128 close();
00129 qWarning("done");
00130 }
00131
00132 void Bundle::setData(const QByteArray &data)
00133 {
00134 m_data = data;
00135 close();
00136 open();
00137 }
00138
00139 QByteArray Bundle::data() const
00140 {
00141 return m_data;
00142 }
00143
00144 bool Bundle::open()
00145 {
00146 if (m_data.isEmpty())
00147 return false;
00148
00149 if (!m_tempDir)
00150 initTempDir();
00151
00152 QBuffer buffer(&m_data);
00153 KZip zip(&buffer);
00154 if (!zip.open(QIODevice::ReadOnly)) {
00155 qWarning("Couldn't open the bundle!");
00156 return false;
00157 }
00158
00159 const KArchiveDirectory *dir = zip.directory();
00160
00161 const KArchiveDirectory *foundDir = recursiveFind(dir);
00162 if (!foundDir) {
00163 qWarning("not a bundle");
00164 m_isValid = false;
00165 zip.close();
00166 return 0;
00167 }
00168
00169 m_isValid = extractArchive(foundDir, QLatin1String(""));
00170 qDebug()<<"Dir = "<<foundDir->name() << m_isValid;
00171
00172 if (m_isValid) {
00173 setPath(m_tempDir->name());
00174 }
00175
00176 zip.close();
00177
00178 return m_isValid;
00179 }
00180
00181 bool Bundle::close()
00182 {
00183 bool ret = m_tempDir;
00184 delete m_tempDir;
00185 m_tempDir = 0;
00186 return ret;
00187 }
00188
00189 bool Bundle::extractArchive(const KArchiveDirectory *dir, const QString &path)
00190 {
00191 QStringList l = dir->entries();
00192
00193 QStringList::Iterator it;
00194 for (it = l.begin(); it != l.end(); ++it) {
00195 const KArchiveEntry* entry = dir->entry((*it));
00196 QString fullPath = QString("%1/%2").arg(path).arg(*it);
00197 if (entry->isDirectory()) {
00198 QString outDir = QString("%1%2").arg(m_tempDir->name()).arg(path);
00199 QDir qdir(outDir);
00200 qdir.mkdir(*it);
00201 extractArchive(static_cast<const KArchiveDirectory*>(entry), fullPath);
00202 } else if (entry->isFile()) {
00203 QString outName = QString("%1%2").arg(m_tempDir->name()).arg(fullPath.remove(0, 1));
00204
00205 QFile f(outName);
00206 if (!f.open(QIODevice::WriteOnly)) {
00207 qWarning("Couldn't create %s", qPrintable(outName));
00208 continue;
00209 }
00210 const KArchiveFile *archiveFile = static_cast<const KArchiveFile*>(entry);
00211 f.write(archiveFile->data());
00212 f.close();
00213 } else {
00214 qWarning("Unidentified entry at %s", qPrintable(fullPath));
00215 }
00216 }
00217 return true;
00218 }
00219
00220 void Bundle::pathChanged()
00221 {
00222
00223 m_isValid = extractInfo();
00224 }
00225
00226 bool Bundle::extractInfo()
00227 {
00228 QString plistLocation = QString("%1Info.plist").arg(path());
00229 QString configXml = QString("%1config.xml").arg(path());
00230 if (QFile::exists(plistLocation)) {
00231
00232 return parsePlist(plistLocation);
00233 } else if (QFile::exists(configXml)) {
00234 return parseConfigXml(configXml);
00235 }
00236
00237 return false;
00238 }
00239
00240 bool Bundle::parsePlist(const QString &loc)
00241 {
00242 QFile f(loc);
00243 if (!f.open(QIODevice::ReadOnly)) {
00244 qWarning("Couldn't open info file: '%s'", qPrintable(loc));
00245 return false;
00246 }
00247
00248 QMap<QString, QString> infoMap;
00249 QString str = f.readAll();
00250 QXmlStreamReader reader(str);
00251 while (!reader.atEnd()) {
00252 reader.readNext();
00253
00254 if (reader.isStartElement()) {
00255
00256 if (reader.name() == "key") {
00257 QString key, value;
00258 reader.readNext();
00259 if (reader.isCharacters()) {
00260 QString str = reader.text().toString();
00261 str = str.trimmed();
00262 if (!str.isEmpty())
00263 key = str;
00264 }
00265 if (key.isEmpty())
00266 continue;
00267 while (!reader.isStartElement())
00268 reader.readNext();
00269 if (reader.name() != "string" &&
00270 reader.name() != "integer") {
00271 qDebug()<<"Unrecognized val "<<reader.name().toString()
00272 <<" for key "<<key;
00273 continue;
00274 }
00275 reader.readNext();
00276 if (reader.isCharacters()) {
00277 QString str = reader.text().toString();
00278 str = str.trimmed();
00279 if (!str.isEmpty())
00280 value = str;
00281 }
00282
00283 infoMap.insert(key, value);
00284 }
00285 }
00286 }
00287
00288 QMap<QString, QString>::const_iterator itr;
00289 for (itr = infoMap.constBegin(); itr != infoMap.constEnd(); ++itr) {
00290 kDebug() << itr.key() << itr.value();
00291 if (itr.key() == QLatin1String("CFBundleIdentifier")) {
00292 m_bundleId = itr.value();
00293 } else if (itr.key() == QLatin1String("CFBundleName")) {
00294 m_description = itr.value();
00295 } else if (itr.key() == QLatin1String("CFBundleDisplayName")) {
00296 m_name = itr.value();
00297 } else if (itr.key() == QLatin1String("CFBundleVersion")) {
00298 m_version = itr.value();
00299 } else if (itr.key() == QLatin1String("CloseBoxInsetX")) {
00300
00301 } else if (itr.key() == QLatin1String("CloseBoxInsetY")) {
00302
00303 } else if (itr.key() == QLatin1String("Height")) {
00304 m_height = itr.value().toInt();
00305 } else if (itr.key() == QLatin1String("Width")) {
00306 m_width = itr.value().toInt();
00307 } else if (itr.key() == QLatin1String("MainHTML")) {
00308 m_htmlLocation = QString("%1%2").arg(path()).arg(itr.value());
00309 addFileDefinition("webpage", itr.value(), i18n("Main Webpage"));
00310 } else {
00311 qDebug()<<"Unrecognized key = "<<itr.key();
00312 }
00313 }
00314 m_iconLocation = QString("%1Icon.png").arg(path());
00315
00316
00317
00318
00319
00320
00321 return !m_bundleId.isEmpty();
00322 }
00323
00324 bool Bundle::installPackage(const QString &archivePath, const QString &packageRoot)
00325 {
00326
00327 QFile f(archivePath);
00328 f.open(QIODevice::ReadOnly);
00329 m_data = f.readAll();
00330 f.close();
00331 open();
00332
00333 if (m_isValid) {
00334 m_tempDir->setAutoRemove(false);
00335 QString pluginName = "dashboard_" + m_bundleId;
00336
00337 KIO::CopyJob* job = KIO::move(m_tempDir->name(), packageRoot + pluginName, KIO::HideProgressInfo);
00338 m_isValid = job->exec();
00339
00340 if (m_isValid) {
00341
00342 Plasma::PackageMetadata data;
00343 data.setName(m_name);
00344 data.setDescription(m_description);
00345 data.setPluginName(pluginName);
00346 data.setImplementationApi("dashboard");
00347 Plasma::Package::registerPackage(data, m_iconLocation);
00348 }
00349 }
00350
00351 if (!m_isValid) {
00352
00353 m_tempDir->setAutoRemove(true);
00354 }
00355
00356 return m_isValid;
00357 }
00358
00359 bool Bundle::parseConfigXml(const QString &loc)
00360 {
00361 QFile f(loc);
00362 if (!f.open(QIODevice::ReadOnly)) {
00363 qWarning("Couldn't open info file: '%s'", qPrintable(loc));
00364 return false;
00365 }
00366
00367 qWarning("FIXME: Widgets 1.0 not implemented");
00368
00369 return false;
00370 }
00371
00372 void Bundle::initTempDir()
00373 {
00374 m_tempDir = new KTempDir();
00375
00376 m_tempDir->setAutoRemove(true);
00377 }
00378
00379 QString Bundle::bundleId() const
00380 {
00381 return m_bundleId;
00382 }
00383
00384 QString Bundle::name() const
00385 {
00386 return m_name;
00387 }
00388
00389 QString Bundle::version() const
00390 {
00391 return m_version;
00392 }
00393
00394 QString Bundle::description() const
00395 {
00396 return m_description;
00397 }
00398
00399 int Bundle::width() const
00400 {
00401 return m_width;
00402 }
00403
00404 int Bundle::height() const
00405 {
00406 return m_height;
00407 }
00408
00409 QString Bundle::htmlLocation() const
00410 {
00411 return m_htmlLocation;
00412 }
00413
00414 QString Bundle::iconLocation() const
00415 {
00416 return m_iconLocation;
00417 }
00418
00419 bool Bundle::isValid() const
00420 {
00421 return m_isValid;
00422 }
00423
00424