1 /* This file is part of the KDE project
3 Copyright (C) 2006-2008 Ralf Habacker <ralf.habacker@freenet.de>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
34 #undef KDE_NO_WARNING_OUTPUT
35 #undef QT_NO_DEBUG_OUTPUT
38 #include <kstandarddirs.h>
39 #include <kservicegroup.h>
40 // required by kdesktopfile.h -> should be in kdesktopfile.h
41 #include <kconfiggroup.h>
42 #include <kdesktopfile.h>
43 #include <kdeversion.h>
45 bool removeDirectory(const QString
& aDir
)
49 if (dir
.exists())//QDir::NoDotAndDotDot
51 QFileInfoList entries
= dir
.entryInfoList(QDir::NoDotAndDotDot
|
52 QDir::Dirs
| QDir::Files
);
53 int count
= entries
.size();
54 foreach(QFileInfo entryInfo
, entries
)
56 QString path
= entryInfo
.absoluteFilePath();
57 if (entryInfo
.isDir())
59 has_err
= removeDirectory(path
);
68 if (!dir
.rmdir(dir
.absolutePath()))
74 QString
getStartMenuPath(bool bAllUsers
)
76 int idl
= bAllUsers
? CSIDL_COMMON_PROGRAMS
: CSIDL_PROGRAMS
;
78 WCHAR wPath
[MAX_PATH
+1];
80 hRes
= SHGetFolderPathW(NULL
, idl
, NULL
, 0, wPath
);
83 QString s
= QString::fromUtf16((unsigned short*)wPath
);
89 QStringList
getInstalledKDEVersions()
91 QStringList installedVersions
;
92 QDir
dir(getStartMenuPath());
94 return installedVersions
;
96 QFileInfoList entries
= dir
.entryInfoList(QDir::NoDotAndDotDot
| QDir::Dirs
);
97 int count
= entries
.size();
98 foreach(QFileInfo entryInfo
, entries
) {
99 if (entryInfo
.fileName().startsWith("KDE "))
100 installedVersions
<< entryInfo
.fileName();
102 return installedVersions
;
105 QString
getKDEStartMenuRootEntry()
107 QString version
= KDE::versionString();
108 QStringList versions
= version
.split(" ");
110 QString compileMode
= "Release";
112 QString compileMode
= "Debug";
114 return "KDE " + versions
[0] + " " + compileMode
;
117 inline QString
getWorkingDir()
119 return QDir::toNativeSeparators(KStandardDirs::installPath("exe"));
122 QString
getKDEStartMenuPath()
124 return getStartMenuPath() + "/" + getKDEStartMenuRootEntry();
127 KServiceGroup::Ptr
findGroup(const QString
&relPath
)
130 QString
alreadyFound("Settings/");
131 QStringList rest
= relPath
.split( '/');
133 kDebug() << "Trying harder to find group " << relPath
;
134 for ( int i
=0; i
<rest
.count(); i
++)
135 kDebug() << "Item (" << rest
.at(i
) << ")";
137 while (!rest
.isEmpty()) {
138 KServiceGroup::Ptr tmp
= KServiceGroup::group(alreadyFound
);
139 if (!tmp
|| !tmp
->isValid())
140 return KServiceGroup::Ptr();
143 foreach (const KSycocaEntry::Ptr
&e
, tmp
->entries(true, true)) {
144 if (e
->isType(KST_KServiceGroup
)) {
145 KServiceGroup::Ptr
g(KServiceGroup::Ptr::staticCast(e
));
146 if ((g
->caption()==rest
.front()) || (g
->name()==alreadyFound
+rest
.front())) {
147 kDebug() << "Found group with caption " << g
->caption()
148 << " with real name: " << g
->name() << endl
;
150 rest
.erase(rest
.begin());
151 alreadyFound
= g
->name();
152 kDebug() << "ALREADY FOUND: " << alreadyFound
;
159 kDebug() << "Group with caption " << rest
.front() << " not found within "
160 << alreadyFound
<< endl
;
161 return KServiceGroup::Ptr();
165 return KServiceGroup::group(alreadyFound
);
168 bool generateMenuEntries(QList
<LinkFile
> &files
, const KUrl
&url
, const QString
&relPathTranslated
)
170 QString groupPath
= url
.path( KUrl::AddTrailingSlash
);
171 groupPath
.remove(0, 1); // remove starting '/'
173 KServiceGroup::Ptr grp
= KServiceGroup::group(groupPath
);
175 if (!grp
|| !grp
->isValid()) {
176 grp
= findGroup(groupPath
);
177 if (!grp
|| !grp
->isValid()) {
178 kDebug() << "Unknown settings folder";
183 unsigned int count
= 0;
185 foreach (const KSycocaEntry::Ptr
&e
, grp
->entries(true, true)) {
186 if (e
->isType(KST_KServiceGroup
)) {
187 KServiceGroup::Ptr
g(KServiceGroup::Ptr::staticCast(e
));
188 // Avoid adding empty groups.
189 KServiceGroup::Ptr subMenuRoot
= KServiceGroup::group(g
->relPath());
190 if (subMenuRoot
->childCount() == 0)
194 if ((g
->name().at(0) == '.'))
197 QString relPath
= g
->relPath();
199 a
.setPath("/" + relPath
);
200 generateMenuEntries(files
,a
,relPathTranslated
+ "/" + g
->caption());
202 KService::Ptr
s(KService::Ptr::staticCast(e
));
204 // read exec attribute
205 KDesktopFile
df(KStandardDirs::locate("apps", s
->entryPath()));
206 if (df
.readType() != "Application")
209 QString _exec
= df
.desktopGroup().readEntry("Exec","");
210 QStringList cmd
= _exec
.split(" ");
211 QString exec
= cmd
[0];
212 QStringList arguments
;
213 if (cmd
.size() > 1) {
214 // ignore arguments completely when they contain a variable
215 if (!(_exec
.contains("%i") || _exec
.contains("%u") || _exec
.contains("%U") || _exec
.contains("%c"))) {
217 arguments
.removeFirst();
221 // create executable path
222 QString execPath
= KStandardDirs::findExe(exec
);
223 if (execPath
.isEmpty()) {
224 kDebug() << "could not find executable for" << exec
;
228 QString linkPath
= getKDEStartMenuPath() + relPathTranslated
+ "/";
229 QString linkName
= s
->name();
230 if (!s
->genericName().isEmpty() && s
->genericName() != s
->name())
231 linkName
+= " (" + s
->genericName().replace("/","-") + ")";
233 QString linkFilePath
= linkPath
+ linkName
+ ".lnk";
234 QFileInfo
fi(linkFilePath
);
235 QDir
d(fi
.absolutePath());
237 if(!d
.mkpath(fi
.absolutePath())) {
238 kDebug() << "Can't create directory " << d
.absolutePath();
242 QString workingDir
= getWorkingDir();
243 QString description
= s
->genericName();
245 files
.append(LinkFile(QStringList() << execPath
<< arguments
,linkFilePath
,description
,workingDir
));
253 check start menu for older kde installations and remove obsolate or non existing ones
255 This is done by the following rules:
256 1. If no entry in an installation points to an existing executable, this installation
257 is removed and could be deleted
258 2. if start menu entries for non current kde installation have the same working
259 dir as the current installation, this should be removed too
261 void removeObsolateInstallations()
263 kDebug() << getInstalledKDEVersions();
264 QString currentVersion
= getKDEStartMenuRootEntry();
266 foreach(QString release
,getInstalledKDEVersions())
268 // skip current version
269 if (release
== currentVersion
)
271 // get all link files for a specific release
272 QList
<LinkFile
> allReleasesFiles
;
273 LinkFiles::scan(allReleasesFiles
, getStartMenuPath() + "/" + release
);
274 bool available
= false;
275 bool sameWorkingDir
= false;
276 foreach(LinkFile lf
, allReleasesFiles
)
278 lf
.read(); // this in not done by the LinkFile class by default
279 kDebug() << release
<< " : " << lf
;
280 QFileInfo
fi(lf
.execPath());
283 if (lf
.workingDir() == getWorkingDir())
284 sameWorkingDir
= true;
286 if (!available
|| sameWorkingDir
)
287 removeDirectory(getStartMenuPath() + "/" + release
);
291 void updateStartMenuLinks()
293 removeObsolateInstallations();
295 // generate list of installed linkfiles
296 QList
<LinkFile
> oldFiles
;
297 LinkFiles::scan(oldFiles
, getKDEStartMenuPath());
298 foreach(const LinkFile
& lf
, oldFiles
)
299 kDebug() << "oldFile: " << lf
;
301 // create list of currently available link files
302 QList
<LinkFile
> newFiles
;
303 generateMenuEntries(newFiles
,KUrl("applications:/"));
304 foreach(const LinkFile
& lf
, newFiles
)
305 kDebug() << "newFile: " << lf
;
307 // remove obsolate links
308 LinkFiles::cleanup(newFiles
,oldFiles
);
310 LinkFiles::create(newFiles
);
313 void removeStartMenuLinks()
315 removeObsolateInstallations();
316 removeDirectory(getKDEStartMenuPath());