diff options
Diffstat (limited to 'kate/filetemplates/plugin')
-rw-r--r-- | kate/filetemplates/plugin/Makefile.am | 25 | ||||
-rw-r--r-- | kate/filetemplates/plugin/filetemplates.cpp | 1254 | ||||
-rw-r--r-- | kate/filetemplates/plugin/filetemplates.h | 258 | ||||
-rw-r--r-- | kate/filetemplates/plugin/katefiletemplates.desktop | 113 | ||||
-rw-r--r-- | kate/filetemplates/plugin/katetemplate.xml | 87 | ||||
-rw-r--r-- | kate/filetemplates/plugin/ui.rc | 15 |
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 <anders@alweb.dk>'</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>&File</text> + <Action name="file_new_fromtemplate" group="new_merge" /> + </Menu> + <Menu name="settings"><text>&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> |