summaryrefslogtreecommitdiffstats
path: root/kate/filetemplates/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'kate/filetemplates/plugin')
-rw-r--r--kate/filetemplates/plugin/Makefile.am25
-rw-r--r--kate/filetemplates/plugin/filetemplates.cpp1254
-rw-r--r--kate/filetemplates/plugin/filetemplates.h258
-rw-r--r--kate/filetemplates/plugin/katefiletemplates.desktop113
-rw-r--r--kate/filetemplates/plugin/katetemplate.xml87
-rw-r--r--kate/filetemplates/plugin/ui.rc15
6 files changed, 1752 insertions, 0 deletions
diff --git a/kate/filetemplates/plugin/Makefile.am b/kate/filetemplates/plugin/Makefile.am
new file mode 100644
index 0000000..7963916
--- /dev/null
+++ b/kate/filetemplates/plugin/Makefile.am
@@ -0,0 +1,25 @@
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+subdirs=src templates
+
+#KDE_ICON = filetemplates
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = katefiletemplates.la
+
+katefiletemplates_la_SOURCES = filetemplates.cpp
+katefiletemplates_la_LIBADD = -lkateinterfaces -lktexteditor $(LIB_KNEWSTUFF)
+katefiletemplates_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+pluginsdir = $(kde_datadir)/kate/plugins/katefiletemplates
+plugins_DATA = ui.rc
+
+syntaxdir = $(kde_datadir)/katepart/syntax
+syntax_DATA = katetemplate.xml
+
+kde_services_DATA = katefiletemplates.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/katefiletemplates.pot
+
diff --git a/kate/filetemplates/plugin/filetemplates.cpp b/kate/filetemplates/plugin/filetemplates.cpp
new file mode 100644
index 0000000..e1eb847
--- /dev/null
+++ b/kate/filetemplates/plugin/filetemplates.cpp
@@ -0,0 +1,1254 @@
+/*
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ ---
+ Copyright (C) 2004, Anders Lund <anders@alweb.dk>
+ */
+
+//BEGIN Includes
+#include "filetemplates.h"
+
+#include <kate/document.h>
+
+#include <kaboutdata.h>
+#include <kaction.h>
+#include <kactioncollection.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdialogbase.h>
+#include <kdirwatch.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <kicondialog.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knewstuff/knewstuff.h>
+#include <knewstuff/entry.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kurlrequester.h>
+#include <kuser.h>
+#include <kxmlguifactory.h>
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qcursor.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qpopupmenu.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qregexp.h>
+#include <qstyle.h>
+#include <qwhatsthis.h>
+
+#include <stdlib.h>
+
+#include <kdebug.h>
+#include <ktexteditor/templateinterface.h>
+//END Includes
+
+//BEGIN plugin + factory stuff
+class PluginView : public KXMLGUIClient
+{
+ friend class KateFileTemplates;
+
+ public:
+ Kate::MainWindow *win;
+};
+
+extern "C"
+{
+ void* init_katefiletemplates()
+ {
+ KGlobal::locale()->insertCatalogue("katefiletemplates");
+ return new KatePluginFactory;
+ }
+}
+
+KatePluginFactory::KatePluginFactory()
+{
+ s_instance = new KInstance( "kate" );
+}
+
+KatePluginFactory::~KatePluginFactory()
+{
+ delete s_instance;
+}
+
+QObject* KatePluginFactory::createObject( QObject* parent, const char* name, const char*, const QStringList & )
+{
+ return new KateFileTemplates( parent, name );
+}
+
+KInstance* KatePluginFactory::s_instance = 0L;
+//END
+
+//BEGIN TemplateInfo
+class TemplateInfo
+{
+ public:
+ TemplateInfo( const QString& fn, const QString &t, const QString &g )
+ : filename( fn ), tmplate ( t ), group( g ) { ; }
+ ~TemplateInfo() { ; }
+
+ QString filename;
+ QString tmplate;
+ QString group;
+ QString description;
+ QString author;
+ QString highlight;
+ QString icon;
+};
+//END TemplateInfo
+
+//BEGIN KateFileTemplates
+KateFileTemplates::KateFileTemplates( QObject* parent, const char* name )
+ : Kate::Plugin ( (Kate::Application*)parent, name ),
+ m_actionCollection( new KActionCollection( this, "template_actions", new KInstance("kate") ) )
+{
+ // create actions, so that they are shared.
+ // We plug them into each view's menus, and update them centrally, so that
+ // new plugins can automatically become visible in all windows.
+ (void) new KAction ( i18n("Any File..."), 0, this,
+ SLOT( slotAny() ), m_actionCollection,
+ "file_template_any" );
+ // recent templates
+ m_acRecentTemplates = new KRecentFilesAction( i18n("&Use Recent"), 0, this,
+ SLOT(slotOpenTemplate(const KURL &)),
+ m_actionCollection,
+ "file_templates_recent" );
+ m_acRecentTemplates->loadEntries( kapp->config(), "Recent Templates" );
+
+ // template menu
+ m_dw = new KDirWatch( this, "template_dirwatch" );
+ QStringList dirs = KGlobal::dirs()->findDirs("data", "kate/plugins/katefiletemplates/templates");
+ for ( QStringList::Iterator it = dirs.begin(); it != dirs.end(); ++it )
+ {
+ m_dw->addDir( *it, true );
+ }
+
+ connect( m_dw, SIGNAL(dirty(const QString&)),
+ this, SLOT(updateTemplateDirs(const QString&)) );
+ connect( m_dw, SIGNAL(created(const QString&)),
+ this, SLOT(updateTemplateDirs(const QString&)) );
+ connect( m_dw, SIGNAL(deleted(const QString&)),
+ this, SLOT(updateTemplateDirs(const QString&)) );
+
+ m_templates.setAutoDelete( true );
+ updateTemplateDirs();
+
+ m_user = 0;
+ m_emailstuff = 0;
+}
+
+/**
+ * Called whenever the template dir is changed. Recreates the templates list.
+ */
+void KateFileTemplates::updateTemplateDirs(const QString &d)
+{
+ kdDebug()<<"updateTemplateDirs called with arg "<<d<<endl;
+
+ QStringList templates = KGlobal::dirs()->findAllResources(
+ "data","kate/plugins/katefiletemplates/templates/*.katetemplate",
+ false,true);
+
+ m_templates.clear();
+
+ QRegExp re( "\\b(\\w+)\\s*=\\s*(.+)(?:\\s+\\w+=|$)" );
+ re.setMinimal( true );
+
+ KConfig *config = kapp->config();
+ QStringList hidden;
+ config->readListEntry( "Hidden", hidden, ';' );
+
+ for ( QStringList::Iterator it=templates.begin(); it != templates.end(); ++it )
+ {
+ QFile _f( *it );
+ if ( _f.open( IO_ReadOnly ) )
+ {
+ QString fname = (*it).section( '/', -1 );
+
+ // skip if hidden
+ if ( hidden.contains( fname ) )
+ continue;
+
+ // Read the first line of the file, to get the group/name
+ TemplateInfo *tmp = new TemplateInfo( *it, fname, "Other" );
+ bool trymore ( true );
+ QTextStream stream(&_f);
+ while ( trymore )
+ {
+ QString _line = stream.readLine();
+ trymore = _line.startsWith( "katetemplate:" );
+ if ( ! trymore ) break;
+
+ int pos ( 0 );
+ while ( ( ( pos = re.search( _line, pos ) ) >= 0 ) )
+ {
+ pos += re.cap( 1 ).length();
+ if ( re.cap( 1 ).lower() == "template" )
+ tmp->tmplate = re.cap( 2 );
+ if ( re.cap( 1 ).lower() == "group" )
+ tmp->group = re.cap( 2 );
+ if ( re.cap( 1 ).lower() == "description" )
+ tmp->description = re.cap( 2 );
+ if ( re.cap( 1 ).lower() == "author" )
+ tmp->author = re.cap( 2 );
+ if ( re.cap( 1 ).lower() == "highlight" )
+ tmp->highlight = re.cap( 2 );
+ if ( re.cap( 1 ) == "icon" )
+ tmp->icon = re.cap( 2 );
+ }
+ }
+
+ m_templates.append( tmp );
+ _f.close();
+ }
+ }
+
+ // update the menus of all views
+ for (uint z=0; z < m_views.count(); z++)
+ {
+ PluginView *view = m_views.at(z);
+ refreshMenu( view );
+ }
+}
+
+KateFileTemplates::~KateFileTemplates()
+{
+ m_acRecentTemplates->saveEntries( kapp->config(), "Recent Templates" );
+ delete m_emailstuff;
+ delete m_user;
+}
+
+void KateFileTemplates::addView(Kate::MainWindow *win)
+{
+ PluginView *view = new PluginView ();
+
+ (void) new KAction( i18n("&Manage Templates..."), 0,
+ this, SLOT(slotEditTemplate()),
+ view->actionCollection(), "settings_manage_templates" );
+
+ (void)new KActionMenu( i18n("New From &Template"), "make",
+ view->actionCollection(), "file_new_fromtemplate" );
+ refreshMenu( view );
+
+ view->setInstance (new KInstance("kate"));
+ view->setXMLFile("plugins/katefiletemplates/ui.rc");
+ win->guiFactory()->addClient (view);
+ view->win = win;
+
+ m_views.append (view);
+}
+
+void KateFileTemplates::removeView(Kate::MainWindow *win)
+{
+ for (uint z=0; z < m_views.count(); z++)
+ if (m_views.at(z)->win == win)
+ {
+ PluginView *view = m_views.at(z);
+ m_views.remove (view);
+ win->guiFactory()->removeClient (view);
+ delete view;
+ }
+}
+
+QStringList KateFileTemplates::groups()
+{
+ QStringList l;
+ QString s;
+
+ for ( uint i = 0; i < m_templates.count(); i++ )
+ {
+ s = m_templates.at( i )->group;
+ if ( ! l.contains( s ) )
+ l.append( s );
+ }
+
+ return l;
+}
+
+void KateFileTemplates::refreshMenu( PluginView *v )
+{
+ QPopupMenu *m = (QPopupMenu*)(((KActionMenu*)(v->actionCollection()->action("file_new_fromtemplate")))->popupMenu());
+
+ // clear the menu for templates
+ m->clear();
+
+ // restore it
+ m_actionCollection->action( "file_template_any" )->plug( m );
+ m_acRecentTemplates->plug( m );
+ m->insertSeparator();
+
+ QDict<QPopupMenu> submenus; // ### QMAP
+ for ( uint i = 0; i < m_templates.count(); i++ )
+ {
+ if ( ! submenus[ m_templates.at( i )->group ] )
+ {
+ QPopupMenu *sm = new QPopupMenu();
+ submenus.insert( m_templates.at( i )->group, sm );
+ m->insertItem( m_templates.at( i )->group, sm );
+ }
+ kdDebug()<<"=== ICON: '"<<m_templates.at( i )->icon<<"'"<<endl;
+ if ( ! m_templates.at( i )->icon.isEmpty() )
+ submenus[m_templates.at( i )->group]->insertItem(
+ SmallIconSet( m_templates.at( i )->icon ),
+ m_templates.at( i )->tmplate, this, SLOT(slotOpenTemplate( int )), 0, i );
+ else
+ submenus[m_templates.at( i )->group]->insertItem(
+ m_templates.at( i )->tmplate, this, SLOT(slotOpenTemplate( int )), 0, i );
+
+ // add whatsthis containing the description and author
+ QString w ( m_templates.at( i )->description );
+ if( ! m_templates.at( i )->author.isEmpty() )
+ {
+ w.append( "<p>Author: " );
+ w.append( m_templates.at( i )->author );
+ }
+ if ( ! w.isEmpty() )
+ w.prepend( "<p>" );
+
+ if ( ! w.isEmpty() )
+ submenus[m_templates.at( i )->group]->findItem( i )->setWhatsThis( w );
+ }
+}
+
+/**
+ * Action slot: use any file as a template.
+ * Get a URL and pass it on.
+ */
+void KateFileTemplates::slotAny()
+{
+ if (!application()->activeMainWindow())
+ return;
+
+ // get a URL and pass that to slotOpenTemplate
+ QString fn = KFileDialog::getOpenFileName(
+ "katefiletemplate",
+ QString::null,
+ application()->activeMainWindow()->viewManager()->activeView(),
+ i18n("Open as Template") );
+ if ( ! fn.isEmpty() )
+ slotOpenTemplate( KURL( fn ) );
+}
+
+/**
+ * converts template [index] to a URL and passes that
+ */
+void KateFileTemplates::slotOpenTemplate( int index )
+{
+ kdDebug()<<"slotOpenTemplate( "<<index<<" )"<<endl;
+ if ( index < 0 || (uint)index > m_templates.count() ) return;
+ slotOpenTemplate( KURL( m_templates.at( index )->filename ) );
+}
+
+void KateFileTemplates::slotOpenTemplate( const KURL &url )
+{
+ // check if the file can be opened
+ QString tmpfile;
+ QString filename = url.fileName();
+ kdDebug()<<"file: "<<filename<<endl;
+ if ( KIO::NetAccess::download( url, tmpfile, 0L ) )
+ {
+ bool isTemplate ( filename.endsWith( ".katetemplate" ) );
+ QString docname;
+
+ // open the file and parse for template variables and macros
+ QFile file(tmpfile);
+ if ( ! file.open( IO_ReadOnly ) )
+ {
+ KMessageBox::sorry( application()->activeMainWindow()->viewManager()->activeView(),
+ i18n("<qt>Error opening the file<br><strong>%1</strong><br>for reading. The document will not be created.</qt>").arg(filename),
+ i18n("Template Plugin"), 0 );
+ KIO::NetAccess::removeTempFile( tmpfile );
+ return;
+ }
+
+ // this may take a moment..
+ kapp->setOverrideCursor( QCursor(QCursor::WaitCursor) );
+
+ // create a new document
+ application()->activeMainWindow()->viewManager()->openURL( KURL() );
+ Kate::View *view = application()->activeMainWindow()->viewManager()->activeView();
+ Kate::Document *doc = view->getDoc();
+
+
+ QTextStream stream(&file);
+ QString str, tmp;
+ uint numlines = 0;
+ uint doneheader = 0;
+ while ( !stream.eof() ) {
+ tmp = stream.readLine();
+ if ( ! numlines && isTemplate && tmp.startsWith( "katetemplate:" ) )
+ {
+ // look for document name, highlight
+ if ( ! (doneheader & 1) )
+ {
+ QRegExp reName( "\\bdocumentname\\s*=\\s*(.+)(?:\\s+\\w+\\s*=|$)", false );
+ reName.setMinimal( true );
+ if ( reName.search( tmp ) > -1 )
+ {
+ docname = reName.cap( 1 );
+ docname = docname.replace( "%N", "%1" );
+ doneheader |= 1;
+ }
+ }
+
+ if ( ! (doneheader & 2) )
+ {
+ QRegExp reHl( "\\bhighlight\\s*=\\s*(.+)(?:\\s+\\w+\\s*=|$)", false );
+ reHl.setMinimal( true );
+ kdDebug()<<"looking for a hl mode"<<endl;
+ if ( reHl.search( tmp ) > -1 )
+ {
+ kdDebug()<<"looking for a hl mode -- "<<reHl.cap()<<endl;
+ // this is overly complex, too bad the interface is
+ // not providing a resonable method..
+ QString hlmode = reHl.cap( 1 );
+ uint _i = 0;
+ while ( _i < doc->hlModeCount() )
+ {
+ if ( doc->hlModeName( _i ) == hlmode )
+ {
+ doc->setHlMode( _i );
+ break;
+ }
+ _i++;
+ }
+
+ doneheader |= 2;
+ }
+ }
+
+ continue; // skip this line
+ }
+ if ( numlines )
+ str += "\n";
+ str += tmp;
+ numlines++;
+ }
+ file.close();
+ KIO::NetAccess::removeTempFile( tmpfile );
+
+ uint line, col;
+ line = col = 0;
+
+ if ( ! isTemplate )
+ {
+ int d = filename.findRev('.');
+ docname = i18n("Untitled %1");
+ if ( d > 0 ) docname += filename.mid( d );
+ } else if ( docname.isEmpty() )
+ docname = filename.left( filename.length() - 13 );
+
+ // check for other documents matching this naming scheme,
+ // and do a count before chosing a name for this one
+ QString p = docname;
+ p.replace( "%1", "\\d+" );
+ p.replace( ".", "\\." );
+ p.prepend( "^" );
+ p.append( "$" );
+ QRegExp reName( p );
+
+ int count = 1;
+ for ( uint i=0; i < application()->documentManager()->documents(); i++ )
+ if ( ( reName.search ( application()->documentManager()->document( i )->docName() ) > -1 ) )
+ count++;
+
+ if ( docname.contains( "%1" ) )
+ docname = docname.arg( count );
+
+ doc->setDocName( docname );
+
+ doc->setModified( false );
+
+ kapp->restoreOverrideCursor();
+ m_acRecentTemplates->addURL( url );
+
+ // clean up
+ delete m_user;
+ m_user = 0;
+ delete m_emailstuff;
+ m_emailstuff = 0;
+ if (isTemplate) {
+ KTextEditor::TemplateInterface *ti=KTextEditor::templateInterface(doc);
+ ti->insertTemplateText(0,0,str,QMap<QString,QString>());
+ } else {
+ doc->insertText( 0, 0, str );
+ view->setCursorPosition( line, col );
+ }
+ }
+}
+
+
+QWidget *KateFileTemplates::parentWindow()
+{
+ return dynamic_cast<QWidget*>(application()->activeMainWindow());
+}
+
+// The next part are tools to aid the creation and editing of templates
+// /////////////////////////////////////////////////////////////////////
+// Steps to produce a template
+// * Choose a file to start from (optional)
+// * Ask for a location to store the file -- suggesting either the file
+// directory, or the local template directory.
+// Set the URL
+// * Get the template properties -- provide a dialog, which has filled in what
+// we already know -- the author name, list of known groups
+//
+// Combine those data into the editor, and tell the user to position the cursor
+// and edit the file as she wants to...
+void KateFileTemplates::slotCreateTemplate()
+{
+ KateTemplateWizard w( parentWindow(), this );
+ w.exec();
+
+ updateTemplateDirs();
+}
+
+// Tools for editing the existing templates
+// Editing a template:
+// * Select the template to edit
+// * Open the template
+// * Set the URL to a writable one if required
+void KateFileTemplates::slotEditTemplate()
+{
+ KDialogBase dlg( parentWindow(), "templatemanager", false, i18n("Manage File Templates"), KDialogBase::Close);
+ dlg.setMainWidget( new KateTemplateManager( this, &dlg ) );
+ dlg.exec();
+}
+//END KateFileTemplates
+
+//BEGIN KateTemplateInfoWidget
+// This widget can be used to change the data of a TemplateInfo object
+KateTemplateInfoWidget::KateTemplateInfoWidget( QWidget *parent, TemplateInfo *info, KateFileTemplates *kft )
+ : QWidget( parent ),
+ info( info ),
+ kft( kft )
+{
+ QGridLayout *lo = new QGridLayout( this, 6, 2 );
+ lo->setAutoAdd( true );
+ lo->setSpacing( KDialogBase::spacingHint() );
+
+ QLabel *l = new QLabel( i18n("&Template:"), this );
+ QHBox *hb = new QHBox( this );
+ hb->setSpacing( KDialogBase::spacingHint() );
+ leTemplate = new QLineEdit( hb );
+ l->setBuddy( leTemplate );
+ QWhatsThis::add( leTemplate, i18n("<p>This string is used as the template's name "
+ "and is displayed, for example, in the Template menu. It should describe the "
+ "meaning of the template, for example 'HTML Document'.</p>") );
+ ibIcon = new KIconButton( hb );
+ QWhatsThis::add( ibIcon, i18n(
+ "Press to select or change the icon for this template") );
+
+ l = new QLabel( i18n("&Group:"), this );
+ cmbGroup = new QComboBox( true, this );
+ cmbGroup->insertStringList( kft->groups() );
+ l->setBuddy( cmbGroup );
+ QWhatsThis::add( cmbGroup, i18n("<p>The group is used for chosing a "
+ "submenu for the plugin. If it is empty, 'Other' is used.</p>"
+ "<p>You can type any string to add a new group to your menu.</p>") );
+
+ l = new QLabel( i18n("Document &name:"), this );
+ leDocumentName = new QLineEdit( this );
+ l->setBuddy( leDocumentName );
+ QWhatsThis::add( leDocumentName, i18n("<p>This string will be used to set a name "
+ "for the new document, to display in the title bar and file list.</p>"
+ "<p>If the string contains '%N', that will be replaced with a number "
+ "increasing with each similarly named file.</p><p> For example, if the "
+ "Document Name is 'New shellscript (%N).sh', the first document will be "
+ "named 'New shellscript (1).sh', the second 'New shellscipt (2).sh', and "
+ "so on.</p>") );
+
+ l = new QLabel( i18n( "&Highlight:"), this );
+ btnHighlight = new QPushButton( i18n("None"), this );
+ l->setBuddy( btnHighlight );
+ QWhatsThis::add( btnHighlight, i18n("<p>Select the highlight to use for the "
+ "template. If 'None' is chosen, the property will not be set.</p>") );
+
+ l = new QLabel( i18n("&Description:"), this );
+ leDescription = new QLineEdit( this );
+ l->setBuddy( leDescription );
+ QWhatsThis::add( leDescription, i18n("<p>This string is used, for example, as "
+ "context help for this template (such as the 'whatsthis' help for the "
+ "menu item.)</p>") );
+
+ l = new QLabel( i18n("&Author:"), this );
+ leAuthor = new QLineEdit( this );
+ l->setBuddy( leAuthor );
+ QWhatsThis::add( leAuthor, i18n("<p>You can set this if you want to share your "
+ "template with other users.</p>"
+ "<p>the recommended form is like an Email "
+ "address: 'Anders Lund &lt;anders@alweb.dk&gt;'</p>") );
+
+ // if we have a object ! null
+ if ( info )
+ {
+ if ( ! info->icon.isEmpty() )
+ ibIcon->setIcon( info->icon );
+ leTemplate->setText( info->tmplate );
+ cmbGroup->setCurrentText( info->group );
+ leDescription->setText( info->description );
+ leAuthor->setText( info->author );
+ if ( ! info->highlight.isEmpty() )
+ btnHighlight->setText( info->highlight );
+ }
+
+ // fill in the Hl menu
+ Kate::Document *doc = kft->application()->documentManager()->activeDocument();
+ if ( doc )
+ {
+ QPopupMenu *m = new QPopupMenu( btnHighlight );
+ connect( m, SIGNAL( activated( int ) ), this, SLOT( slotHlSet( int ) ) );
+ QDict<QPopupMenu> submenus;
+ for ( uint n = 0; n < doc->hlModeCount(); n++ )
+ {
+ // create the sub menu if it does not exist
+ QString text( doc->hlModeSectionName( n ) );
+ if ( ! text.isEmpty() )
+ {
+ if ( ! submenus[ text ] )
+ {
+ QPopupMenu *sm = new QPopupMenu();
+ submenus.insert( text, sm );
+ connect( sm, SIGNAL( activated( int ) ), this, SLOT( slotHlSet( int ) ) );
+ m->insertItem( text, sm );
+ }
+
+ // create the item
+ submenus[ text ]->insertItem( doc->hlModeName( n ), n );
+ }
+ else
+ m->insertItem( doc->hlModeName( n ), n );
+ }
+
+ btnHighlight->setPopup( m );
+ }
+}
+
+void KateTemplateInfoWidget::slotHlSet( int id )
+{
+ btnHighlight->setText(
+ kft->application()->documentManager()->activeDocument()->hlModeName( id ) );
+}
+//END KateTemplateInfoWidget
+
+//BEGIN KateTemplateWizard
+// A simple wizard to help create a new template :-)
+KateTemplateWizard::KateTemplateWizard( QWidget *parent, KateFileTemplates *kft )
+ : KWizard( parent ),
+ kft( kft )
+{
+ // Hide the help button for now
+ helpButton()->hide();
+
+ // 1) Optionally choose a file or existing template to start from
+ QWidget *page = new QWidget( this );
+ QGridLayout *glo = new QGridLayout( page );
+ //lo->setAutoAdd( true );
+ glo->setSpacing( KDialogBase::spacingHint() );
+
+ glo->addMultiCellWidget( new QLabel( i18n("<p>If you want to base this "
+ "template on an existing file or template, select the appropriate option "
+ "below.</p>"), page ), 1, 1, 1, 2);
+ bgOrigin = new QButtonGroup( page );
+ bgOrigin->hide();
+ bgOrigin->setRadioButtonExclusive( true );
+
+ QRadioButton *rb = new QRadioButton( i18n("Start with an &empty document" ), page );
+ bgOrigin->insert( rb, 1 );
+ glo->addMultiCellWidget( rb, 2, 2, 1, 2 );
+ rb->setChecked( true );
+
+ rb = new QRadioButton( i18n("Use an existing file:"), page );
+ bgOrigin->insert( rb, 2 );
+ glo->addMultiCellWidget( rb, 3, 3, 1, 2 );
+ int marg = rb->style().subRect( QStyle::SR_RadioButtonIndicator, rb ).width();
+ glo->addItem( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 4, 1 );
+ urOrigin = new KURLRequester( page );
+ glo->addWidget( urOrigin, 4, 2 );
+
+ rb = new QRadioButton( i18n("Use an existing template:"), page );
+ bgOrigin->insert( rb, 3 );
+ glo->addMultiCellWidget( rb, 5, 5, 1, 2 );
+ glo->addItem( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 6, 1 );
+ btnTmpl = new QPushButton( page );
+ glo->addWidget( btnTmpl, 6, 2 );
+ QPopupMenu *m = new QPopupMenu( btnTmpl );
+ connect( m, SIGNAL( activated( int ) ), this, SLOT( slotTmplateSet( int ) ) );
+
+ QDict<QPopupMenu> submenus;
+ for ( uint i = 0; i < kft->templates().count(); i++ )
+ {
+ if ( ! submenus[ kft->templates().at( i )->group ] )
+ {
+ QPopupMenu *sm = new QPopupMenu();
+ connect( sm, SIGNAL( activated( int ) ), this, SLOT( slotTmplateSet( int ) ) );
+ submenus.insert( kft->templates().at( i )->group, sm );
+ m->insertItem( kft->templates().at( i )->group, sm );
+ }
+
+ submenus[kft->templates().at( i )->group]->insertItem(
+ kft->templates().at( i )->tmplate, i );
+ }
+ btnTmpl->setPopup( m );
+
+ connect( bgOrigin, SIGNAL(clicked(int)), this, SLOT(slotStateChanged(int)) );
+ connect( urOrigin, SIGNAL(textChanged(const QString&)), this, SLOT(slotStateChanged(const QString&)) );
+
+ glo->addMultiCell( new QSpacerItem( 1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding ), 7, 7, 1, 2 );
+
+ addPage( page, i18n("Choose Template Origin") );
+ kdDebug()<<"=== Adding template origin page at "<<page<<endl;
+ // 2) edit the template properties
+ kti = new KateTemplateInfoWidget( this, 0, kft );
+ kdDebug()<<"=== Adding template info page at "<<kti<<endl;
+ addPage( kti, i18n("Edit Template Properties") );
+ // get liekly values from KTE
+ QMap<QString, QString> map;
+ map[ "fullname" ] = "";
+ map[ "email" ] = "";
+
+ KTextEditor::TemplateInterface::expandMacros( map, parent );
+ QString sFullname = map["fullname"];
+ QString sEmail = map["email"];
+ QString _s = sFullname;
+ if ( ! sEmail.isEmpty() )
+ _s += " <" + sEmail + ">";
+ kti->leAuthor->setText( _s );
+
+ // 3) choose a location - either the template directory (default) or
+ // a custom location
+ page = new QWidget( this );
+ glo = new QGridLayout( page, 7, 2 );
+ glo->setSpacing( KDialogBase::spacingHint() );
+
+ glo->addMultiCellWidget( new QLabel( i18n("<p>Choose a location for the "
+ "template. If you store it in the template directory, it will "
+ "automatically be added to the template menu.</p>"), page ), 1, 1, 1, 2);
+
+ bgLocation = new QButtonGroup( page );
+ bgLocation->hide();
+ bgLocation->setRadioButtonExclusive( true );
+
+ rb = new QRadioButton( i18n("Template directory"), page );
+ bgLocation->insert( rb, 1 );
+ glo->addMultiCellWidget( rb, 2, 2, 1, 2 );
+ rb->setChecked( true );
+
+ glo->addMultiCell( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 3, 4, 1, 1 );
+ leTemplateFileName = new QLineEdit( page );
+ QLabel *l = new QLabel( leTemplateFileName, i18n("Template &file name:"), page );
+
+ glo->addWidget( l, 3, 2 );
+ glo->addWidget( leTemplateFileName, 4, 2 );
+
+ rb = new QRadioButton( i18n("Custom location:"), page );
+ bgLocation->insert( rb, 2 );
+ glo->addMultiCellWidget( rb, 5, 5, 1, 2 );
+
+ glo->addItem( new QSpacerItem( marg, 1, QSizePolicy::Fixed ), 6, 1 );
+ urLocation = new KURLRequester( page );
+ glo->addWidget( urLocation, 6, 2 );
+
+ connect( bgLocation, SIGNAL(clicked(int)), this, SLOT(slotStateChanged(int)) );
+ connect( urLocation, SIGNAL(textChanged(const QString&)), this, SLOT(slotStateChanged(const QString&)) );
+ connect( leTemplateFileName, SIGNAL(textChanged(const QString &)), this, SLOT(slotStateChanged(const QString &)) );
+
+ glo->addMultiCell( new QSpacerItem( 1, 1, QSizePolicy::Expanding, QSizePolicy::Expanding ), 7, 7, 1, 2 );
+
+ addPage( page, i18n("Choose Location") );
+ kdDebug()<<"=== Adding location page at "<<page<<endl;
+ // 4) Should we edit the text to add some macros, replacing username etc?
+ // This is *only* relevant if the origin is a non-template file.
+ page = new QWidget( this );
+ QVBoxLayout *lo = new QVBoxLayout( page );
+ lo->setSpacing( KDialogBase::spacingHint() );
+
+ lo->addWidget(
+ new QLabel( i18n( "<p>You can replace certain strings in the text with "
+ "template macros.<p>If any of the data below is incorrect or missing, "
+ "edit the data in the KDE email information."), page ) );
+
+ cbRRealname = new QCheckBox( i18n("Replace full name '%1' with the "
+ "'%{fullname}' macro").arg( sFullname ), page );
+ cbRRealname->setEnabled( ! sFullname.isEmpty() );
+ lo->addWidget( cbRRealname );
+
+ cbREmail = new QCheckBox( i18n("Replace email address '%1' with the "
+ "'%email' macro").arg( sEmail ), page);
+ cbREmail->setEnabled( ! sEmail.isEmpty() );
+ lo->addWidget( cbREmail );
+
+ lo->addStretch();
+
+ addPage( page, i18n("Autoreplace Macros") );
+ kdDebug()<<"=== Adding autoreplace page at "<<page<<endl;
+ // 5) Display a summary
+ page = new QWidget( this );
+ lo = new QVBoxLayout( page );
+ lo->setSpacing( KDialogBase::spacingHint() );
+
+ QString s = i18n("<p>The template will now be created and saved to the chosen "
+ "location. To position the cursor put a caret ('^') character where you "
+ "want it in files created from the template.</p>");
+
+ lo->addWidget( new QLabel( s, page ) );
+
+ cbOpenTemplate = new QCheckBox( i18n("Open the template for editing"), page );
+
+ lo->addWidget( cbOpenTemplate );
+
+ lo->addStretch();
+
+ addPage( page, i18n("Create Template") );
+ kdDebug()<<"=== Adding summary page at "<<endl;
+ connect( this, SIGNAL(selected(const QString&)), this, SLOT(slotStateChanged(const QString&)) );
+}
+
+void KateTemplateWizard::slotTmplateSet( int idx )
+{
+ btnTmpl->setText( kft->templates().at( idx )->tmplate );
+ selectedTemplateIdx = idx;
+ slotStateChanged();
+}
+
+/**
+ * When the state of any button in any setup page is changed, set the
+ * enabled state of the next button accordingly.
+ *
+ * Origin:
+ * if file is chosen, the URLRequester must have a valid URL in it
+ * if template is chosen, one must be selected in the menu button.
+ *
+ * Props:
+ * anything goes, but if the user wants to store the template in the template
+ * directory, she should be encouraged to fill in information.
+*/
+void KateTemplateWizard::slotStateChanged()
+{
+ bool sane( true );
+ switch ( indexOf( currentPage() ) )
+ {
+ case 0: // origin
+ {
+ int _t = bgOrigin->selectedId();
+ sane = ( _t == 1 ||
+ ( _t == 2 && ! urOrigin->url().isEmpty() ) ||
+ ( _t == 3 && ! btnTmpl->text().isEmpty() ) );
+ setAppropriate( page(3), _t == 2 );
+ }
+ break;
+ case 1: // template properties
+ // if origin is a existing template, let us try setting some of the properties
+ if ( bgOrigin->selectedId() == 3 )
+ {
+ TemplateInfo *info = kft->templateInfo( selectedTemplateIdx );
+ kti->cmbGroup->setCurrentText( info->group );
+ }
+ break;
+ case 2: // location
+ {
+ // If there is a template name, and the user did not enter text into
+ // the template file name entry, we will construct the name from the
+ // template name.
+ int _t = bgLocation->selectedId();
+ sane = ( ( _t == 1 && (! leTemplateFileName->text().isEmpty() || ! kti->leTemplate->text().isEmpty() ) ) ||
+ ( _t == 2 && ! urLocation->url().isEmpty() ) );
+ }
+ break;
+ case 4: // summary
+ setFinishEnabled( currentPage(), true );
+ break;
+ default:
+ break;
+ }
+ nextButton()->setEnabled( sane );
+}
+
+/**
+ * This will create the new template based on the collected information.
+ */
+void KateTemplateWizard::accept()
+{
+ // TODO check that everything is kosher, so that we can get a save location
+ // etc.
+
+ // check that we can combine a valid URL
+ KURL templateUrl;
+ if ( bgLocation->selectedId() == 1 )
+ {
+ QString suggestion;
+ if ( ! leTemplateFileName->text().isEmpty() )
+ suggestion = leTemplateFileName->text();
+ else
+ suggestion = kti->leTemplate->text();
+
+ suggestion.replace(" ", "");
+
+ if ( ! suggestion.endsWith(".katetemplate") )
+ suggestion.append(".katetemplate");
+
+ QString dir = KGlobal::dirs()->saveLocation( "data", "kate/plugins/katefiletemplates/templates/", true );
+
+ templateUrl = dir + suggestion;
+
+ if ( QFile::exists( templateUrl.path() ) )
+ {
+ if ( KMessageBox::warningContinueCancel( this, i18n(
+ "<p>The file <br><strong>'%1'</strong><br> already exists; if you "
+ "do not want to overwrite it, change the template file name to "
+ "something else.").arg( templateUrl.prettyURL() ),
+ i18n("File Exists"), i18n("Overwrite") )
+ == KMessageBox::Cancel )
+ return;
+ }
+ }
+ else
+ {
+ templateUrl = urLocation->url();
+ }
+
+ QWizard::accept();
+ // The following must be done:
+ // 1) add the collected template information to the top
+ uint ln = 0;
+ QString s, str;
+ if ( ! kti->leTemplate->text().isEmpty() )
+ s += " Template=" + kti->leTemplate->text();
+ if ( ! kti->cmbGroup->currentText().isEmpty() )
+ s += " Group=" + kti->cmbGroup->currentText();
+ if ( ! kti->leDocumentName->text().isEmpty() )
+ s += " Documentname=" + kti->leDocumentName->text();
+ if ( ! kti->ibIcon->icon().isEmpty() )
+ s += " Icon=" + kti->ibIcon->icon();
+ if ( ! kti->btnHighlight->text().isEmpty() )
+ s += " Highlight=" + kti->btnHighlight->text();
+
+ str = "katetemplate:" + s;
+
+ if ( ! (s = kti->leAuthor->text()).isEmpty() )
+ str += "\nkatetemplate: Author=" + s;
+
+ if ( ! (s = kti->leDescription->text()).isEmpty() )
+ str += "\nkatetemplate: Description=" + s;
+
+ // 2) If a file or template is chosen, open that. and fill the data into a string
+ int toid = bgOrigin->selectedId(); // 1 = blank, 2 = file, 3 = template
+ kdDebug()<<"=== create template: origin type "<<toid<<endl;
+ if ( toid > 1 )
+ {
+ KURL u;
+ if ( toid == 2 ) // file
+ u = KURL( urOrigin->url() );
+ else // template
+ u = KURL( kft->templates().at( selectedTemplateIdx )->filename );
+
+ QString tmpfile, tmp;
+ if ( KIO::NetAccess::download( u, tmpfile, 0L ) )
+ {
+ QFile file(tmpfile);
+ if ( ! file.open( IO_ReadOnly ) )
+ {
+ KMessageBox::sorry( this, i18n(
+ "<qt>Error opening the file<br><strong>%1</strong><br>for reading. "
+ "The document will not be created</qt>").arg(u.prettyURL()),
+ i18n("Template Plugin"), 0 );
+
+ KIO::NetAccess::removeTempFile( tmpfile );
+ return;
+ }
+
+ QTextStream stream(&file);
+ QString ln;
+ bool trymore = true;
+ while ( !stream.eof() )
+ {
+ // skip template headers
+ ln = stream.readLine();
+ if ( trymore && ln.startsWith("katetemplate:") )
+ continue;
+
+ trymore = false;
+ tmp += "\n" + ln;
+ }
+
+ file.close();
+ KIO::NetAccess::removeTempFile( tmpfile );
+ }
+
+ if ( toid == 2 ) // file
+ {
+ // 3) if the file is not already a template, escape any "%" and "^" in it,
+ // and try do do some replacement of the authors username, name and email.
+ tmp.replace( QRegExp("%(?=\\{[^}]+\\})"), "\\%" );
+ tmp.replace( QRegExp("\\$(?=\\{[^}]+\\})"), "\\$" );
+ //tmp.replace( "^", "\\^" );
+
+ if ( cbRRealname->isChecked() && ! sFullname.isEmpty() )
+ tmp.replace( sFullname, "%{realname}" );
+
+
+ if ( cbREmail->isChecked() && ! sEmail.isEmpty() )
+ tmp.replace( sEmail, "%{email}" );
+ }
+
+ str += tmp;
+ }
+
+ // 4) Save the document to the suggested URL if possible
+
+ bool succes = false;
+
+ if ( templateUrl.isValid() )
+ {
+ if ( templateUrl.isLocalFile() )
+ {
+ QFile file( templateUrl.path() );
+ if ( file.open(IO_WriteOnly) )
+ {
+ kdDebug()<<"file opened with succes"<<endl;
+ QTextStream stream( &file );
+ stream << str;
+ file.close();
+ succes = true;
+ }
+ }
+ else
+ {
+ KTempFile tmp;
+ QString fn = tmp.name();
+ QTextStream stream( tmp.file() );
+ stream << str;
+ tmp.close();
+
+ succes = KIO::NetAccess::upload( fn, templateUrl, 0 );
+ KIO::NetAccess::removeTempFile( fn );
+ }
+ }
+
+ if ( ! succes )
+ {
+ KMessageBox::sorry( this, i18n(
+ "Unable to save the template to '%1'.\n\nThe template will be opened, "
+ "so you can save it from the editor.").arg( templateUrl.prettyURL() ),
+ i18n("Save Failed") );
+
+ kft->application()->activeMainWindow()->viewManager()->openURL( KURL() );
+ Kate::View *view = kft->application()->activeMainWindow()->viewManager()->activeView();
+ Kate::Document *doc = view->getDoc();
+ doc->insertText( ln++, 0, str );
+ }
+ else if ( cbOpenTemplate->isChecked() )
+ kft->application()->activeMainWindow()->viewManager()->openURL( templateUrl );
+}
+//END KateTemplateWizard
+
+//BEGIN KateTemplateItem
+class KateTemplateItem : public KListViewItem
+{
+ public:
+ KateTemplateItem( KListViewItem *parent, TemplateInfo *templateinfo )
+ : KListViewItem( parent, templateinfo->tmplate ), templateinfo( templateinfo )
+ {
+ }
+ TemplateInfo *templateinfo;
+};
+//END KateTemplateItem
+
+//BEGIN KFTNewStuff
+class KFTNewStuff : public KNewStuff {
+ public:
+ KFTNewStuff( const QString &type, QWidget *parent=0 ) : KNewStuff( type, parent ), m_win( parent ) {}
+ ~KFTNewStuff() {}
+ bool install( const QString &/*filename*/ ) { return true; }
+ bool createUploadFile( const QString &/*filename*/ ) { return false; }
+ QString downloadDestination( KNS::Entry *entry )
+ {
+ QString dir = KGlobal::dirs()->saveLocation( "data", "kate/plugins/katefiletemplates/templates/", true );
+ return dir.append( entry->payload().filename() );
+ }
+
+ private:
+ QWidget *m_win;
+};
+//END KTNewStuff
+
+//BEGIN KateTemplateManager
+KateTemplateManager::KateTemplateManager( KateFileTemplates *kft, QWidget *parent, const char *name )
+ : QWidget( parent, name )
+ , kft( kft )
+{
+ QGridLayout *lo = new QGridLayout( this, 2, 6 );
+ lo->setSpacing( KDialogBase::spacingHint() );
+ lvTemplates = new KListView( this );
+ lvTemplates->addColumn( i18n("Template") );
+ lo->addMultiCellWidget( lvTemplates, 1, 1, 1, 6 );
+ connect( lvTemplates, SIGNAL(selectionChanged()), this, SLOT(slotUpdateState()) );
+
+ btnNew = new QPushButton( i18n("New..."), this );
+ connect( btnNew, SIGNAL(clicked()), kft, SLOT(slotCreateTemplate()) );
+ lo->addWidget( btnNew, 2, 2 );
+
+ btnEdit = new QPushButton( i18n("Edit..."), this );
+ connect( btnEdit, SIGNAL(clicked()), this, SLOT( slotEditTemplate()) );
+ lo->addWidget( btnEdit, 2, 3 );
+
+ btnRemove = new QPushButton( i18n("Remove"), this );
+ connect( btnRemove, SIGNAL(clicked()), this, SLOT(slotRemoveTemplate()) );
+ lo->addWidget( btnRemove, 2, 4 );
+
+ btnUpload = new QPushButton( i18n("Upload..."), this );
+ connect( btnUpload, SIGNAL(clicked()), this, SLOT(slotUpload()) );
+ lo->addWidget( btnUpload, 2, 5 );
+
+ btnDownload = new QPushButton( i18n("Download..."), this );
+ connect( btnDownload, SIGNAL(clicked()), this, SLOT(slotDownload()) );
+ lo->addWidget( btnDownload, 2, 6 );
+
+ lo->setColStretch( 1, 1 );
+
+ reload();
+ slotUpdateState();
+}
+
+void KateTemplateManager::apply()
+{
+ // if any files were removed, delete them unless they are not writeable, in
+ // which case a link .filename should be put in the writable directory.
+}
+
+void KateTemplateManager::reload()
+{
+ lvTemplates->clear();
+
+ QDict<KListViewItem> groupitems; // FIXME QMAP
+ for ( uint i = 0; i < kft->templates().count(); i++ )
+ {
+ if ( ! groupitems[ kft->templates().at( i )->group ] )
+ {
+ groupitems.insert( kft->templates().at( i )->group , new KListViewItem( lvTemplates, kft->templates().at( i )->group ) );
+ groupitems[ kft->templates().at( i )->group ]->setOpen( true );
+ }
+ new KateTemplateItem( groupitems[ kft->templates().at( i )->group ], kft->templates().at( i ) );
+ }
+}
+
+void KateTemplateManager::slotUpdateState()
+{
+ // enable/disable buttons wrt the current item in the list view.
+ // we are in single selection mode, so currentItem() is selected.
+ bool cool = false;
+ if ( dynamic_cast<KateTemplateItem*>( lvTemplates->currentItem() ) )
+ cool = true;
+
+ btnEdit->setEnabled( cool );
+ btnRemove->setEnabled( cool );
+ btnUpload->setEnabled( cool );
+}
+
+void KateTemplateManager::slotEditTemplate()
+{
+ // open the template file in kate
+ // TODO show the properties dialog, and modify the file if the data was changed.
+ KateTemplateItem *item = dynamic_cast<KateTemplateItem*>( lvTemplates->currentItem() );
+ if ( item )
+ kft->application()->activeMainWindow()->viewManager()->openURL( item->templateinfo->filename );
+}
+
+void KateTemplateManager::slotRemoveTemplate()
+{
+ KateTemplateItem *item = dynamic_cast<KateTemplateItem*>( lvTemplates->currentItem() );
+ if ( item )
+ {
+ // Find all instances of filename, and try to delete them.
+ // If it fails (there was a global, unwritable instance), add to a
+ // list of removed templates
+ KConfig *config = kapp->config();
+ QString fname = item->templateinfo->filename.section( '/', -1 );
+ QStringList templates = KGlobal::dirs()->findAllResources(
+ "data", fname.prepend( "kate/plugins/katefiletemplates/templates/" ),
+ false,true);
+ int failed = 0;
+ int removed = 0;
+ for ( QStringList::Iterator it=templates.begin(); it!=templates.end(); ++it )
+ {
+ if ( ! QFile::remove(*it) )
+ failed++;
+ else
+ removed++;
+ }
+
+ if ( failed )
+ {
+ config->setGroup( "KateFileTemplates" );
+ QStringList l;
+ config->readListEntry( "Hidden", l, ';' );
+ l << fname;
+ config->writeEntry( "Hidden", l, ';' );
+ }
+
+ // If we removed any files, we should delete a KNewStuff key
+ // for this template, so the template is installable again.
+ // ### This assumes that the knewstuff name is similar to the template name.
+ kdDebug()<<"trying to remove knewstuff key '"<<item->templateinfo->tmplate<<"'"<<endl;
+ config->setGroup("KNewStuffStatus");
+ config->deleteEntry( item->templateinfo->tmplate );
+
+
+ kft->updateTemplateDirs();
+ reload();
+ }
+}
+
+// KNewStuff upload
+void KateTemplateManager::slotUpload()
+{
+ // TODO something nicer, like preparing the meta data from the template info.
+ KateTemplateItem *item = dynamic_cast<KateTemplateItem*>( lvTemplates->currentItem() );
+ if ( item )
+ {
+ KFTNewStuff *ns = new KFTNewStuff( "katefiletemplates/template", this );
+ ns->upload( item->templateinfo->filename, QString::null );
+ }
+}
+
+// KNewStuff download
+void KateTemplateManager::slotDownload()
+{
+ KFTNewStuff *ns = new KFTNewStuff( "katefiletemplates/template", this );
+ ns->download();
+
+ kft->updateTemplateDirs();
+ reload();
+}
+
+//END KateTemplateManager
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
+#include "filetemplates.moc"
diff --git a/kate/filetemplates/plugin/filetemplates.h b/kate/filetemplates/plugin/filetemplates.h
new file mode 100644
index 0000000..0eedc38
--- /dev/null
+++ b/kate/filetemplates/plugin/filetemplates.h
@@ -0,0 +1,258 @@
+/*
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ ---
+ Copyright (C) 2004, Anders Lund <anders@alweb.dk>
+ */
+
+#ifndef _PLUGIN_KATE_FILETEMPLATES_H_
+#define _PLUGIN_KATE_FILETEMPLATES_H_
+
+#include <kate/application.h>
+#include <kate/documentmanager.h>
+#include <kate/document.h>
+#include <kate/mainwindow.h>
+#include <kate/plugin.h>
+#include <kate/view.h>
+#include <kate/viewmanager.h>
+
+#include <klibloader.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kwizard.h>
+
+#include <qptrlist.h>
+
+class KatePluginFactory : public KLibFactory
+{
+ Q_OBJECT
+
+ public:
+ KatePluginFactory();
+ virtual ~KatePluginFactory();
+
+ virtual QObject* createObject( QObject* parent = 0, const char* pname = 0, const char* name = "QObject", const QStringList &args = QStringList() );
+
+ private:
+ static KInstance* s_instance;
+};
+
+/**
+ * This template system has the following features:
+ * It allows to create new documents that allready has some contents and a meaningfull
+ * document name.
+ *
+ * Any file can b e used as a template.
+ *
+ * Special template files can contain macros that are expanded when the document
+ * is created, and the cursor can be positioned in the new document.
+ *
+ * A menu is provided, allowing access to templates located in the KDE file system
+ * in the plugins data directory. The menu is dynamically updated.
+ *
+ * Simple tools are provided for creating/eidting templates.
+ *
+ * The main class has methods to do all of the work related to use file templates:
+ * @li Maintain the Template menu (File, New from Template)
+ * @li Load templates
+ * @li Provide simple tools for creating/editing templates
+*/
+class KateFileTemplates : public Kate::Plugin, public Kate::PluginViewInterface
+{
+ Q_OBJECT
+
+ public:
+ KateFileTemplates( QObject* parent = 0, const char* name = 0 );
+ virtual ~KateFileTemplates();
+
+ void addView (Kate::MainWindow *win);
+ void removeView (Kate::MainWindow *win);
+
+ /**
+ * @return a list of unique group names in the template list.
+ */
+ QStringList groups();
+
+ /**
+ * @return a pointer to the templateinfo collection
+ */
+ QPtrList<class TemplateInfo> templates() { return m_templates; }
+
+ /**
+ * @return a pointer to the templateInfo for the template at @p index
+ * in the template collection.
+ */
+ class TemplateInfo *templateInfo( int index ) { return m_templates.at( index ); }
+
+ /**
+ * @return a a pointer to the active main window
+ */
+ QWidget * parentWindow();
+
+ public slots:
+ /**
+ * Update the template collection by rereading the template
+ * directories. Also updates the menu.
+ */
+ void updateTemplateDirs(const QString &s=QString::null);
+
+ private slots:
+ /**
+ * Show a file dialog, so that any file can be opened as a template.
+ * If the chosen file has the .katetemplate extension, it is parsed,
+ * otherwise it is just copied to the new document.
+ */
+ void slotAny();
+
+ /**
+ * Open the template found at @p index in the colletion
+ */
+ void slotOpenTemplate( int index );
+
+ /**
+ * Open the file at @p url as a template. If it has the .katetemplate
+ * extension it is parsed, otherwise its content is just copied to the new
+ * document.
+ */
+ void slotOpenTemplate( const KURL &url );
+
+ void slotEditTemplate();
+
+ /**
+ * Show a KateTemplateWizard wizard.
+ */
+ void slotCreateTemplate();
+
+ private:
+ void refreshMenu( class PluginView */*class QPopupMenu **/ );
+
+ QPtrList<class PluginView> m_views;
+ class KActionCollection *m_actionCollection;
+ class KRecentFilesAction *m_acRecentTemplates;
+ QPtrList<class TemplateInfo> m_templates;
+ class KDirWatch *m_dw;
+ class KUser *m_user;
+ class KConfig *m_emailstuff;
+ class KActionMenu *m_menu;
+};
+
+class TemplateInfo;
+
+/**
+ * This widget provide a GUI for editing template properties.
+ */
+class KateTemplateInfoWidget : public QWidget
+{
+ Q_OBJECT
+ public:
+ KateTemplateInfoWidget( QWidget *parent=0, TemplateInfo *info=0, KateFileTemplates *kft=0 );
+ ~KateTemplateInfoWidget() {}
+
+ TemplateInfo *info;
+
+ class QLineEdit *leTemplate, *leDocumentName, *leDescription, *leAuthor;
+ class QComboBox *cmbGroup;
+ class QPushButton *btnHighlight;
+ class KIconButton *ibIcon;
+
+ private slots:
+ void slotHlSet( int id );
+
+ private:
+ KateFileTemplates *kft;
+};
+
+/**
+ * This wizard helps creating a new template, which is then opened for the user
+ * to edit.
+ * Basically, the user is offered to select an existing file or template to start
+ * from, set template properties, and if a file is loaded, some replacements is
+ * done in the text:
+ * @li % characters are protected (% -> %%)
+ * @li ^ characters are protected (with a backsplash)
+ * @li The users name, username and email is replaced by the corresponding macros
+ * If so chosen, the file is saved to either the template directory, or a location
+ * set by the user.
+*/
+class KateTemplateWizard : public KWizard
+{
+ friend class KateFileTemplates;
+ Q_OBJECT
+ public:
+ KateTemplateWizard( QWidget* parent, KateFileTemplates *ktf );
+ ~KateTemplateWizard() {}
+
+ public slots:
+ void accept();
+
+ private slots:
+ void slotTmplateSet( int );
+ void slotStateChanged();
+ void slotStateChanged( int ) { slotStateChanged(); }
+ void slotStateChanged( const QString& ) { slotStateChanged(); }
+
+ private:
+ KateFileTemplates *kft;
+ KateTemplateInfoWidget *kti;
+
+ // origin page
+ class QButtonGroup *bgOrigin;
+ class KURLRequester *urOrigin;
+ class QPushButton *btnTmpl;
+ uint selectedTemplateIdx;
+
+ // location page
+ class QButtonGroup *bgLocation;
+ class KURLRequester *urLocation;
+ class QLineEdit *leTemplateFileName;
+
+ // macro replacement page
+ class QCheckBox *cbRRealname, *cbRUsername, *cbREmail;
+ QString sFullname, sEmail/*, sUsername*/;
+
+ // final
+ class QCheckBox *cbOpenTemplate;
+};
+
+class KateTemplateManager : public QWidget
+{
+ Q_OBJECT
+ public:
+ KateTemplateManager( KateFileTemplates *kft=0, QWidget *parent=0, const char *name=0 );
+ ~KateTemplateManager() {}
+
+ public slots:
+ void apply();
+ void reload();
+ void reset() { reload(); }
+
+ private slots:
+ void slotUpload();
+ void slotDownload();
+ void slotUpdateState();
+ void slotEditTemplate();
+ void slotRemoveTemplate();
+
+ private:
+ class KListView *lvTemplates;
+ class QPushButton *btnNew, *btnEdit, *btnRemove, *btnDownload, *btnUpload;
+ KateFileTemplates *kft;
+ QPtrList<class TemplateInfo> *remove;
+
+};
+
+#endif // _PLUGIN_KATE_FILETEMPLATES_H_
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/kate/filetemplates/plugin/katefiletemplates.desktop b/kate/filetemplates/plugin/katefiletemplates.desktop
new file mode 100644
index 0000000..252adaa
--- /dev/null
+++ b/kate/filetemplates/plugin/katefiletemplates.desktop
@@ -0,0 +1,113 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=Kate/Plugin
+X-Kate-Version=2.5
+X-KDE-Library=katefiletemplates
+Name=Kate File Templates
+Name[bs]=Kate predlošci datoteka
+Name[ca]=Plantilles de fitxer Kate
+Name[cs]=Souborové šablony Kate
+Name[da]=Kate filskabeloner
+Name[de]=Kate-Dateivorlagen
+Name[el]=Αρχείο προτύπων του Kate
+Name[eo]=Dosieraj ŝablonoj por Kodredaktilo
+Name[es]=Plantillas de archivos de Kate
+Name[et]=Kate failimallid
+Name[eu]=Kateren txantiloi fitxategiak
+Name[fa]=قالبهای پروندۀ Kate
+Name[fi]=Kate tiedostomallit
+Name[fr]=Fichier de modèle pour Kate
+Name[fy]=Kate Triemsjabloanen
+Name[ga]=Teimpléid Kate
+Name[gl]=Modelos de Ficheiro para Kate
+Name[he]= תבניות הטקסט של Kate
+Name[hi]=के-एटीई फ़ाइल टैम्पलेट्स
+Name[hr]=Predlošci datoteka za Kate
+Name[hu]=Kate fájlsablonok
+Name[is]=Kate skráasniðmát
+Name[it]=File template di Kate
+Name[ja]=Kate ファイルテンプレート
+Name[ka]=Kate ფაილის შაბლონები
+Name[kk]=Kate файл үлгілері
+Name[km]=ពុម្ព​ឯកសារ Kate​
+Name[lt]=Kate bylų šablonai
+Name[mk]=Шаблони на датотеки за Кате
+Name[ms]=Templat Fail Kate
+Name[nb]=Kate Filmaler
+Name[nds]=Kate-Dateivörlagen
+Name[ne]=केट फाइल टेम्प्लेटहरू
+Name[nl]=Kate Bestandsjablonen
+Name[nn]=Kate Filmalar
+Name[pa]=ਕੇਟ ਫਾਇਲ ਨਮੂਨੇ
+Name[pl]=Wzorce plików dla Kate
+Name[pt]=Modelos de Ficheiro do Kate
+Name[pt_BR]=Modelos de Arquivo do Kate
+Name[ru]=Шаблоны Kate
+Name[sk]=Šablóny súborov pre Kate
+Name[sl]=Datotečne predloge za Kate
+Name[sr]=Шаблони фајлова за Kate
+Name[sr@Latn]=Šabloni fajlova za Kate
+Name[sv]=Kate-filmallar
+Name[ta]=கேட் உரை வார்ப்புரு
+Name[tg]=Нусхаҳои Kate
+Name[tr]=Kate Dosya Şablonları
+Name[uk]=Шаблони файлів для Kate
+Name[uz]=Kate fayl namunalari
+Name[uz@cyrillic]=Kate файл намуналари
+Name[vi]=Mẫu tập tin Kate
+Name[zh_CN]=Kate 文件模板
+Name[zh_TW]=Kate 檔案樣本
+Comment=Create new files from templates in the Kate text editor
+Comment[bg]=Създаване на нови файлове от шаблони
+Comment[bs]=Napravi nove datoteke iz šablona u Kate editoru teksta
+Comment[ca]=Crea fitxers nous des de les plantilles de l'editor de text Kate
+Comment[cs]=Vytváří z šablon nové soubory v textovém editoru Kate
+Comment[da]=Lav nye filer ud fra skabeloner i teksteditoren Kate
+Comment[de]=Erstellt neue Dateien aus Vorlagen im Kate Texteditor
+Comment[el]=Δημιουργία νέων αρχείων από πρότυπα στον επεξεργαστή κειμένου Kate
+Comment[eo]=Kreas novajn dosierojn el ŝablonoj en Kodredaktilo
+Comment[es]=Crea archivos nuevos a partir de plantillas en el editor de texto Kate
+Comment[et]=Uute failide loomine mallide põhjal tekstiredaktoris Kate
+Comment[eu]=Sortu fitxategi berriak txantiloietatik Kate testu editorean
+Comment[fa]=ایجاد پرونده‌های جدید از قالبهای درون ویرایشگر متن
+Comment[fi]=Luo uudet tiedostot Kate-tekstieditorin malleista
+Comment[fr]=Création de nouveaux fichiers à partir de modèles dans l'éditeur de texte de Kate
+Comment[fy]=Makket nije triemmen fanút sjabloanen binnen de Kate tekstferwurker
+Comment[ga]=Cruthaigh comhaid nua ó theimpléid in eagarthóir téacs Kate
+Comment[gl]=Criar novos ficheiros a partir de modelos no editor de textKate
+Comment[hi]=टैम्पलेट्स के द्वारा केएटीई पाठ संपादक में नया फ़ाइल बनाएँ
+Comment[hr]=Izrađuje nove datoteke iz predložaka unutar Kate uređivača
+Comment[hu]=Új fájlok létrehozása sablon alapján a Kate szövegszerkesztőben
+Comment[is]=Búa til nýjar skrár úr sniðmátum í kate ritlinum
+Comment[it]=Crea nuovi file dai template nell'editor di testi di Kate
+Comment[ja]=テンプレートから新しいファイルを作成します
+Comment[ka]=ახალი ფაილების შექმნა Kate ტექსტური რედაქტორიდან
+Comment[kk]=Kate мәтін редакторында үлгілер бойынша жаңа файлдарды құру
+Comment[km]=បង្កើត​ឯកសារ​ថ្មី​ចេញ​ពី​ពុម្ព​នៅ​ក្នុង​កម្មវិធី​​និពន្ធ​​អត្ថបទ​របស់ Kate
+Comment[lt]=Kurkite naujas bylas iš Kate teksto rengyklės šablonų
+Comment[mk]=Креира нови датотеки од шаблони во уредувачот на текст Кате
+Comment[ms]=Cipta fail bari dari templat dalam editor teks Kate
+Comment[nb]=Lag nye filer fra maler i redigeringsprogrammet Kate
+Comment[nds]=In Kate niege Dateien ut Vörlagen opstellen
+Comment[ne]=केट पाठ सम्पादकमा टेम्प्लेटहरूबाट नयाँ फाइल सिर्जना गर्छ
+Comment[nl]=Creëert nieuwe bestanden vanuit sjablonen binnen de Kate tekstverwerker
+Comment[nn]=Lag nye filer frå malar i redigeringsprogrammet Kate
+Comment[pl]=Tworzy nowe pliki ze wzorców w edytorze tekstów Kate
+Comment[pt]=Criar novos ficheiro a partir de modelos no editor de texto Kate
+Comment[pt_BR]=Cria arquivos através dos modelos no editor de textos Kate
+Comment[ru]=Создание новых файлов из шаблонов в Kate
+Comment[sk]=Vytváranie nových súborov zo štablón v textovom editore Kate
+Comment[sl]=Ustvari nove datoteke iz predlog v urejevalniku besedil Kate
+Comment[sr]=Прави нове фајлове према шаблону у уређивачу текста Kate
+Comment[sr@Latn]=Pravi nove fajlove prema šablonu u uređivaču teksta Kate
+Comment[sv]=Skapa nya filer från mallar i texteditorn Kate
+Comment[ta]=புதிய கோப்பினை கேட் உரை தொகுப்பியின் வார்ப்புருவில் இருந்து உருவாக்கவும்
+Comment[tg]=Эҷод кардани файлҳои нав аз нусхаҳо ба Kate
+Comment[tr]=Kate metin düzenleyicide hazır şablonlardan dosya oluşturma
+Comment[uk]=Створення нових файлів з шаблонів в текстовому редакторі Kate
+Comment[uz]=Namunalardan Kate tahrirchida fayl yaratish
+Comment[uz@cyrillic]=Намуналардан Kate таҳрирчида файл яратиш
+Comment[vi]=Tạo tập tin mới từ mẫu trong trình soạn thảo văn bản Kate
+Comment[zh_CN]=在 Kate 文本编辑器中根据模板创建新文件
+Comment[zh_TW]=在 Kate 文字編輯器中從樣本建立新檔案
+author=Anders Lund, anders@alweb.dk
diff --git a/kate/filetemplates/plugin/katetemplate.xml b/kate/filetemplates/plugin/katetemplate.xml
new file mode 100644
index 0000000..0748481
--- /dev/null
+++ b/kate/filetemplates/plugin/katetemplate.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE language SYSTEM "language.dtd">
+<!--
+ This file is part of KDE's kate project.
+
+ (C) 2004 by Anders Lund <anders@alweb.dk>
+ (C) 2004 by Joseph Weninger <jowenn@kde.org>
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+-->
+<!--
+ This file is highlighting kate template files.
+ TODO equal signs will disturb in the template header (property values)
+-->
+<language version="1.00" kateversion="2.3" name="Kate File Template" section="Markup" extensions="*.katetemplate" mimetype="" author="Anders Lund" licence="GPL">
+ <highlighting>
+
+ <list name="properties">
+ <item>template</item>
+ <item>group</item>
+ <item>documentname</item>
+ <item>author</item>
+ <item>description</item>
+ <item>highlight</item>
+ <item>icon</item>
+ </list>
+ <list name="macros" casesensitive="1">
+ <item>realname</item>
+ <item>username</item>
+ <item>email</item>
+ <item>organisation</item>
+ <item>date</item>
+ <item>time</item>
+ <item>datetime</item>
+ <item>month</item>
+ <item>year</item>
+ </list>
+
+ <contexts>
+ <context attribute="Normal Text" lineEndContext="#pop" name="Normal Text">
+ <RegExpr attribute="Header Keyword" context="header" String="^katetemplate:" />
+ <RegExpr attribute="Normal" context="escape" String="\\[$%]\{[^}\s]+\}" lookAhead="true" />
+ <RegExpr attribute="Macro" context="macros" String="[$%]\{[^}\s]+\}" lookAhead="true"/>
+ <Detect2Chars attribute="Escape" context="#stay" char="\" char1="^" />
+ <DetectChar attribute="Keyword" context="#stay" char="^" />
+ </context>
+ <context attribute="Comment" lineEndContext="#pop" name="header">
+ <keyword attribute="Property" context="headervalue" String="properties" />
+ </context>
+ <context attribute="Property Value" lineEndContext="#pop#pop" name="headervalue">
+ <DetectChar attribute="Header Text" context="#stay" char="=" />
+ <RegExpr context="#pop" String=" \w+\s*=" lookAhead="true" />
+ </context>
+ <context attribute="Error" lineEndContext="#pop" name="macros">
+ <Detect2Chars attribute="Keyword" context="#stay" char="$" char1="{"/>
+ <Detect2Chars attribute="Keyword" context="#stay" char="%" char1="{"/>
+ <DetectChar attribute="Keyword" context="#pop" char="}" />
+ <RegExpr attribute="Macro" context="#stay" String="[^}\s]+" />
+ <keyword attribute="Keyword" context="#stay" String="macros" />
+ </context>
+ <context attribute="Escape" lineEndContext="#stay" name="escape">
+ <Detect2Chars attribute="Escape" context="#pop" char="\" char1="$"/>
+ </context>
+ </contexts>
+
+
+ <itemDatas>
+ <itemData name="Normal Text" defStyleNum="dsNormal" />
+ <itemData name="Keyword" defStyleNum="dsKeyword" />
+ <itemData name="Escape" defStyleNum="dsOthers" />
+ <itemData name="Macro" defStyleNum="dsDataType" />
+ <itemData name="Error" defStyleNum="dsError" />
+ <itemData name="Header Keyword" defStyleNum="dsKeyword" backgroundColor="#eee" />
+ <itemData name="Property" defStyleNum="dsDecVal" bold="true" backgroundColor="#eee"/>
+ <itemData name="Property Value" defStyleNum="dsString" backgroundColor="#eee"/>
+ <itemData name="Comment" defStyleNum="dsComment" backgroundColor="#eee" />
+ <itemData name="Header Text" defStyleNum="dsNormal" backgroundColor="#eee" />
+ </itemDatas>
+ </highlighting>
+ <general>
+ <keywords casesensitive="0"/>
+ </general>
+</language>
+<!-- kate: space-indent on; indent-width 2; replace-tabs on; -->
diff --git a/kate/filetemplates/plugin/ui.rc b/kate/filetemplates/plugin/ui.rc
new file mode 100644
index 0000000..cbf18c8
--- /dev/null
+++ b/kate/filetemplates/plugin/ui.rc
@@ -0,0 +1,15 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="katefiletemplates" library="libkatefiletemplates" version="2">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_new_fromtemplate" group="new_merge" />
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Separator/>
+ <Action name="settings_manage_templates" />
+ </Menu>
+</MenuBar>
+ <Toolbar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="file_new_fromtemplate" group="file_open" />
+</Toolbar>
+</kpartplugin>