1 | /* |
2 | This program is free software; you can redistribute it and/or |
3 | modify it under the terms of the GNU General Public License |
4 | as published by the Free Software Foundation; either version 2 |
5 | of the License, or (at your option) any later version. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin Street, Fifth Floor, |
15 | Boston, MA 02110-1301, USA. |
16 | |
17 | --- |
18 | Copyright (C) 2004, Anders Lund <anders@alweb.dk> |
19 | */ |
20 | |
21 | //BEGIN Includes |
22 | #include "filetemplates.h" |
23 | |
24 | |
25 | #include <kaboutdata.h> |
26 | #include <kaction.h> |
27 | #include <kactionmenu.h> |
28 | #include <kactioncollection.h> |
29 | #include <kcombobox.h> |
30 | #include <kconfig.h> |
31 | #include <kdialog.h> |
32 | #include <kdirwatch.h> |
33 | #include <kfiledialog.h> |
34 | #include <kglobal.h> |
35 | #include <kicondialog.h> |
36 | #include <kiconloader.h> |
37 | #include <kio/netaccess.h> |
38 | #include <klineedit.h> |
39 | #include <klocale.h> |
40 | #include <kmessagebox.h> |
41 | #include <kstandarddirs.h> |
42 | #include <ktemporaryfile.h> |
43 | #include <kurlrequester.h> |
44 | #include <kuser.h> |
45 | #include <kxmlguifactory.h> |
46 | |
47 | #include <qbuttongroup.h> |
48 | #include <qcheckbox.h> |
49 | #include <qcursor.h> |
50 | #include <qdatetime.h> |
51 | #include <qlabel.h> |
52 | #include <qlayout.h> |
53 | #include <qpushbutton.h> |
54 | #include <qradiobutton.h> |
55 | #include <qregexp.h> |
56 | #include <qstyle.h> |
57 | //Added by qt3to4: |
58 | #include <QTextStream> |
59 | #include <QGridLayout> |
60 | #include <QVBoxLayout> |
61 | #include <QStyle> |
62 | #include <QApplication> |
63 | #include <khbox.h> |
64 | |
65 | #include <QWizardPage> |
66 | #include <QTreeWidget> |
67 | |
68 | #include <stdlib.h> |
69 | |
70 | #include <kdebug.h> |
71 | #include <ktexteditor/templateinterface.h> |
72 | #include <krecentfilesaction.h> |
73 | |
74 | #include <kpluginfactory.h> |
75 | #include <kpluginloader.h> |
76 | #include <kaboutdata.h> |
77 | #include <kmenu.h> |
78 | //END Includes |
79 | |
80 | //BEGIN plugin + factory stuff |
81 | |
82 | K_PLUGIN_FACTORY(KateFileTemplatesFactory, registerPlugin<KateFileTemplates>();) |
83 | K_EXPORT_PLUGIN(KateFileTemplatesFactory(KAboutData("katefiletemplates" ,"katefiletemplates" ,ki18n("File Templates" ), "0.1" , ki18n("Create files from templates" ), KAboutData::License_LGPL_V2)) ) |
84 | |
85 | //END |
86 | |
87 | //BEGIN PluginViewKateFileTemplates |
88 | PluginViewKateFileTemplates::PluginViewKateFileTemplates(KateFileTemplates *plugin, Kate::MainWindow *mainwindow): |
89 | Kate::PluginView(mainwindow),Kate::XMLGUIClient(KateFileTemplatesFactory::componentData()),m_plugin(plugin) |
90 | { |
91 | QAction *a = actionCollection()->addAction("settings_manage_templates" ); |
92 | a->setText(i18n("&Manage Templates..." )); |
93 | connect( a, SIGNAL(triggered(bool)), plugin, SLOT(slotEditTemplate()) ); |
94 | |
95 | a=new KActionMenu( i18n("New From &Template" ), actionCollection()); |
96 | actionCollection()->addAction("file_new_fromtemplate" ,a); |
97 | refreshMenu(); |
98 | |
99 | mainwindow->guiFactory()->addClient (this); |
100 | |
101 | } |
102 | |
103 | void PluginViewKateFileTemplates::() |
104 | { |
105 | m_plugin->refreshMenu( (static_cast<KActionMenu*>(actionCollection()->action("file_new_fromtemplate" )))->menu()); |
106 | } |
107 | |
108 | PluginViewKateFileTemplates::~PluginViewKateFileTemplates() |
109 | { |
110 | mainWindow()->guiFactory()->removeClient (this); |
111 | } |
112 | //END PluginViewKateFileTemplates |
113 | |
114 | //BEGIN TemplateInfo |
115 | class TemplateInfo |
116 | { |
117 | public: |
118 | TemplateInfo( const QString& fn, const QString &t, const QString &g ) |
119 | : filename( fn ), tmplate ( t ), group( g ) { ; } |
120 | ~TemplateInfo() { ; } |
121 | |
122 | QString filename; |
123 | QString tmplate; |
124 | QString group; |
125 | QString description; |
126 | QString author; |
127 | QString highlight; |
128 | QString icon; |
129 | }; |
130 | Q_DECLARE_METATYPE(TemplateInfo*) |
131 | //END TemplateInfo |
132 | |
133 | //BEGIN KateFileTemplates |
134 | KateFileTemplates::KateFileTemplates( QObject* parent, const QList<QVariant> &dummy) |
135 | : Kate::Plugin ( (Kate::Application*)parent) |
136 | { |
137 | Q_UNUSED(dummy) |
138 | // // create actions, so that they are shared. |
139 | // // We plug them into each view's menus, and update them centrally, so that |
140 | // // new plugins can automatically become visible in all windows. |
141 | mActionAny = new KAction ( i18n("Any File..." ), this ); |
142 | connect( mActionAny, SIGNAL(triggered(bool)), this, SLOT(slotAny()) ); |
143 | |
144 | |
145 | // template menu |
146 | m_dw = new KDirWatch( this); |
147 | m_dw->setObjectName( "template_dirwatch" ); |
148 | const QStringList dirs = KGlobal::dirs()->findDirs("data" , "kate/plugins/katefiletemplates/templates" ); |
149 | for ( QStringList::const_iterator it = dirs.begin(); it != dirs.end(); ++it ) |
150 | { |
151 | m_dw->addDir( *it, KDirWatch::WatchFiles ); |
152 | } |
153 | |
154 | connect( m_dw, SIGNAL(dirty(QString)), |
155 | this, SLOT(updateTemplateDirs(QString)) ); |
156 | connect( m_dw, SIGNAL(created(QString)), |
157 | this, SLOT(updateTemplateDirs(QString)) ); |
158 | connect( m_dw, SIGNAL(deleted(QString)), |
159 | this, SLOT(updateTemplateDirs(QString)) ); |
160 | |
161 | // m_templates.setAutoDelete( true ); |
162 | updateTemplateDirs(); |
163 | |
164 | m_user = 0; |
165 | m_emailstuff = 0; |
166 | } |
167 | |
168 | /** |
169 | * Called whenever the template dir is changed. Recreates the templates list. |
170 | */ |
171 | void KateFileTemplates::updateTemplateDirs(const QString &d) |
172 | { |
173 | kDebug()<<"updateTemplateDirs called with arg " <<d; |
174 | |
175 | const QStringList templates = KGlobal::dirs()->findAllResources( |
176 | "data" ,"kate/plugins/katefiletemplates/templates/*.katetemplate" , |
177 | KStandardDirs::NoDuplicates); |
178 | |
179 | m_templates.clear(); |
180 | |
181 | QRegExp re( "\\b(\\w+)\\s*=\\s*(.+)(?:\\s+\\w+=|$)" ); |
182 | re.setMinimal( true ); |
183 | |
184 | KConfigGroup cg( KGlobal::config(), "KateFileTemplates" ); |
185 | QStringList hidden; |
186 | cg.readXdgListEntry( "Hidden" , hidden ); // XXX this is bogus |
187 | |
188 | for ( QStringList::const_iterator it=templates.begin(); it != templates.end(); ++it ) |
189 | { |
190 | QFile _f( *it ); |
191 | if ( _f.open( QIODevice::ReadOnly ) ) |
192 | { |
193 | QString fname = (*it).section( '/', -1 ); |
194 | |
195 | // skip if hidden |
196 | if ( hidden.contains( fname ) ) |
197 | continue; |
198 | |
199 | // Read the first line of the file, to get the group/name |
200 | TemplateInfo *tmp = new TemplateInfo( *it, fname, i18nc( "@item:inmenu" , "Other" ) ); |
201 | bool trymore ( true ); |
202 | QTextStream stream(&_f); |
203 | while ( trymore ) |
204 | { |
205 | QString _line = stream.readLine(); |
206 | trymore = _line.startsWith( "katetemplate:" ); |
207 | if ( ! trymore ) break; |
208 | |
209 | int pos ( 0 ); |
210 | while ( ( ( pos = re.indexIn( _line, pos ) ) >= 0 ) ) |
211 | { |
212 | pos += re.cap( 1 ).length(); |
213 | if ( re.cap( 1 ).toLower() == "template" ) |
214 | tmp->tmplate = i18nc( "@item:inmenu" , re.cap( 2 ).toUtf8() ); |
215 | if ( re.cap( 1 ).toLower() == "group" ) |
216 | tmp->group = i18nc( "@item:inmenu" , re.cap( 2 ).toUtf8() ); |
217 | if ( re.cap( 1 ).toLower() == "description" ) |
218 | tmp->description = i18nc( "@info:whatsthis" , re.cap( 2 ).toUtf8() ); |
219 | if ( re.cap( 1 ).toLower() == "author" ) |
220 | tmp->author = i18nc( "@info:credit" , re.cap( 2 ).toUtf8() ); |
221 | if ( re.cap( 1 ).toLower() == "highlight" ) |
222 | tmp->highlight = re.cap( 2 ); |
223 | if ( re.cap( 1 ) == "icon" ) |
224 | tmp->icon = re.cap( 2 ); |
225 | } |
226 | } |
227 | |
228 | m_templates.append( tmp ); |
229 | _f.close(); |
230 | } |
231 | } |
232 | |
233 | emit triggerMenuRefresh(); |
234 | |
235 | } |
236 | |
237 | KateFileTemplates::~KateFileTemplates() |
238 | { |
239 | // m_acRecentTemplates->saveEntries( KGlobal::config(), "Recent Templates" ); |
240 | delete m_emailstuff; |
241 | delete m_user; |
242 | } |
243 | |
244 | Kate::PluginView *KateFileTemplates::createView (Kate::MainWindow *mainWindow) |
245 | { |
246 | PluginViewKateFileTemplates *view=new PluginViewKateFileTemplates(this,mainWindow); |
247 | connect(this,SIGNAL(triggerMenuRefresh()),view,SLOT(refreshMenu())); |
248 | return view; |
249 | } |
250 | |
251 | QStringList KateFileTemplates::groups() |
252 | { |
253 | QStringList l; |
254 | QString s; |
255 | |
256 | for ( int i = 0; i < m_templates.count(); i++ ) |
257 | { |
258 | s = m_templates[ i ]->group; |
259 | if ( ! l.contains( s ) ) |
260 | l.append( s ); |
261 | } |
262 | |
263 | return l; |
264 | } |
265 | |
266 | void KateFileTemplates::( KMenu * ) |
267 | { |
268 | |
269 | // clear the menu for templates |
270 | menu->clear(); |
271 | |
272 | // restore it |
273 | menu->addAction( mActionAny ); |
274 | menu->addSeparator(); |
275 | |
276 | QMap<QString, QMenu*> ; // ### QMAP |
277 | for ( int i = 0; i < m_templates.count(); i++ ) |
278 | { |
279 | if ( ! submenus[ m_templates[ i ]->group ] ) |
280 | { |
281 | QMenu *sm=menu->addMenu(m_templates[ i ]->group); |
282 | submenus.insert( m_templates[ i ]->group, sm ); |
283 | } |
284 | // kDebug()<<"=== ICON: '"<<m_templates[ i ].icon<<"'"; |
285 | QMenu *sm=submenus[m_templates.at(i)->group]; |
286 | QAction *a; |
287 | if ( ! m_templates[ i ]->icon.isEmpty() ) |
288 | a=sm->addAction( |
289 | KIcon( m_templates[ i ]->icon ), |
290 | m_templates[ i ]->tmplate); |
291 | else |
292 | a=sm->addAction( |
293 | m_templates[ i ]->tmplate); |
294 | a->setData(i); |
295 | connect(a,SIGNAL(triggered(bool)),this,SLOT(slotOpenTemplate())); |
296 | |
297 | // add whatsthis containing the description and author |
298 | QString w ( m_templates[ i ]->description ); |
299 | if( ! m_templates[ i ]->author.isEmpty() ) |
300 | { |
301 | w.append( "<p>" ); |
302 | w.append( i18n("Author: " ) ); |
303 | w.append( m_templates[ i ]->author ); |
304 | } |
305 | if ( ! w.isEmpty() ) |
306 | w.prepend( "<p>" ); |
307 | |
308 | if ( ! w.isEmpty() ) |
309 | a->setWhatsThis( w ); |
310 | } |
311 | } |
312 | |
313 | /** |
314 | * Action slot: use any file as a template. |
315 | * Get a URL and pass it on. |
316 | */ |
317 | void KateFileTemplates::slotAny() |
318 | { |
319 | if (!application()->activeMainWindow()) |
320 | return; |
321 | |
322 | // get a URL and pass that to slotOpenTemplate |
323 | QString fn = KFileDialog::getOpenFileName( |
324 | KUrl(), |
325 | QString(), |
326 | application()->activeMainWindow()->activeView(), |
327 | i18n("Open as Template" ) ); |
328 | if ( ! fn.isEmpty() ) |
329 | slotOpenTemplate( KUrl( fn ) ); |
330 | } |
331 | |
332 | /** |
333 | * converts template [index] to a URL and passes that |
334 | */ |
335 | void KateFileTemplates::slotOpenTemplate() |
336 | { |
337 | int index=static_cast<QAction*>(sender())->data().toInt(); |
338 | kDebug()<<"slotOpenTemplate( " <<index<<" )" ; |
339 | if ( index < 0 || index > m_templates.count() ) return; |
340 | slotOpenTemplate( KUrl( m_templates.at( index )->filename ) ); |
341 | } |
342 | |
343 | void KateFileTemplates::slotOpenTemplate( const KUrl &url ) |
344 | { |
345 | // check if the file can be opened |
346 | QString tmpfile; |
347 | QString filename = url.fileName(); |
348 | kDebug()<<"file: " <<filename; |
349 | if ( KIO::NetAccess::download( url, tmpfile, 0L ) ) |
350 | { |
351 | bool isTemplate ( filename.endsWith( ".katetemplate" ) ); |
352 | QString docname; |
353 | |
354 | // open the file and parse for template variables and macros |
355 | QFile file(tmpfile); |
356 | if ( ! file.open( QIODevice::ReadOnly ) ) |
357 | { |
358 | KMessageBox::sorry( application()->activeMainWindow()->activeView(), |
359 | i18n("<qt>Error opening the file<br /><strong>%1</strong><br />for reading. The document will not be created.</qt>" , filename), |
360 | i18n("Template Plugin" ), 0 ); |
361 | KIO::NetAccess::removeTempFile( tmpfile ); |
362 | return; |
363 | } |
364 | |
365 | // this may take a moment.. |
366 | QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); |
367 | |
368 | // create a new document |
369 | application()->activeMainWindow()->openUrl( KUrl() ); |
370 | KTextEditor::View *view = application()->activeMainWindow()->activeView(); |
371 | KTextEditor::Document *doc = view->document(); |
372 | |
373 | |
374 | QTextStream stream(&file); |
375 | QString str, tmp; |
376 | uint numlines = 0; |
377 | uint = 0; |
378 | while ( !stream.atEnd() ) { |
379 | tmp = stream.readLine(); |
380 | if ( ! numlines && isTemplate && tmp.startsWith( "katetemplate:" ) ) |
381 | { |
382 | // look for document name, highlight |
383 | if ( ! (doneheader & 1) ) |
384 | { |
385 | QRegExp reName( "\\bdocumentname\\s*=\\s*(.+)(?:\\s+\\w+\\s*=|$)" , Qt::CaseInsensitive ); |
386 | reName.setMinimal( true ); |
387 | if ( reName.indexIn( tmp ) > -1 ) |
388 | { |
389 | docname = reName.cap( 1 ); |
390 | docname = docname.replace( "%N" , "%1" ); |
391 | doneheader |= 1; |
392 | } |
393 | } |
394 | |
395 | if ( ! (doneheader & 2) ) |
396 | { |
397 | QRegExp reHl( "\\bhighlight\\s*=\\s*(.+)(?:\\s+\\w+\\s*=|$)" , Qt::CaseInsensitive ); |
398 | reHl.setMinimal( true ); |
399 | kDebug()<<"looking for a hl mode" ; |
400 | if ( reHl.indexIn( tmp ) > -1 ) |
401 | { |
402 | kDebug()<<"looking for a hl mode -- " <<reHl.cap(); |
403 | // this is overly complex, too bad the interface is |
404 | // not providing a reasonable method.. |
405 | QString hlmode = reHl.cap( 1 ); |
406 | doc->setMode (hlmode); |
407 | |
408 | doneheader |= 2; |
409 | } |
410 | } |
411 | |
412 | continue; // skip this line |
413 | } |
414 | if ( numlines ) |
415 | str += '\n'; |
416 | str += tmp; |
417 | numlines++; |
418 | } |
419 | file.close(); |
420 | KIO::NetAccess::removeTempFile( tmpfile ); |
421 | |
422 | uint line, col; |
423 | line = col = 0; |
424 | |
425 | if ( ! isTemplate ) |
426 | { |
427 | int d = filename.lastIndexOf('.'); |
428 | // ### warning i18n: Hack to have localized number later... |
429 | docname = i18n("Untitled %1" , QString("%1" )); |
430 | if ( d > 0 ) docname += filename.mid( d ); |
431 | } else if ( docname.isEmpty() ) |
432 | docname = filename.left( filename.length() - 13 ); |
433 | |
434 | // check for other documents matching this naming scheme, |
435 | // and do a count before choosing a name for this one |
436 | QString p = docname; |
437 | p.replace( "%1" , "\\d+" ); |
438 | p.replace( "." , "\\." ); |
439 | p.prepend( "^" ); |
440 | p.append( "$" ); |
441 | QRegExp reName( p ); |
442 | |
443 | int count = 1; |
444 | const QList<KTextEditor::Document*> docs=application()->documentManager()->documents(); |
445 | foreach(const KTextEditor::Document *doc,docs) { |
446 | if ( ( reName.indexIn( doc->documentName() ) > -1 ) ) |
447 | count++; |
448 | } |
449 | if ( docname.contains( "%1" ) ) |
450 | //### warning i18n: ...localized number here |
451 | |
452 | docname = docname.arg( i18n("%1" , count) ); |
453 | //### warning FIXME, setDocName is gone |
454 | #if 0 |
455 | doc->setDocName( docname ); |
456 | #endif |
457 | doc->setModified( false ); |
458 | |
459 | QApplication::restoreOverrideCursor(); |
460 | // m_acRecentTemplates->addUrl( url ); |
461 | |
462 | // clean up |
463 | delete m_user; |
464 | m_user = 0; |
465 | delete m_emailstuff; |
466 | m_emailstuff = 0; |
467 | if (isTemplate) { |
468 | KTextEditor::TemplateInterface *ti=qobject_cast<KTextEditor::TemplateInterface*>(doc->activeView()); |
469 | ti->insertTemplateText(KTextEditor::Cursor(0,0),str,QMap<QString,QString>()); |
470 | } else { |
471 | doc->insertText( KTextEditor::Cursor(0, 0), str ); |
472 | view->setCursorPosition(KTextEditor::Cursor(line, col)); |
473 | } |
474 | } |
475 | } |
476 | |
477 | |
478 | QWidget *KateFileTemplates::parentWindow() |
479 | { |
480 | return dynamic_cast<QWidget*>(application()->activeMainWindow()); |
481 | } |
482 | |
483 | // The next part are tools to aid the creation and editing of templates |
484 | // ///////////////////////////////////////////////////////////////////// |
485 | // Steps to produce a template |
486 | // * Choose a file to start from (optional) |
487 | // * Ask for a location to store the file -- suggesting either the file |
488 | // directory, or the local template directory. |
489 | // Set the URL |
490 | // * Get the template properties -- provide a dialog, which has filled in what |
491 | // we already know -- the author name, list of known groups |
492 | // |
493 | // Combine those data into the editor, and tell the user to position the cursor |
494 | // and edit the file as she wants to... |
495 | void KateFileTemplates::slotCreateTemplate() |
496 | { |
497 | KateTemplateWizard w( parentWindow(), this ); |
498 | w.exec(); |
499 | |
500 | updateTemplateDirs(); |
501 | } |
502 | |
503 | // Tools for editing the existing templates |
504 | // Editing a template: |
505 | // * Select the template to edit |
506 | // * Open the template |
507 | // * Set the URL to a writable one if required |
508 | void KateFileTemplates::slotEditTemplate() |
509 | { |
510 | KDialog dlg( parentWindow()); |
511 | dlg.setModal(true); |
512 | dlg.setCaption(i18n("Manage File Templates" )); |
513 | dlg.setButtons(KDialog::Close); |
514 | dlg.setMainWidget( new KateTemplateManager( this, &dlg ) ); |
515 | dlg.exec(); |
516 | } |
517 | //END KateFileTemplates |
518 | |
519 | //BEGIN KateTemplateInfoWidget |
520 | // This widget can be used to change the data of a TemplateInfo object |
521 | KateTemplateInfoWidget::KateTemplateInfoWidget( QWidget *parent, TemplateInfo *info, KateFileTemplates *kft ) |
522 | : QWidget( parent ), |
523 | info( info ), |
524 | kft( kft ) |
525 | { |
526 | QGridLayout *lo = new QGridLayout( this ); |
527 | lo->setSpacing( KDialog::spacingHint() ); |
528 | |
529 | QLabel *l = new QLabel( i18n("&Template:" ), this ); |
530 | KHBox *hb = new KHBox( this ); |
531 | hb->setSpacing( KDialog::spacingHint() ); |
532 | leTemplate = new KLineEdit( hb ); |
533 | l->setBuddy( leTemplate ); |
534 | leTemplate->setToolTip( i18n("<p>This string is used as the template's name " |
535 | "and is displayed, for example, in the Template menu. It should describe the " |
536 | "meaning of the template, for example 'HTML Document'.</p>" ) ); |
537 | ibIcon = new KIconButton( hb ); |
538 | ibIcon->setToolTip(i18n( |
539 | "Press to select or change the icon for this template" ) ); |
540 | |
541 | l = new QLabel( i18n("&Group:" ), this ); |
542 | cmbGroup = new KComboBox( true, this ); |
543 | cmbGroup->insertItems( 0, kft->groups() ); |
544 | l->setBuddy( cmbGroup ); |
545 | cmbGroup->setToolTip(i18n("<p>The group is used for choosing a " |
546 | "submenu for the plugin. If it is empty, 'Other' is used.</p>" |
547 | "<p>You can type any string to add a new group to your menu.</p>" ) ); |
548 | |
549 | l = new QLabel( i18n("Document &name:" ), this ); |
550 | leDocumentName = new KLineEdit( this ); |
551 | l->setBuddy( leDocumentName ); |
552 | leDocumentName->setToolTip( i18n("<p>This string will be used to set a name " |
553 | "for the new document, to display in the title bar and file list.</p>" |
554 | "<p>If the string contains '%N', that will be replaced with a number " |
555 | "increasing with each similarly named file.</p><p> For example, if the " |
556 | "Document Name is 'New shellscript (%N).sh', the first document will be " |
557 | "named 'New shellscript (1).sh', the second 'New shellscipt (2).sh', and " |
558 | "so on.</p>" ) ); |
559 | |
560 | l = new QLabel( i18n( "&Highlight:" ), this ); |
561 | btnHighlight = new QPushButton( i18n("None" ), this ); |
562 | l->setBuddy( btnHighlight ); |
563 | btnHighlight->setToolTip( i18n("<p>Select the highlight to use for the " |
564 | "template. If 'None' is chosen, the property will not be set.</p>" ) ); |
565 | |
566 | l = new QLabel( i18n("&Description:" ), this ); |
567 | leDescription = new KLineEdit( this ); |
568 | l->setBuddy( leDescription ); |
569 | leDescription->setToolTip(i18n("<p>This string is used, for example, as " |
570 | "context help for this template (such as the 'whatsthis' help for the " |
571 | "menu item.)</p>" ) ); |
572 | |
573 | l = new QLabel( i18n("&Author:" ), this ); |
574 | leAuthor = new KLineEdit( this ); |
575 | l->setBuddy( leAuthor ); |
576 | leAuthor->setToolTip(i18n("<p>You can set this if you want to share your " |
577 | "template with other users.</p>" |
578 | "<p>the recommended form is like an Email " |
579 | "address: 'Anders Lund <anders@alweb.dk>'</p>" ) ); |
580 | |
581 | // if we have a object ! null |
582 | if ( info ) |
583 | { |
584 | if ( ! info->icon.isEmpty() ) |
585 | ibIcon->setIcon( info->icon ); |
586 | leTemplate->setText( info->tmplate ); |
587 | int i = cmbGroup->findText( info->group ); |
588 | if ( i != -1 ) { |
589 | cmbGroup->setCurrentIndex( i ); |
590 | } else { |
591 | cmbGroup->setEditText( info->group ); |
592 | } |
593 | leDescription->setText( info->description ); |
594 | leAuthor->setText( info->author ); |
595 | if ( ! info->highlight.isEmpty() ) |
596 | btnHighlight->setText( info->highlight ); |
597 | } |
598 | |
599 | // fill in the Hl menu |
600 | KTextEditor::Document *doc = kft->application()->activeMainWindow()->activeView()->document(); |
601 | if ( doc ) |
602 | { |
603 | QStringList highlightModes = doc->highlightingModes(); |
604 | QMenu *m = new QMenu( btnHighlight ); |
605 | connect( m, SIGNAL(triggered(QAction*)), this, SLOT(slotHlSet(QAction*)) ); |
606 | QMap<QString, QMenu*> ; |
607 | for ( int n = 0; n < highlightModes.count(); n++ ) |
608 | { |
609 | // create the sub menu if it does not exist |
610 | QString text( doc->highlightingModeSection( n ) ); |
611 | if ( ! text.isEmpty() ) |
612 | { |
613 | if ( ! submenus[ text ] ) |
614 | { |
615 | QMenu *sm = m->addMenu( text ); |
616 | connect( sm, SIGNAL(triggered(QAction*)), this, SLOT(slotHlSet(QAction*)) ); |
617 | submenus.insert( text, sm ); |
618 | } |
619 | // create the item |
620 | QAction *a = submenus[ text ]->addAction( highlightModes[ n ] ); |
621 | a->setData( n ); |
622 | } |
623 | else { |
624 | QAction *a = m->addAction( highlightModes[ n ] ); |
625 | a->setData( n ); |
626 | } |
627 | } |
628 | btnHighlight->setMenu( m ); |
629 | } |
630 | } |
631 | |
632 | void KateTemplateInfoWidget::slotHlSet( QAction *action ) |
633 | { |
634 | KTextEditor::Document *doc=kft->application()->activeMainWindow()->activeView()->document(); |
635 | if (doc) |
636 | highlightName = doc->highlightingModes()[action->data().toInt()]; |
637 | btnHighlight->setText( action->text() ); // fixme |
638 | } |
639 | //END KateTemplateInfoWidget |
640 | |
641 | //BEGIN KateTemplateWizard |
642 | // A simple wizard to help create a new template :-) |
643 | KateTemplateWizard::KateTemplateWizard( QWidget *parent, KateFileTemplates *kft ) |
644 | : QWizard( parent ), |
645 | kft( kft ) |
646 | { |
647 | // 1) Optionally chose a file or existing template to start from |
648 | QWizardPage *page = new QWizardPage; |
649 | page->setTitle( i18n("Template Origin" ) ); |
650 | page->setSubTitle( i18n("If you want to base this " |
651 | "template on an existing file or template, select the appropriate option " |
652 | "below." ) ); |
653 | |
654 | addPage( page ); |
655 | |
656 | QGridLayout *glo = new QGridLayout( page ); |
657 | glo->setSpacing( KDialog::spacingHint() ); |
658 | |
659 | bgOrigin = new QButtonGroup( page ); |
660 | // bgOrigin->hide(); |
661 | bgOrigin->setExclusive( true ); |
662 | |
663 | QRadioButton *rb = new QRadioButton( i18n("Start with an &empty document" ), page ); |
664 | bgOrigin->addButton( rb, 1 ); |
665 | glo->addWidget( rb, 1, 1, 1, 2 ); |
666 | rb->setChecked( true ); |
667 | |
668 | rb = new QRadioButton( i18n("Use an existing file:" ), page ); |
669 | bgOrigin->addButton( rb, 2 ); |
670 | glo->addWidget( rb, 2, 1, 1, 2 ); |
671 | // ### warning 0 could be wrong here: it crashes with Plastik |
672 | // int marg = rb->style()->subElementRect( QStyle::SE_RadioButtonIndicator, 0,rb ).width(); |
673 | int marg = KDialog::marginHint(); |
674 | glo->addItem( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 3, 1 ); |
675 | urOrigin = new KUrlRequester( page ); |
676 | glo->addWidget( urOrigin, 3, 2 ); |
677 | |
678 | rb = new QRadioButton( i18n("Use an existing template:" ), page ); |
679 | bgOrigin->addButton( rb, 3 ); |
680 | glo->addWidget( rb, 4, 1, 1, 2 ); |
681 | glo->addItem( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 5, 1 ); |
682 | btnTmpl = new QPushButton( page ); |
683 | glo->addWidget( btnTmpl, 5, 2 ); |
684 | QMenu *m = new QMenu( btnTmpl ); |
685 | connect( m, SIGNAL(triggered(QAction*)), this, SLOT(slotTmplateSet(QAction*)) ); |
686 | |
687 | QMap<QString, QMenu*> ; |
688 | for ( int i = 0; i < kft->templates().count(); i++ ) |
689 | { |
690 | if ( ! submenus[ kft->templates()[ i ]->group ] ) |
691 | { |
692 | QMenu *sm = m->addMenu( kft->templates()[ i ]->group ); |
693 | connect( sm, SIGNAL(triggered(QAction*)), this, SLOT(slotTmplateSet(QAction*)) ); |
694 | submenus.insert( kft->templates()[ i ]->group, sm ); |
695 | } |
696 | |
697 | QAction *a = submenus[kft->templates()[ i ]->group]->addAction( |
698 | kft->templates()[ i ]->tmplate ); |
699 | a->setData( i ); |
700 | } |
701 | btnTmpl->setMenu( m ); |
702 | |
703 | connect( bgOrigin, SIGNAL(buttonClicked(int)), this, SLOT(slotStateChanged()) ); |
704 | connect( urOrigin, SIGNAL(textChanged(QString)), this, SLOT(slotStateChanged()) ); |
705 | |
706 | glo->addItem( new QSpacerItem( 1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding ), 7, 7, 1, 2 ); |
707 | |
708 | // 2) edit the template properties |
709 | page = new QWizardPage; |
710 | page->setTitle( i18n("Edit Template Properties" ) ); |
711 | page->setSubTitle( i18n("Specify the main properties of your plugin. You can leave fields empty for which you have no meaningful value." ) ); |
712 | glo = new QGridLayout( page ); |
713 | kti = new KateTemplateInfoWidget( page, 0, kft ); |
714 | glo->addWidget( kti, 1, 1 ); |
715 | addPage( page ); |
716 | |
717 | // get liekly values from KTE |
718 | QMap<QString, QString> map; |
719 | map[ "fullname" ] = "" ; |
720 | map[ "email" ] = "" ; |
721 | |
722 | KTextEditor::TemplateInterface::expandMacros( map, parent ); |
723 | QString sFullname = map["fullname" ]; |
724 | QString sEmail = map["email" ]; |
725 | QString _s = sFullname; |
726 | if ( ! sEmail.isEmpty() ) |
727 | _s += " <" + sEmail + '>'; |
728 | kti->leAuthor->setText( _s ); |
729 | |
730 | // 3) chose a location - either the template directory (default) or |
731 | // a custom location |
732 | page = new QWizardPage; |
733 | page->setTitle( i18n("Choose Location" ) ); |
734 | page->setSubTitle( i18n("<p>Choose a location for the " |
735 | "template. If you store it in the template directory, it will " |
736 | "automatically be added to the template menu.</p>" ) ); |
737 | glo = new QGridLayout( page ); |
738 | glo->setSpacing( KDialog::spacingHint() ); |
739 | |
740 | bgLocation = new QButtonGroup( page ); |
741 | // bgLocation->hide(); |
742 | bgLocation->setExclusive( true ); |
743 | |
744 | rb = new QRadioButton( i18n("Template directory" ), page ); |
745 | bgLocation->addButton( rb, 1 ); |
746 | glo->addWidget( rb, 2, 1, 1, 2 ); |
747 | rb->setChecked( true ); |
748 | |
749 | glo->addItem( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 3, 1, 2, 1 ); |
750 | leTemplateFileName = new KLineEdit( page ); |
751 | QLabel *l = new QLabel( i18n("Template &file name:" ), page ); |
752 | l->setBuddy( leTemplateFileName ); |
753 | |
754 | glo->addWidget( l, 3, 2 ); |
755 | glo->addWidget( leTemplateFileName, 4, 2 ); |
756 | |
757 | rb = new QRadioButton( i18n("Custom location:" ), page ); |
758 | bgLocation->addButton( rb, 2 ); |
759 | glo->addWidget( rb, 5, 1, 1, 2 ); |
760 | |
761 | glo->addItem( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 6, 1 ); |
762 | urLocation = new KUrlRequester( page ); |
763 | glo->addWidget( urLocation, 6, 2 ); |
764 | |
765 | connect( bgLocation, SIGNAL(buttonClicked(int)), this, SLOT(slotStateChanged()) ); |
766 | connect( urLocation, SIGNAL(textChanged(QString)), this, SLOT(slotStateChanged()) ); |
767 | connect( leTemplateFileName, SIGNAL(textChanged(QString)), this, SLOT(slotStateChanged()) ); |
768 | |
769 | glo->addItem( new QSpacerItem( 1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding ), 7, 1, 1, 2 ); |
770 | |
771 | addPage( page ); |
772 | // 4) Should we edit the text to add some macros, replacing username etc? |
773 | // This is *only* relevant if the origin is a non-template file. |
774 | page = new QWizardPage; |
775 | page->setTitle( i18n("Autoreplace Macros" ) ); |
776 | page->setSubTitle( i18n( "You can replace certain strings in the text with " |
777 | "template macros. If any of the data below is incorrect or missing, " |
778 | "edit the data in the personal kaddressbook entry." ) ); |
779 | QVBoxLayout *lo = new QVBoxLayout( page ); |
780 | lo->setSpacing( KDialog::spacingHint() ); |
781 | |
782 | cbRRealname = new QCheckBox( i18n("Replace full name '%1' with the " |
783 | "'%{fullname}' macro" , sFullname ), page ); |
784 | cbRRealname->setEnabled( ! sFullname.isEmpty() ); |
785 | lo->addWidget( cbRRealname ); |
786 | |
787 | cbREmail = new QCheckBox( i18n("Replace email address '%1' with the " |
788 | "'%email' macro" , sEmail ), page); |
789 | cbREmail->setEnabled( ! sEmail.isEmpty() ); |
790 | lo->addWidget( cbREmail ); |
791 | |
792 | lo->addStretch(); |
793 | |
794 | addPage( page ); |
795 | |
796 | // 5) Display a summary |
797 | page = new QWizardPage; |
798 | page->setTitle( i18n("Create Template" ) ); |
799 | page->setSubTitle( i18n("The template will now be created and saved to the chosen " |
800 | "location. To position the cursor put the string ${|} where you " |
801 | "want it in files created from the template." ) ); |
802 | lo = new QVBoxLayout( page ); |
803 | lo->setSpacing( KDialog::spacingHint() ); |
804 | |
805 | cbOpenTemplate = new QCheckBox( i18n("Open the template for editing in Kate" ), page ); |
806 | |
807 | lo->addWidget( cbOpenTemplate ); |
808 | |
809 | lo->addStretch(); |
810 | |
811 | addPage( page ); |
812 | connect( this, SIGNAL(currentIdChanged(int)), this, SLOT(slotStateChanged()) ); |
813 | } |
814 | |
815 | void KateTemplateWizard::slotTmplateSet( QAction *action ) |
816 | { |
817 | int idx = action->data().toInt(); |
818 | btnTmpl->setText( kft->templates().at( idx )->tmplate ); |
819 | selectedTemplateIdx = idx; |
820 | slotStateChanged(); |
821 | } |
822 | |
823 | /** |
824 | * When the state of any button in any setup page is changed, set the |
825 | * enabled state of the next button accordingly. |
826 | * |
827 | * Origin: |
828 | * if file is chosen, the URLRequester must have a valid URL in it |
829 | * if template is chosen, one must be selected in the menu button. |
830 | * |
831 | * Props: |
832 | * anything goes, but if the user wants to store the template in the template |
833 | * directory, she should be encouraged to fill in information. |
834 | */ |
835 | void KateTemplateWizard::slotStateChanged() |
836 | { |
837 | bool sane( true ); |
838 | switch ( currentId() ) |
839 | { |
840 | case 0: // origin |
841 | { |
842 | int _t = bgOrigin->checkedId(); |
843 | kDebug()<<"selected button:" <<_t; |
844 | sane = ( _t == 1 || |
845 | ( _t == 2 && ! urOrigin->url().isEmpty() ) || |
846 | ( _t == 3 && ! btnTmpl->text().isEmpty() ) ); |
847 | // setAppropriate( page(3), _t == 2 ); |
848 | } |
849 | break; |
850 | case 1: // template properties |
851 | // if origin is a existing template, let us try setting some of the properties |
852 | if ( bgOrigin->checkedId() == 3 ) |
853 | { |
854 | TemplateInfo *info = kft->templateInfo( selectedTemplateIdx ); |
855 | int i = kti->cmbGroup->findText( info->group ); |
856 | if ( i != -1 ) { |
857 | kti->cmbGroup->setCurrentIndex( i ); |
858 | } else { |
859 | kti->cmbGroup->setEditText( info->group ); |
860 | } |
861 | } |
862 | break; |
863 | case 2: // location |
864 | { |
865 | // If there is a template name, and the user did not enter text into |
866 | // the template file name entry, we will construct the name from the |
867 | // template name. |
868 | int _t = bgLocation->checkedId(); |
869 | sane = ( ( _t == 1 && (! leTemplateFileName->text().isEmpty() || ! kti->leTemplate->text().isEmpty() ) ) || |
870 | ( _t == 2 && ! urLocation->url().isEmpty() ) ); |
871 | } |
872 | break; |
873 | default: |
874 | break; |
875 | } |
876 | kDebug()<<"enabling 'next' button:" <<sane; |
877 | button( QWizard::NextButton )->setEnabled( sane ); |
878 | } |
879 | |
880 | int KateTemplateWizard::nextId() const |
881 | { |
882 | switch ( currentId() ) |
883 | { |
884 | // case 0: |
885 | // if ( bgOrigin->checkedId() == 2 ) return 2; |
886 | // else return 1; |
887 | default: |
888 | return QWizard::nextId(); |
889 | } |
890 | } |
891 | /** |
892 | * This will create the new template based on the collected information. |
893 | */ |
894 | void KateTemplateWizard::accept() |
895 | { |
896 | // TODO check that everything is kosher, so that we can get a save location |
897 | // etc. |
898 | |
899 | // check that we can combine a valid URL |
900 | KUrl templateUrl; |
901 | if ( bgLocation->checkedId() == 1 ) |
902 | { |
903 | QString suggestion; |
904 | if ( ! leTemplateFileName->text().isEmpty() ) |
905 | suggestion = leTemplateFileName->text(); |
906 | else |
907 | suggestion = kti->leTemplate->text(); |
908 | |
909 | suggestion.remove(' '); |
910 | |
911 | if ( ! suggestion.endsWith(".katetemplate" ) ) |
912 | suggestion.append(".katetemplate" ); |
913 | |
914 | QString dir = KGlobal::dirs()->saveLocation( "data" , "kate/plugins/katefiletemplates/templates/" , true ); |
915 | |
916 | templateUrl = dir + suggestion; |
917 | |
918 | if ( QFile::exists( templateUrl.toLocalFile() ) ) |
919 | { |
920 | if ( KMessageBox::warningContinueCancel( this, i18n( |
921 | "<p>The file <br /><strong>'%1'</strong><br /> already exists; if you " |
922 | "do not want to overwrite it, change the template file name to " |
923 | "something else.</p>" , templateUrl.pathOrUrl() ), |
924 | i18n("File Exists" ), KGuiItem(i18n("Overwrite" ) )) |
925 | == KMessageBox::Cancel ) |
926 | return; |
927 | } |
928 | } |
929 | else |
930 | { |
931 | templateUrl = urLocation->url(); |
932 | } |
933 | |
934 | QWizard::accept(); |
935 | // The following must be done: |
936 | // 1) add the collected template information to the top |
937 | uint ln = 0; |
938 | QString s, str; |
939 | if ( ! kti->leTemplate->text().isEmpty() ) |
940 | s += " Template=" + kti->leTemplate->text(); |
941 | if ( ! kti->cmbGroup->currentText().isEmpty() ) |
942 | s += " Group=" + kti->cmbGroup->currentText(); |
943 | if ( ! kti->leDocumentName->text().isEmpty() ) |
944 | s += " Documentname=" + kti->leDocumentName->text(); |
945 | if ( ! kti->ibIcon->icon().isEmpty() ) |
946 | s += " Icon=" + kti->ibIcon->icon(); |
947 | if ( ! kti->highlightName.isEmpty() && kti->highlightName != "None" ) |
948 | s += " Highlight=" + kti->highlightName; |
949 | |
950 | str = "katetemplate:" + s; |
951 | |
952 | if ( ! (s = kti->leAuthor->text()).isEmpty() ) |
953 | str += "\nkatetemplate: Author=" + s; |
954 | |
955 | if ( ! (s = kti->leDescription->text()).isEmpty() ) |
956 | str += "\nkatetemplate: Description=" + s; |
957 | |
958 | // 2) If a file or template is chosen, open that. and fill the data into a string |
959 | int toid = bgOrigin->checkedId(); // 1 = blank, 2 = file, 3 = template |
960 | kDebug()<<"=== create template: origin type " <<toid; |
961 | if ( toid > 1 ) |
962 | { |
963 | KUrl u; |
964 | if ( toid == 2 ) // file |
965 | u = KUrl( urOrigin->url() ); |
966 | else // template |
967 | u = KUrl( kft->templates().at( selectedTemplateIdx )->filename ); |
968 | |
969 | QString tmpfile, tmp; |
970 | if ( KIO::NetAccess::download( u, tmpfile, 0L ) ) |
971 | { |
972 | QFile file(tmpfile); |
973 | if ( ! file.open( QIODevice::ReadOnly ) ) |
974 | { |
975 | KMessageBox::sorry( this, i18n( |
976 | "<qt>Error opening the file<br /><strong>%1</strong><br />for reading. " |
977 | "The document will not be created</qt>" , u.pathOrUrl()), |
978 | i18n("Template Plugin" ), 0 ); |
979 | |
980 | KIO::NetAccess::removeTempFile( tmpfile ); |
981 | return; |
982 | } |
983 | |
984 | QTextStream stream(&file); |
985 | QString ln; |
986 | bool trymore = true; |
987 | while ( !stream.atEnd() ) |
988 | { |
989 | // skip template headers |
990 | ln = stream.readLine(); |
991 | if ( trymore && ln.startsWith("katetemplate:" ) ) |
992 | continue; |
993 | |
994 | trymore = false; |
995 | tmp += '\n' + ln; |
996 | } |
997 | |
998 | file.close(); |
999 | KIO::NetAccess::removeTempFile( tmpfile ); |
1000 | } |
1001 | |
1002 | if ( toid == 2 ) // file |
1003 | { |
1004 | // 3) if the file is not already a template, escape any "%" and "^" in it, |
1005 | // and try do do some replacement of the authors username, name and email. |
1006 | tmp.replace( QRegExp("%(?=\\{[^}]+\\})" ), "\\%" ); |
1007 | tmp.replace( QRegExp("\\$(?=\\{[^}]+\\})" ), "\\$" ); |
1008 | //tmp.replace( "^", "\\^" ); |
1009 | |
1010 | if ( cbRRealname->isChecked() && ! sFullname.isEmpty() ) |
1011 | tmp.replace( sFullname, "%{realname}" ); |
1012 | |
1013 | |
1014 | if ( cbREmail->isChecked() && ! sEmail.isEmpty() ) |
1015 | tmp.replace( sEmail, "%{email}" ); |
1016 | } |
1017 | |
1018 | str += tmp; |
1019 | } |
1020 | |
1021 | // 4) Save the document to the suggested URL if possible |
1022 | |
1023 | bool succes = false; |
1024 | |
1025 | if ( templateUrl.isValid() ) |
1026 | { |
1027 | if ( templateUrl.isLocalFile() ) |
1028 | { |
1029 | QFile file( templateUrl.toLocalFile() ); |
1030 | if ( file.open(QIODevice::WriteOnly) ) |
1031 | { |
1032 | kDebug()<<"file opened with succes" ; |
1033 | QTextStream stream( &file ); |
1034 | stream << str; |
1035 | file.close(); |
1036 | succes = true; |
1037 | } |
1038 | } |
1039 | else |
1040 | { |
1041 | KTemporaryFile tmp; |
1042 | tmp.open(); |
1043 | QString fn = tmp.fileName(); |
1044 | QTextStream stream( &tmp ); |
1045 | stream << str; |
1046 | stream.flush(); |
1047 | |
1048 | succes = KIO::NetAccess::upload( fn, templateUrl, 0 ); |
1049 | } |
1050 | } |
1051 | |
1052 | if ( ! succes ) |
1053 | { |
1054 | KMessageBox::sorry( this, i18n( |
1055 | "Unable to save the template to '%1'.\n\nThe template will be opened, " |
1056 | "so you can save it from the editor." , templateUrl.pathOrUrl() ), |
1057 | i18n("Save Failed" ) ); |
1058 | |
1059 | kft->application()->activeMainWindow()->openUrl( KUrl() ); |
1060 | KTextEditor::View *view = kft->application()->activeMainWindow()->activeView(); |
1061 | KTextEditor::Document *doc = view->document(); |
1062 | doc->insertText( KTextEditor::Cursor(ln++, 0), str ); |
1063 | } |
1064 | else if ( cbOpenTemplate->isChecked() ) |
1065 | kft->application()->activeMainWindow()->openUrl( templateUrl ); |
1066 | } |
1067 | //END KateTemplateWizard |
1068 | |
1069 | //BEGIN KateTemplateManager |
1070 | KateTemplateManager::KateTemplateManager( KateFileTemplates *kft, QWidget *parent ) |
1071 | : QWidget( parent ) |
1072 | , kft( kft ) |
1073 | { |
1074 | QGridLayout *lo = new QGridLayout( this ); |
1075 | lo->setSpacing( KDialog::spacingHint() ); |
1076 | lvTemplates = new QTreeWidget( this ); |
1077 | lvTemplates->setHeaderLabel( i18n("Template" ) ); |
1078 | lvTemplates->setSelectionMode( QAbstractItemView::SingleSelection ); |
1079 | lo->addWidget( lvTemplates, 1, 1, 1, 4 ); |
1080 | connect( lvTemplates, SIGNAL(itemSelectionChanged()), this, SLOT(slotUpdateState()) ); |
1081 | |
1082 | btnNew = new QPushButton( i18nc("@action:button Template" , "New..." ), this ); |
1083 | connect( btnNew, SIGNAL(clicked()), kft, SLOT(slotCreateTemplate()) ); |
1084 | lo->addWidget( btnNew, 2, 2 ); |
1085 | |
1086 | btnEdit = new QPushButton( i18nc("@action:button Template" , "Edit..." ), this ); |
1087 | connect( btnEdit, SIGNAL(clicked()), this, SLOT(slotEditTemplate()) ); |
1088 | lo->addWidget( btnEdit, 2, 3 ); |
1089 | |
1090 | btnRemove = new QPushButton( i18nc("@action:button Template" , "Remove" ), this ); |
1091 | connect( btnRemove, SIGNAL(clicked()), this, SLOT(slotRemoveTemplate()) ); |
1092 | lo->addWidget( btnRemove, 2, 4 ); |
1093 | |
1094 | lo->setColumnStretch( 1, 1 ); |
1095 | |
1096 | reload(); |
1097 | slotUpdateState(); |
1098 | } |
1099 | |
1100 | void KateTemplateManager::apply() |
1101 | { |
1102 | // if any files were removed, delete them unless they are not writeable, in |
1103 | // which case a link .filename should be put in the writable directory. |
1104 | } |
1105 | |
1106 | #define KATETEMPLATEITEM 1001 |
1107 | void KateTemplateManager::reload() |
1108 | { |
1109 | lvTemplates->clear(); |
1110 | |
1111 | QMap<QString, QTreeWidgetItem*> groupitems; |
1112 | for ( int i = 0; i < kft->templates().count(); i++ ) |
1113 | { |
1114 | if ( ! groupitems[ kft->templates()[ i ]->group ] ) |
1115 | { |
1116 | groupitems.insert( kft->templates()[ i ]->group , new QTreeWidgetItem( lvTemplates ) ); |
1117 | groupitems[ kft->templates()[ i ]->group ]->setText( 0, kft->templates()[ i ]->group ); |
1118 | groupitems[ kft->templates()[ i ]->group ]->setExpanded( true ); |
1119 | } |
1120 | QTreeWidgetItem *item = new QTreeWidgetItem( groupitems[ kft->templates()[ i ]->group ], KATETEMPLATEITEM ); |
1121 | item->setText( 0, kft->templates()[ i ]->tmplate ); |
1122 | item->setData( 0, Qt::UserRole, QVariant::fromValue( kft->templates()[ i ] ) ); |
1123 | } |
1124 | } |
1125 | |
1126 | void KateTemplateManager::slotUpdateState() |
1127 | { |
1128 | // enable/disable buttons wrt the current item in the list view. |
1129 | // we are in single selection mode, so currentItem() is selected. |
1130 | QTreeWidgetItem *item = lvTemplates->currentItem(); |
1131 | bool cool = item && item->type() == KATETEMPLATEITEM; |
1132 | |
1133 | btnEdit->setEnabled( cool ); |
1134 | btnRemove->setEnabled( cool ); |
1135 | } |
1136 | |
1137 | void KateTemplateManager::slotEditTemplate() |
1138 | { |
1139 | // open the template file in kate |
1140 | // TODO show the properties dialog, and modify the file if the data was changed. |
1141 | QList<QTreeWidgetItem*> selection = lvTemplates->selectedItems(); |
1142 | |
1143 | if ( selection.count() ) { |
1144 | QTreeWidgetItem *item = selection[ 0 ]; |
1145 | if ( item->type() != KATETEMPLATEITEM ) |
1146 | return; |
1147 | TemplateInfo *info = item->data(0, Qt::UserRole ).value<TemplateInfo*>(); |
1148 | kft->application()->activeMainWindow()->openUrl( info->filename ); |
1149 | } |
1150 | } |
1151 | |
1152 | void KateTemplateManager::slotRemoveTemplate() |
1153 | { |
1154 | QTreeWidgetItem *item = lvTemplates->selectedItems().first(); |
1155 | if ( item && item->type() == KATETEMPLATEITEM ) |
1156 | { |
1157 | // Find all instances of filename, and try to delete them. |
1158 | // If it fails (there was a global, unwritable instance), add to a |
1159 | // list of removed templates |
1160 | KSharedConfig::Ptr config = KGlobal::config(); |
1161 | TemplateInfo *info = item->data(0, Qt::UserRole).value<TemplateInfo*>(); |
1162 | QString fname = info->filename.section( '/', -1 ); |
1163 | const QStringList templates = KGlobal::dirs()->findAllResources( |
1164 | "data" , fname.prepend( "kate/plugins/katefiletemplates/templates/" ),KStandardDirs::NoDuplicates); |
1165 | int failed = 0; |
1166 | int removed = 0; |
1167 | for ( QStringList::const_iterator it=templates.begin(); it!=templates.end(); ++it ) |
1168 | { |
1169 | if ( ! QFile::remove(*it) ) |
1170 | failed++; |
1171 | else |
1172 | removed++; |
1173 | } |
1174 | |
1175 | if ( failed ) |
1176 | { |
1177 | KConfigGroup cg( config, "KateFileTemplates" ); |
1178 | QStringList l; |
1179 | cg.readXdgListEntry( "Hidden" , l ); // XXX this is bogus |
1180 | l << fname; |
1181 | cg.writeXdgListEntry( "Hidden" , l ); // XXX this is bogus |
1182 | } |
1183 | |
1184 | kft->updateTemplateDirs(); |
1185 | reload(); |
1186 | } |
1187 | } |
1188 | //END KateTemplateManager |
1189 | |
1190 | // kate: space-indent on; indent-width 2; replace-tabs on; |
1191 | |
1192 | #include "filetemplates.moc" |
1193 | |