1
/***************************************************************************
2
* Copyright (C) 2003 by Julian Rockey *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
9
***************************************************************************/
11
#include <qwhatsthis.h>
14
#include <qfileinfo.h>
18
#include <kdeversion.h>
19
#include <kiconloader.h>
21
#include <kdevgenericfactory.h>
22
#include <kfiledialog.h>
24
#include <kstandarddirs.h>
25
#include <kstdaction.h>
27
#include <kapplication.h>
28
#include <kactionclasses.h>
29
#include <kpopupmenu.h>
32
#include "kdevmainwindow.h"
33
#include "kdevproject.h"
34
#include "kdevpartcontroller.h"
35
#include "configwidgetproxy.h"
37
#include "filetemplate.h"
41
#include "filecreate_widget2.h"
42
#include "filecreate_widget3.h"
43
#include "filecreate_part.h"
44
#include "filecreate_filetype.h"
45
#include "filecreate_filedialog.h"
46
#include "filecreate_newfile.h"
47
#include "fcconfigwidget.h"
49
#define PROJECTSETTINGSPAGE 1
50
#define GLOBALSETTINGSPAGE 2
52
#include "kdevplugininfo.h"
54
static const KDevPluginInfo data("kdevfilecreate");
56
typedef KDevGenericFactory<FileCreatePart> FileCreateFactory;
57
K_EXPORT_COMPONENT_FACTORY( libkdevfilecreate, FileCreateFactory( data ) )
59
using namespace FileCreate;
61
FileCreatePart::FileCreatePart(QObject *parent, const char *name, const QStringList & )
62
: KDevCreateFile(&data, parent, name ? name : "FileCreatePart"), m_selectedWidget(-1), m_useSideTab(true), m_subPopups(0)
64
setInstance(FileCreateFactory::instance());
65
setXMLFile("kdevpart_filecreate.rc");
67
connect( core(), SIGNAL(projectOpened()), this, SLOT(slotProjectOpened()) );
68
connect( core(), SIGNAL(projectClosed()), this, SLOT(slotProjectClosed()) );
70
_configProxy = new ConfigWidgetProxy( core() );
71
_configProxy->createProjectConfigPage( i18n("File Templates"), PROJECTSETTINGSPAGE, info()->icon() );
72
_configProxy->createGlobalConfigPage( i18n("File Templates"), GLOBALSETTINGSPAGE, info()->icon() );
73
connect( _configProxy, SIGNAL(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )),
74
this, SLOT(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )) );
77
KToolBarPopupAction * newAction = new KToolBarPopupAction( i18n("&New"), "filenew", CTRL+Qt::Key_N, this, SLOT(slotNewFile()), actionCollection(), "file_new");
78
newAction->setWhatsThis( i18n("<b>New file</b><p>Creates a new file. Also adds it the project if the <b>Add to project</b> checkbox is turned on.") );
79
newAction->setToolTip( i18n("Create a new file") );
80
m_newPopupMenu = newAction->popupMenu();
81
connect(m_newPopupMenu, SIGNAL(aboutToShow()), this, SLOT(slotAboutToShowNewPopupMenu()));
83
// m_filetypes.setAutoDelete(true);
85
m_availableWidgets[0] = new FriendlyWidget(this);
86
m_availableWidgets[1] = new ListWidget(this);
89
/// @todo provide a way of choosing your preferred widget without
90
/// having to change the source, as this is not considered 'user-friendly'
91
/// these days, I'm led to believe.
94
QTimer::singleShot( 0, this, SLOT(slotGlobalInitialize()) );
98
FileCreatePart::~FileCreatePart()
101
for(int c=0;c<m_numWidgets;c++){
102
if (TypeChooser* chooser = m_availableWidgets[c]) {
104
if( QWidget* as_widget = dynamic_cast<QWidget*>(chooser) )
105
mainWindow()->removeView( as_widget );
113
m_newPopupMenu->clear();
117
void FileCreatePart::insertConfigWidget( const KDialogBase * dlg, QWidget * page, unsigned int pagenumber )
119
kdDebug() << k_funcinfo << endl;
123
case PROJECTSETTINGSPAGE:
125
FCConfigWidget* w = new FCConfigWidget( this, false, page, "filecreate config widget" );
126
connect( dlg, SIGNAL( okClicked( ) ), w, SLOT( accept( ) ) );
130
case GLOBALSETTINGSPAGE:
132
FCConfigWidget *w = new FCConfigWidget( this, true, page, "filecreate config widget" );
133
connect(dlg, SIGNAL(okClicked()), w, SLOT(accept()));
139
void FileCreatePart::selectWidget(int widgetNumber) {
140
if (m_selectedWidget==widgetNumber) return;
141
if (widgetNumber<-1 || widgetNumber>=m_numWidgets) return;
142
if (setWidget(widgetNumber==-1 ? NULL : m_availableWidgets[widgetNumber]))
143
m_selectedWidget = widgetNumber;
147
bool FileCreatePart::setWidget(TypeChooser * widg) {
149
QWidget *as_widget = widg ? dynamic_cast<QWidget*>(widg) : NULL;
151
// remove the existing widget
152
TypeChooser *tc = typeChooserWidget();
154
disconnect( tc->signaller(), SIGNAL(filetypeSelected(const FileType *)), this, SLOT(slotFiletypeSelected(const FileType *)) );
155
QWidget *as_widget2 = dynamic_cast<QWidget*>(tc);
157
kdDebug(9034) << "filecreate_part: Removing as_widget2" << endl;
158
mainWindow()->removeView(as_widget2);
160
kdWarning(9034) << "WARNING: could not cast to as_widget2" << endl;
164
if (widg && as_widget) {
165
connect( widg->signaller(), SIGNAL(filetypeSelected(const FileType *)), this, SLOT(slotFiletypeSelected(const FileType *)) );
166
mainWindow()->embedSelectView(as_widget, i18n("New File"), i18n("File creation"));
172
void FileCreatePart::refresh() {
173
if (typeChooserWidget()) typeChooserWidget()->refresh();
176
void FileCreatePart::slotAboutToShowNewPopupMenu()
178
KIconLoader * m_iconLoader = KGlobal::iconLoader();
179
m_newPopupMenu->clear();
183
FileType * filetype = m_filetypes.first();
184
for(; filetype; filetype=m_filetypes.next())
186
if (filetype->enabled())
188
if (filetype->subtypes().count()==0)
190
QPixmap iconPix = m_iconLoader->loadIcon(
191
filetype->icon(), KIcon::Desktop, KIcon::SizeSmall,
192
KIcon::DefaultState, NULL, true);
193
m_newPopupMenu->insertItem(iconPix, filetype->name(), this,
194
SLOT(slotNewFilePopup(int)), 0, ++id );
195
m_newPopupMenu->setItemParameter( id, (long)filetype );
198
KPopupMenu* subMenu = NULL;
199
QPtrList<FileType> subtypes = filetype->subtypes();
200
for(FileType * subtype = subtypes.first(); subtype; subtype=subtypes.next())
202
if (subtype->enabled()){
204
subMenu = new KPopupMenu(0,0);
205
QPixmap iconPix = m_iconLoader->loadIcon(
206
subtype->icon(), KIcon::Desktop, KIcon::SizeSmall,
207
KIcon::DefaultState, NULL, true);
208
subMenu->insertItem(iconPix, subtype->name(), this,
209
SLOT(slotNewFilePopup(int)), 0, ++id );
210
subMenu->setItemParameter( id, (long)subtype );
217
m_subPopups = new QPtrList<KPopupMenu>;
218
m_subPopups->setAutoDelete(true);
220
m_subPopups->append( subMenu );
221
m_newPopupMenu->insertItem( filetype->name(), subMenu );
230
void FileCreatePart::slotNewFilePopup( int pFileType )
232
const FileType* filetype = (const FileType*) pFileType;
233
slotFiletypeSelected( filetype );
236
void FileCreatePart::slotNewFile() {
237
KDevCreateFile::CreatedFile createdFile = createNewFile();
238
openCreatedFile(createdFile);
241
void FileCreatePart::slotProjectOpened() {
242
QTimer::singleShot( 0, this, SLOT(slotInitialize()) );
245
void FileCreatePart::addFileType(const QString & filename) {
246
FileType * filetype = getType(filename);
248
filetype = new FileType;
249
filetype->setName( filename + " files" );
250
filetype->setExt( filename );
251
filetype->setCreateMethod("template");
252
m_filetypes.append(filetype);
254
filetype->setEnabled(true);
257
void FileCreatePart::slotProjectClosed() {
260
QTimer::singleShot( 0, this, SLOT(slotGlobalInitialize()) );
263
void FileCreatePart::slotFiletypeSelected(const FileType * filetype) {
265
KDevCreateFile::CreatedFile createdFile = createNewFile(filetype->ext(),
268
filetype->subtypeRef());
271
openCreatedFile(createdFile);
273
// mainWindow()->lowerView( typeChooserWidgetAsQWidget() );
276
void FileCreatePart::openCreatedFile(const KDevCreateFile::CreatedFile & createdFile) {
277
if (createdFile.status == KDevCreateFile::CreatedFile::STATUS_OK && project() ) {
278
KURL uu(project()->projectDirectory() + createdFile.dir + "/" + createdFile.filename );
279
partController()->editDocument ( uu );
283
int FileCreatePart::readTypes(const QDomDocument & dom, QPtrList<FileType> &m_filetypes, bool enable) {
285
QDomElement fileTypes = DomUtil::elementByPath(dom,"/kdevfilecreate/filetypes");
286
if (!fileTypes.isNull()) {
287
for(QDomNode node = fileTypes.firstChild();!node.isNull();node=node.nextSibling()) {
288
// kapp->processEvents();
290
if (node.isElement() && node.nodeName()=="type") {
291
QDomElement element = node.toElement();
292
FileType * filetype = new FileType;
293
filetype->setName( element.attribute("name") );
294
filetype->setExt( element.attribute("ext") );
295
filetype->setCreateMethod( element.attribute("create") );
297
filetype->setIcon( element.attribute("icon") );
298
filetype->setDescr( (DomUtil::namedChildElement(element, "descr")).text() );
299
filetype->setEnabled(enable || (filetype->ext()==""));
300
m_filetypes.append(filetype);
303
kdDebug(9034) << "node: " << filetype->name().latin1() << endl;
305
if (node.hasChildNodes()) {
306
for(QDomNode subnode = node.firstChild();!subnode.isNull();subnode=subnode.nextSibling()) {
307
kdDebug(9034) << "subnode: " << subnode.nodeName().latin1() << endl;
308
// kapp->processEvents();
309
if (subnode.isElement() && subnode.nodeName()=="subtype") {
310
QDomElement subelement = subnode.toElement();
311
FileType * subtype = new FileType;
312
subtype->setExt( filetype->ext() );
313
subtype->setCreateMethod( filetype->createMethod() );
314
subtype->setSubtypeRef( subelement.attribute("ref") );
315
subtype->setIcon( subelement.attribute("icon") );
316
subtype->setName( subelement.attribute("name") );
317
subtype->setDescr( (DomUtil::namedChildElement(subelement, "descr")).text() );
318
subtype->setEnabled(enable);
319
filetype->addSubtype(subtype);
329
FileType * FileCreatePart::getType(const QString & ex, const QString subtRef) {
331
QString subtypeRef = subtRef;
333
int dashPos = ext.find('-');
334
if (dashPos>-1 && subtRef.isNull()) {
335
ext = ex.left(dashPos);
336
subtypeRef = ex.mid(dashPos+1);
339
QPtrList<FileType> filetypes = getFileTypes();
340
for(FileType * filetype = filetypes.first();
342
filetype=filetypes.next()) {
343
if (filetype->ext()==ext) {
344
if (subtypeRef.isNull()) return filetype;
345
QPtrList<FileType> subtypes = filetype->subtypes();
346
for(FileType * subtype = subtypes.first();
348
subtype=subtypes.next()) {
349
if (subtypeRef==subtype->subtypeRef()) return subtype;
356
FileType * FileCreatePart::getEnabledType(const QString & ex, const QString subtRef) {
358
QString subtypeRef = subtRef;
360
int dashPos = ext.find('-');
361
if (dashPos>-1 && subtRef.isNull()) {
362
ext = ex.left(dashPos);
363
subtypeRef = ex.mid(dashPos+1);
366
QPtrList<FileType> filetypes = getFileTypes();
367
for(FileType * filetype = filetypes.first();
369
filetype=filetypes.next()) {
370
if (filetype->ext()==ext) {
371
if ( (subtypeRef.isNull()) && (filetype->enabled()) ) return filetype;
372
QPtrList<FileType> subtypes = filetype->subtypes();
373
for(FileType * subtype = subtypes.first();
375
subtype=subtypes.next()) {
376
if ( (subtypeRef==subtype->subtypeRef()) && (filetype->enabled()) ) return subtype;
383
// KDevFileCreate interface
385
KDevCreateFile::CreatedFile FileCreatePart::createNewFile(QString ext, QString dir, QString name, QString subtype)
387
KDevCreateFile::CreatedFile result;
392
//result.status = KDevCreateFile::CreatedFile::STATUS_NOTCREATED;
397
projectURL = project()->projectDirectory();
402
NewFileChooser dialog;
403
dialog.setFileTypes(m_filetypes);
404
const FileType *filetype = getEnabledType(ext,subtype);
405
kdDebug(9034) << "Looking for filetype pointer for " << ext << "/" << subtype << endl;
407
kdDebug(9034) << "found filetype" << endl;
409
kdDebug(9034) << "could not find filetype" << endl;
412
dialog.setInProjectMode(false);
415
dialog.setDirectory(dir);
417
dialog.setDirectory(QDir::currentDirPath());
420
QString activeDir = project()->activeDirectory();
421
dialog.setDirectory( project()->projectDirectory() +
422
( activeDir[0] == '/' ? "" : "/" )
425
if (!name.isNull()) dialog.setName(name);
426
if (filetype) dialog.setCurrent(filetype);
428
dialog.setInitialSize(QSize(500, 200));
429
int dialogResult = dialog.exec();
431
if (dialogResult == KDialogBase::Rejected) {
432
result.status = KDevCreateFile::CreatedFile::STATUS_NOTCREATED;
438
result.addToProject = dialog.addToProject();
439
selectedURL = dialog.url();
440
const FileType *selectedFileType = dialog.selectedType();
442
if (dialog.addToProject() && !projectURL.isParentOf(selectedURL)) {
443
result.status = KDevCreateFile::CreatedFile::STATUS_NOTWITHINPROJECT;
447
if (selectedFileType) {
448
ext = selectedFileType->ext();
449
subtype = selectedFileType->subtypeRef();
452
QString fullPath = selectedURL.path();
453
// add appropriate extension, if not already there
454
if (!ext.isNull() & ext!="" & !fullPath.endsWith("." + ext)) fullPath+="." + ext;
456
QString filename = URLUtil::filename(fullPath);
457
kdDebug(9034) << "full path = " << fullPath << endl;
459
// add in subtype, if specified
460
if (!subtype.isEmpty())
461
ext += "-" + subtype;
463
// create file from template
464
if (!FileTemplate::exists(this, ext) ||
465
!FileTemplate::copy(this, ext, fullPath) ) {
466
// no template, create a blank file instead
468
f.open( IO_WriteOnly );
471
if (dialog.addToProject())
473
// work out the path relative to the project directory
474
// QString relToProj = URLUtil::relativePath(projectURL, selectedURL, URLUtil::SLASH_PREFIX );
475
QString relToProj = URLUtil::relativePath(projectURL.path(), fullPath, URLUtil::SLASH_PREFIX );
476
project()->addFile(relToProj.mid(1));
481
url.setPath(fullPath);
482
partController()->editDocument(url);
485
QString fileName = URLUtil::filename(fullPath);
486
kdDebug(9034) << "file name = " << filename << endl;
488
result.filename = fileName;
489
result.dir = URLUtil::directory(fullPath);
490
result.status = KDevCreateFile::CreatedFile::STATUS_OK;
495
void FileCreatePart::setShowSideTab(bool on) {
496
selectWidget(on ? 1 : -1 );
499
void FileCreatePart::slotNoteFiletype(const FileType * filetype) {
500
kdDebug(9034) << "Noting file type: " << (filetype ? filetype->ext() : QString::fromLatin1("Null") ) << endl;
501
m_filedialogFiletype = filetype;
504
void FileCreatePart::slotInitialize( )
509
//read global configuration
510
slotGlobalInitialize();
512
// read in which global templates are to be used for this project
513
QDomElement useGlobalTypes =
514
DomUtil::elementByPath(*projectDom(),"/kdevfilecreate/useglobaltypes");
515
for(QDomNode node = useGlobalTypes.firstChild();
516
!node.isNull();node=node.nextSibling()) {
518
// kapp->processEvents();
520
if (node.isElement() && node.nodeName()=="type") {
521
QDomElement element = node.toElement();
522
QString ext = element.attribute("ext");
523
QString subtyperef = element.attribute("subtyperef");
524
// if an extension has been specified as enabled, ensure it
525
// and all its subtypes are enabled
526
if (subtyperef.isNull()) {
527
FileType * filetype = getType(ext);
529
filetype->setEnabled(true);
530
if (filetype->subtypes().count())
531
filetype->setSubtypesEnabled(true);
534
// if an extension + subtype have been specified, enable
535
// the subtype and the extension (the 'parent')
536
FileType * filetype = getType(ext);
537
FileType * subtype = getType(ext,subtyperef);
538
if (filetype && subtype) {
539
filetype->setEnabled(true);
540
subtype->setEnabled(true);
546
// read in the list of file types for this project
547
if ( project() && readTypes( *projectDom(), m_filetypes, true )==0 ) {
548
// default by scanning the templates directory if no template info
549
// found in project file
550
QDir templDir( project()->projectDirectory() + "/templates/" );
551
if (templDir.exists()) {
552
templDir.setFilter( QDir::Files );
553
const QFileInfoList * list = templDir.entryInfoList();
555
QFileInfoListIterator it( *list );
557
while ( (fi = it.current()) != 0 ) {
558
addFileType(fi->fileName());
563
/* else { // it was probably an imported project
564
// KLUDGE: we need a better way to determine file types
565
// the current method looks a bit too restrictive
566
addFileType( "cpp" );
571
setShowSideTab(m_useSideTab);
577
void FileCreatePart::slotGlobalInitialize( )
579
// read in global template information
580
QString globalXMLFile = ::locate("data", "kdevfilecreate/template-info.xml");
581
kdDebug(9034) << "Found global template info info " << globalXMLFile << endl;
582
QDomDocument globalDom;
583
if (!globalXMLFile.isNull() &&
584
DomUtil::openDOMFile(globalDom,globalXMLFile)) {
585
kdDebug(9034) << "Reading global template info..." << endl;
586
// kapp->processEvents();
587
readTypes(globalDom, m_filetypes, false);
589
// use side tab or not?
590
/// @todo this is a very Bad Way to do this. Must remember to move this setting to user's kdeveloprc config file
591
QDomElement useSideTab = DomUtil::elementByPath(globalDom,"/kdevfilecreate/sidetab");
592
if (!useSideTab.isNull() && useSideTab.attribute("active")=="no") {
593
m_useSideTab = false;
595
setShowSideTab(m_useSideTab); // not the cleanest thing to do.. but c'mon, look at the rest of this code.. ;)
603
#include "filecreate_part.moc"
605
// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;