lib

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