KoTemplates.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2000 Werner Trobin <trobin@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include <KoTemplates.h>
21
22#include <tqdir.h>
23#include <tqimage.h>
24#include <tqprinter.h>
25
26#include <kdesktopfile.h>
27#include <ksimpleconfig.h>
28#include <kdebug.h>
29#include <tdeversion.h>
30#include <tdeinstance.h>
31#include <ksavefile.h>
32#include <kstandarddirs.h>
33#include <kiconloader.h>
34#include <tdeio/netaccess.h>
35#include <tdelocale.h>
36
37#include <stdlib.h>
38
39
40KoTemplate::KoTemplate(const TQString &name, const TQString &description, const TQString &file,
41 const TQString &picture, const TQString &fileName, const TQString &_measureSystem,
42 bool hidden, bool touched) :
43 m_name(name), m_descr(description), m_file(file), m_picture(picture), m_fileName(fileName),
44 m_hidden(hidden), m_touched(touched), m_cached(false), m_measureSystem(_measureSystem)
45{
46}
47
48const TQPixmap &KoTemplate::loadPicture( TDEInstance* instance ) {
49
50 if(m_cached)
51 return m_pixmap;
52 m_cached=true;
53 if ( m_picture[ 0 ] == '/' )
54 {
55 // ### TODO: use the class KoPicture instead of TQImage to support non-image pictures
56 TQImage img( m_picture );
57 if (img.isNull()) {
58 kdWarning() << "Couldn't find icon " << m_picture << endl;
59 m_pixmap=TQPixmap();
60 return m_pixmap;
61 }
62 const int maxHeightWidth = 128; // ### TODO: some people would surely like to have 128x128
63 if (img.width() > maxHeightWidth || img.height() > maxHeightWidth) {
64 img = img.smoothScale( maxHeightWidth, maxHeightWidth, TQImage::ScaleMax );
65 }
66 m_pixmap.convertFromImage(img);
67 return m_pixmap;
68 } else { // relative path
69 m_pixmap = instance->iconLoader()->loadIcon( m_picture, TDEIcon::Desktop, 128 );
70 return m_pixmap;
71 }
72}
73
74
75KoTemplateGroup::KoTemplateGroup(const TQString &name, const TQString &dir,
76 int _sortingWeight, bool touched) :
77 m_name(name), m_touched(touched), m_sortingWeight(_sortingWeight)
78{
79 m_dirs.append(dir);
80 m_templates.setAutoDelete(true);
81}
82
83bool KoTemplateGroup::isHidden() const {
84
85 TQPtrListIterator<KoTemplate> it(m_templates);
86 bool hidden=true;
87 while(it.current()!=0L && hidden) {
88 hidden=it.current()->isHidden();
89 ++it;
90 }
91 return hidden;
92}
93
94void KoTemplateGroup::setHidden(bool hidden) const {
95
96 TQPtrListIterator<KoTemplate> it(m_templates);
97 for( ; it.current()!=0L; ++it)
98 it.current()->setHidden(hidden);
99 m_touched=true;
100}
101
102bool KoTemplateGroup::add(KoTemplate *t, bool force, bool touch) {
103
104 KoTemplate *myTemplate=find(t->name());
105 if(myTemplate==0L) {
106 m_templates.append(t);
107 m_touched=touch;
108 return true;
109 }
110 else if(myTemplate && force) {
111 //kdDebug() << "removing :" << myTemplate->fileName() << endl;
112 TQFile::remove( myTemplate->fileName() );
113 TQFile::remove( myTemplate->picture() );
114 TQFile::remove( myTemplate->file() );
115 m_templates.removeRef(myTemplate);
116 m_templates.append(t);
117 m_touched=touch;
118 return true;
119 }
120 return false;
121}
122
123KoTemplate *KoTemplateGroup::find(const TQString &name) const {
124
125 TQPtrListIterator<KoTemplate> it(m_templates);
126 while(it.current() && it.current()->name()!=name)
127 ++it;
128 return it.current();
129}
130
131
132KoTemplateTree::KoTemplateTree(const TQCString &templateType,
133 TDEInstance *instance, bool readTree) :
134 m_templateType(templateType), m_instance(instance), m_defaultGroup(0L),
135 m_defaultTemplate(0L) {
136
137 m_groups.setAutoDelete(true);
138 if(readTree)
139 readTemplateTree();
140}
141
142void KoTemplateTree::readTemplateTree() {
143
144 readGroups();
145 readTemplates();
146}
147
148void KoTemplateTree::writeTemplateTree() {
149 TQString localDir=m_instance->dirs()->saveLocation(m_templateType);
150
151 for(KoTemplateGroup *group=m_groups.first(); group!=0L; group=m_groups.next()) {
152 //kdDebug() << "---------------------------------" << endl;
153 //kdDebug() << "group: " << group->name() << endl;
154
155 bool touched=false;
156 for(KoTemplate *t=group->first(); t!=0L && !touched && !group->touched(); t=group->next())
157 touched=t->touched();
158
159 if(group->touched() || touched) {
160 //kdDebug() << "touched" << endl;
161 if(!group->isHidden()) {
162 //kdDebug() << "not hidden" << endl;
163 TDEStandardDirs::makeDir(localDir+group->name()); // create the local group dir
164 }
165 else {
166 //kdDebug() << "hidden" << endl;
167 if(group->dirs().count()==1 && !group->dirs().grep(localDir).isEmpty()) {
168 //kdDebug() << "local only" << endl;
169 TDEIO::NetAccess::del(group->dirs().first(), 0);
170 //kdDebug() << "removing: " << group->dirs().first() << endl;
171 }
172 else {
173 //kdDebug() << "global" << endl;
174 TDEStandardDirs::makeDir(localDir+group->name());
175 }
176 }
177 }
178 for(KoTemplate *t=group->first(); t!=0L; t=group->next()) {
179 if(t->touched()) {
180 //kdDebug() << "++template: " << t->name() << endl;
181 writeTemplate(t, group, localDir);
182 }
183 if(t->isHidden() && t->touched() ) {
184 //kdDebug() << "+++ delete local template ##############" << endl;
185 writeTemplate(t, group, localDir);
186 TQFile::remove(t->file());
187 TQFile::remove(t->picture());
188 }
189 }
190 }
191}
192
193void KoTemplateTree::add(KoTemplateGroup *g) {
194
195 KoTemplateGroup *group=find(g->name());
196 if(group==0L)
197 m_groups.append(g);
198 else
199 group->addDir(g->dirs().first()); // "...there can be only one..." (Queen)
200}
201
202KoTemplateGroup *KoTemplateTree::find(const TQString &name) const {
203
204 TQPtrListIterator<KoTemplateGroup> it(m_groups);
205 while(it.current() && it.current()->name()!=name)
206 ++it;
207 return it.current();
208}
209
210void KoTemplateTree::readGroups() {
211
212 TQStringList dirs = m_instance->dirs()->resourceDirs(m_templateType);
213 for(TQStringList::ConstIterator it=dirs.begin(); it!=dirs.end(); ++it) {
214 //kdDebug() << "dir: " << *it << endl;
215 TQDir dir(*it);
216 // avoid the annoying warning
217 if(!dir.exists())
218 continue;
219 dir.setFilter(TQDir::Dirs);
220 TQStringList templateDirs=dir.entryList();
221 for(TQStringList::ConstIterator tdirIt=templateDirs.begin(); tdirIt!=templateDirs.end(); ++tdirIt) {
222 if(*tdirIt=="." || *tdirIt=="..") // we don't want to check those dirs :)
223 continue;
224 TQDir templateDir(*it+*tdirIt);
225 TQString name=*tdirIt;
226 TQString defaultTab;
227 int sortingWeight = 1000;
228 if(templateDir.exists(".directory")) {
229 KSimpleConfig config(templateDir.absPath()+"/.directory", true);
230 config.setDesktopGroup();
231 name=config.readEntry("Name");
232 defaultTab=config.readEntry("X-TDE-DefaultTab");
233 sortingWeight=config.readNumEntry("X-TDE-SortingWeight", 1000);
234 //kdDebug() << "name: " << name <<endl;
235 }
236 KoTemplateGroup *g=new KoTemplateGroup(name, *it+*tdirIt+TQChar('/'), sortingWeight);
237 add(g);
238 if(defaultTab=="true")
239 m_defaultGroup=g;
240 }
241 }
242}
243
244void KoTemplateTree::readTemplates() {
245 TQString dontShow = "imperial";
246
247 if(TDEGlobal::locale()->pageSize() == TQPrinter::Letter) {
248 dontShow = "metric";
249 }
250
251 TQPtrListIterator<KoTemplateGroup> groupIt(m_groups);
252 for( ; groupIt.current()!=0L; ++groupIt) {
253 TQStringList dirs=groupIt.current()->dirs();
254 for(TQStringList::ConstIterator it=dirs.begin(); it!=dirs.end(); ++it) {
255 TQDir d(*it);
256 if( !d.exists() )
257 continue;
258 TQStringList files=d.entryList( TQDir::Files | TQDir::Readable, TQDir::Name );
259 for(unsigned int i=0; i<files.count(); ++i) {
260 TQString filePath = *it + files[i];
261 //kdDebug() << "filePath: " << filePath << endl;
262 TQString icon;
263 TQString text;
264 TQString description;
265 TQString hidden_str;
266 TQString fileName;
267 bool hidden=false;
268 bool defaultTemplate = false;
269 TQString templatePath;
270 TQString measureSystem;
271 // If a desktop file, then read the name from it.
272 // Otherwise (or if no name in it?) use file name
273 if (KDesktopFile::isDesktopFile(filePath)) {
274 KSimpleConfig config(filePath, true);
275 config.setDesktopGroup();
276 if (config.readEntry("Type")=="Link") {
277 text=config.readEntry("Name");
278 fileName=filePath;
279 description=config.readEntry("Comment");
280 //kdDebug() << "name: " << text << endl;
281 icon=config.readEntry("Icon");
282 if(icon[0]!='/' && // allow absolute paths for icons
283 TQFile::exists(*it+icon)) // allow icons from icontheme
284 icon=*it+icon;
285 //kdDebug() << "icon2: " << icon << endl;
286 hidden=config.readBoolEntry("X-TDE-Hidden", false);
287 defaultTemplate = config.readBoolEntry("X-TDE-DefaultTemplate", false);
288 measureSystem=config.readEntry("X-TDE-MeasureSystem").lower();
289
290 // Don't add a template that is for the wrong measure system
291 if(measureSystem == dontShow)
292 continue;
293
294 //kdDebug() << "hidden: " << hidden_str << endl;
295 templatePath=config.readPathEntry("URL");
296 //kdDebug() << "Link to : " << templatePath << endl;
297 if(templatePath[0]!='/') {
298 if(templatePath.left(6)=="file:/") // I doubt this will happen
299 templatePath=templatePath.right(templatePath.length()-6);
300 //else
301 // kdDebug() << "dirname=" << *it << endl;
302 templatePath=*it+templatePath;
303 //kdDebug() << "templatePath: " << templatePath << endl;
304 }
305 } else
306 continue; // Invalid
307 }
308 // The else if and the else branch are here for compat. with the old system
309 else if ( files[i].right(4) != ".png" )
310 // Ignore everything that is not a PNG file
311 continue;
312 else {
313 // Found a PNG file - the template must be here in the same dir.
314 icon = filePath;
315 TQFileInfo fi(filePath);
316 text = fi.baseName();
317 templatePath = filePath; // Note that we store the .png file as the template !
318 // That's the way it's always been done. Then the app replaces the extension...
319 }
320 KoTemplate *t=new KoTemplate(text, description, templatePath, icon, fileName,
321 measureSystem, hidden);
322 groupIt.current()->add(t, false, false); // false -> we aren't a "user", false -> don't
323 // "touch" the group to avoid useless
324 // creation of dirs in .kde/blah/...
325 if ( defaultTemplate )
326 m_defaultTemplate = t;
327 }
328 }
329 }
330}
331
332void KoTemplateTree::writeTemplate(KoTemplate *t, KoTemplateGroup *group,
333 const TQString &localDir) {
334 TQString fileName;
335 if ( t->isHidden() )
336 {
337 fileName = t->fileName();
338 // try to remove the file
339 if ( TQFile::remove(fileName) || !TQFile::exists(fileName) )
340 {
341 TQFile::remove( t->name() );
342 TQFile::remove( t->picture() );
343 return;
344 }
345 }
346 // be sure that the template's file name is unique so we don't overwrite an other
347 TQString const path = localDir + group->name() + '/';
348 TQString const name = KoTemplates::stripWhiteSpace( t->name() );
349 fileName = path + name + ".desktop";
350 if ( t->isHidden() && TQFile::exists(fileName) )
351 return;
352 TQString fill;
353 while ( TDEIO::NetAccess::exists( fileName, true, 0 ) )
354 {
355 fill += '_';
356 fileName = path + fill + name + ".desktop";
357 }
358
359 KSimpleConfig config( fileName );
360 config.setDesktopGroup();
361 config.writeEntry("Type", "Link");
362 config.writePathEntry("URL", t->file());
363 config.writeEntry("Name", t->name());
364 config.writeEntry("Icon", t->picture());
365 config.writeEntry("X-TDE-Hidden", t->isHidden());
366}
367
368namespace KoTemplates {
369TQString stripWhiteSpace(const TQString &string) {
370
371 TQString ret;
372 for(unsigned int i=0; i<string.length(); ++i) {
373 TQChar tmp(string[i]);
374 if(!tmp.isSpace())
375 ret+=tmp;
376 }
377 return ret;
378}
379}
TDEAction * find(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
const char * name(StdAction id)