2 Copyright (c) 2007 Zack Rusin <zack@kde.org>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 #include <QXmlStreamReader>
31 #include <KIO/CopyJob>
34 #include <Plasma/PackageMetadata>
35 #include <Plasma/Package>
37 void recursive_print(const KArchiveDirectory
*dir
, const QString
&path
)
39 const QStringList l
= dir
->entries();
40 QStringList::const_iterator it
= l
.constBegin();
41 for (; it
!= l
.end(); ++it
)
43 const KArchiveEntry
* entry
= dir
->entry((*it
));
44 printf("mode=%07o %s %s size: %lld pos: %lld %s%s isdir=%d%s",
46 entry
->user().toLatin1().constData(),
47 entry
->group().toLatin1().constData(),
48 entry
->isDirectory() ? 0 : ((KArchiveFile
*)entry
)->size(),
49 entry
->isDirectory() ? 0 : ((KArchiveFile
*)entry
)->position(),
50 path
.toLatin1().constData(),
51 (*it
).toLatin1().constData(), entry
->isDirectory(),
52 entry
->symLinkTarget().isEmpty() ? "" :
53 QString(" symlink: %1").arg(
54 entry
->symLinkTarget()).toLatin1().constData());
56 //if (!entry->isDirectory()) printf("%d",
57 // ((KArchiveFile*)entry)->size());
59 if (entry
->isDirectory())
60 recursive_print((KArchiveDirectory
*)entry
, path
+(*it
)+'/');
65 static const KArchiveDirectory
*recursiveFind(const KArchiveDirectory
*dir
)
67 const QStringList l
= dir
->entries();
68 QStringList::const_iterator it
;
69 for (it
= l
.constBegin(); it
!= l
.constEnd(); ++it
) {
70 const KArchiveEntry
* entry
= dir
->entry((*it
));
71 if (entry
->isDirectory()) {
73 if (name
.startsWith(QLatin1String("__MACOSX"))) {
76 } else if (name
.endsWith(QLatin1String(".wdgt"))) {
78 return static_cast<const KArchiveDirectory
*>(entry
);
80 const KArchiveDirectory
*fd
=
81 recursiveFind(static_cast<const KArchiveDirectory
*>(entry
));
90 Bundle::Bundle(const QString
&path
)
91 : PackageStructure(0, "MacDashboard"),
93 m_width(0), m_height(0)
95 setContentsPrefix(QString());
97 f
.open(QIODevice::ReadOnly
);
104 Bundle::Bundle(const QByteArray
&data
)
105 : PackageStructure(0, "MacDashboard"),
110 setContentsPrefix(QString());
116 Bundle::Bundle(QObject
*parent
, QVariantList args
)
117 : PackageStructure(parent
, "MacDashboard"),
124 setContentsPrefix(QString());
133 void Bundle::setData(const QByteArray
&data
)
140 QByteArray
Bundle::data() const
151 if (m_data
.isEmpty()) {
155 QBuffer
buffer(&m_data
);
157 if (!zip
.open(QIODevice::ReadOnly
)) {
158 qWarning("Couldn't open the bundle!");
162 const KArchiveDirectory
*dir
= zip
.directory();
164 const KArchiveDirectory
*foundDir
= recursiveFind(dir
);
166 qWarning("not a bundle");
172 m_isValid
= extractArchive(foundDir
, QLatin1String(""));
173 qDebug()<<"Dir = "<<foundDir
->name() << m_isValid
;
176 setPath(m_tempDir
->name());
186 bool ret
= m_tempDir
;
192 bool Bundle::extractArchive(const KArchiveDirectory
*dir
, const QString
&path
)
194 const QStringList l
= dir
->entries();
196 QStringList::const_iterator it
;
197 for (it
= l
.constBegin(); it
!= l
.constEnd(); ++it
) {
198 const KArchiveEntry
* entry
= dir
->entry((*it
));
199 QString fullPath
= QString("%1/%2").arg(path
).arg(*it
);
200 if (entry
->isDirectory()) {
201 QString outDir
= QString("%1%2").arg(m_tempDir
->name()).arg(path
);
204 extractArchive(static_cast<const KArchiveDirectory
*>(entry
), fullPath
);
205 } else if (entry
->isFile()) {
206 QString outName
= QString("%1%2").arg(m_tempDir
->name()).arg(fullPath
.remove(0, 1));
207 //qDebug()<<"-------- "<<outName;
209 if (!f
.open(QIODevice::WriteOnly
)) {
210 qWarning("Couldn't create %s", qPrintable(outName
));
213 const KArchiveFile
*archiveFile
= static_cast<const KArchiveFile
*>(entry
);
214 f
.write(archiveFile
->data());
217 qWarning("Unidentified entry at %s", qPrintable(fullPath
));
223 void Bundle::pathChanged()
225 //qDebug() << "path changed";
226 m_isValid
= extractInfo();
229 bool Bundle::extractInfo()
231 QString plistLocation
= QString("%1Info.plist").arg(path());
232 QString configXml
= QString("%1config.xml").arg(path());
233 if (QFile::exists(plistLocation
)) {
234 //qDebug() << "doing plist";
235 return parsePlist(plistLocation
);
236 } else if (QFile::exists(configXml
)) {
237 return parseConfigXml(configXml
);
243 bool Bundle::parsePlist(const QString
&loc
)
246 if (!f
.open(QIODevice::ReadOnly
)) {
247 qWarning("Couldn't open info file: '%s'", qPrintable(loc
));
251 QMap
<QString
, QString
> infoMap
;
252 QString str
= f
.readAll();
253 QXmlStreamReader
reader(str
);
254 while (!reader
.atEnd()) {
257 if (reader
.isStartElement()) {
258 //qDebug() << reader.name().toString();
259 if (reader
.name() == "key") {
262 if (reader
.isCharacters()) {
263 QString str
= reader
.text().toString();
270 while (!reader
.isStartElement())
272 if (reader
.name() != "string" &&
273 reader
.name() != "integer") {
274 qDebug()<<"Unrecognized val "<<reader
.name().toString()
279 if (reader
.isCharacters()) {
280 QString str
= reader
.text().toString();
285 //qDebug()<<"key = "<<key<<", value = "<<value;
286 infoMap
.insert(key
, value
);
291 QMap
<QString
, QString
>::const_iterator itr
;
292 for (itr
= infoMap
.constBegin(); itr
!= infoMap
.constEnd(); ++itr
) {
293 kDebug() << itr
.key() << itr
.value();
294 if (itr
.key() == QLatin1String("CFBundleIdentifier")) {
295 m_bundleId
= itr
.value();
296 } else if (itr
.key() == QLatin1String("CFBundleName")) {
297 m_description
= itr
.value();
298 } else if (itr
.key() == QLatin1String("CFBundleDisplayName")) {
299 m_name
= itr
.value();
300 } else if (itr
.key() == QLatin1String("CFBundleVersion")) {
301 m_version
= itr
.value();
302 } else if (itr
.key() == QLatin1String("CloseBoxInsetX")) {
304 } else if (itr
.key() == QLatin1String("CloseBoxInsetY")) {
306 } else if (itr
.key() == QLatin1String("Height")) {
307 m_height
= itr
.value().toInt();
308 } else if (itr
.key() == QLatin1String("Width")) {
309 m_width
= itr
.value().toInt();
310 } else if (itr
.key() == QLatin1String("MainHTML")) {
311 m_htmlLocation
= QString("%1%2").arg(path()).arg(itr
.value());
312 addFileDefinition("mainscript", itr
.value(), i18n("Main Webpage"));
314 qDebug()<<"Unrecognized key = "<<itr
.key();
317 m_iconLocation
= QString("%1Icon.png").arg(path());
319 addDirectoryDefinition("root", "/", i18n("Root HTML directory"));
321 //qDebug()<<"name = "<<m_name;
322 //qDebug()<<"id = "<<m_bundleId;
323 //qDebug()<<"html = "<<m_htmlLocation;
324 //qDebug()<<"icon = "<<m_iconLocation;
326 return !m_bundleId
.isEmpty();
329 bool Bundle::installPackage(const QString
&archivePath
, const QString
&packageRoot
)
331 //kDebug() << "??????????????" << archivePath << packageRoot;
332 QFile
f(archivePath
);
333 f
.open(QIODevice::ReadOnly
);
334 m_data
= f
.readAll();
339 m_tempDir
->setAutoRemove(false);
340 QString pluginName
= "dashboard_" + m_bundleId
;
341 //kDebug() << "valid, so going to move it in to" << pluginName;
342 KIO::CopyJob
* job
= KIO::move(m_tempDir
->name(), packageRoot
+ pluginName
, KIO::HideProgressInfo
);
343 m_isValid
= job
->exec();
346 //kDebug() << "still so good ... registering";
347 Plasma::PackageMetadata data
;
348 data
.setName(m_name
);
349 data
.setDescription(m_description
);
350 data
.setPluginName(pluginName
);
351 data
.setImplementationApi("dashboard");
352 Plasma::Package::registerPackage(data
, m_iconLocation
);
357 // make sure we clean up after ourselves afterwards on failure
358 m_tempDir
->setAutoRemove(true);
364 bool Bundle::parseConfigXml(const QString
&loc
)
367 if (!f
.open(QIODevice::ReadOnly
)) {
368 qWarning("Couldn't open info file: '%s'", qPrintable(loc
));
372 qWarning("FIXME: Widgets 1.0 not implemented");
377 void Bundle::initTempDir()
379 m_tempDir
= new KTempDir();
381 m_tempDir
->setAutoRemove(true);
384 QString
Bundle::bundleId() const
389 QString
Bundle::name() const
394 QString
Bundle::version() const
399 QString
Bundle::description() const
401 return m_description
;
404 int Bundle::width() const
409 int Bundle::height() const
414 QString
Bundle::htmlLocation() const
416 return m_htmlLocation
;
419 QString
Bundle::iconLocation() const
421 return m_iconLocation
;
424 bool Bundle::isValid() const