~ubuntu-branches/debian/sid/kdevelop/sid

« back to all changes in this revision

Viewing changes to languages/cpp/subclassingdlg.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy Lainé
  • Date: 2006-05-23 18:39:42 UTC
  • Revision ID: james.westby@ubuntu.com-20060523183942-hucifbvh68k2bwz7
Tags: upstream-3.3.2
Import upstream version 3.3.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2002 by Jakob Simon-Gaarde                              *
 
3
 *   jsgaarde@tdcspace.dk                                                  *
 
4
 *   Copyright (C) 2003 by Alexander Dymo                                  *
 
5
 *   cloudtemple@mksat.net                                                 *
 
6
 *                                                                         *
 
7
 *   This program is free software; you can redistribute it and/or modify  *
 
8
 *   it under the terms of the GNU General Public License as published by  *
 
9
 *   the Free Software Foundation; either version 2 of the License, or     *
 
10
 *   (at your option) any later version.                                   *
 
11
 *                                                                         *
 
12
 ***************************************************************************/
 
13
 
 
14
#include "subclassingdlg.h"
 
15
#include "cppsupportpart.h"
 
16
#include "backgroundparser.h"
 
17
#include "store_walker.h"
 
18
#include "cppsupportfactory.h"
 
19
#include "kdevsourceformatter.h"
 
20
#include "kdevapi.h"
 
21
#include "kdevproject.h"
 
22
#include "filetemplate.h"
 
23
#include "codemodel.h"
 
24
 
 
25
#include <qradiobutton.h>
 
26
#include <qstringlist.h>
 
27
#include <qcheckbox.h>
 
28
#include <qmessagebox.h>
 
29
#include <kfiledialog.h>
 
30
#include <klineedit.h>
 
31
#include <qpushbutton.h>
 
32
#include <domutil.h>
 
33
#include <qdom.h>
 
34
#include <kstandarddirs.h>
 
35
#include <kdebug.h>
 
36
#include <klocale.h>
 
37
#include <qfile.h>
 
38
#include <qregexp.h>
 
39
#include <kconfig.h>
 
40
 
 
41
 
 
42
#define WIDGET_CAPTION_NAME "widget/property|name=caption/string"
 
43
#define WIDGET_CLASS_NAME   "class"
 
44
#define WIDGET_SLOTS        "slots"
 
45
#define WIDGET_FUNCTIONS    "functions"
 
46
 
 
47
// All widgets
 
48
#define SLOT_ACCEPT SlotItem(m_slotView,"accept()","virtual","protected","void",false,true)
 
49
#define SLOT_REJECT SlotItem(m_slotView,"reject()","virtual","protected","void",false,true)
 
50
 
 
51
// Wizards
 
52
#define SLOT_BACK SlotItem(m_slotView,"back()","virtual","protected","void",false,true)
 
53
#define SLOT_NEXT SlotItem(m_slotView,"next()","virtual","protected","void",false,true)
 
54
#define SLOT_HELP SlotItem(m_slotView,"help()","virtual","protected","void",false,true)
 
55
 
 
56
 
 
57
SlotItem::SlotItem(QListView *parent,const QString &methodName,
 
58
                   const QString &specifier,
 
59
                   const QString &access, const QString &returnType,
 
60
                   bool isFunc,bool callBaseClass)
 
61
: QCheckListItem(parent,methodName,QCheckListItem::CheckBox)
 
62
{
 
63
        setOn(true);
 
64
        m_methodName = methodName;
 
65
        m_access = access.isEmpty() ? (const QString) "public" : access;
 
66
        m_specifier = specifier.isEmpty() ? (const QString) "virtual" : specifier;
 
67
        m_returnType = returnType.isEmpty() ? (const QString) "void" : returnType;
 
68
        m_isFunc = isFunc;
 
69
        m_callBaseClass = callBaseClass;
 
70
        setText(0,m_methodName);
 
71
        setText(1,m_access);
 
72
        setText(2,m_specifier);
 
73
        setText(3,m_returnType);
 
74
        setText(4,m_isFunc ? "Function" : "Slot");
 
75
        if (m_access=="private" || m_specifier=="non virtual")
 
76
        {
 
77
                setOn(false);
 
78
                setEnabled(false);
 
79
        }
 
80
        if (m_specifier=="pure virtual")
 
81
        {
 
82
                setOn(true);
 
83
                setEnabled(false);
 
84
        }
 
85
        m_alreadyInSubclass = false;
 
86
}
 
87
 
 
88
void SlotItem::setAllreadyInSubclass()
 
89
{
 
90
        setOn(true);
 
91
        setEnabled(false);
 
92
        m_alreadyInSubclass = true;
 
93
}
 
94
 
 
95
 
 
96
SubclassingDlg::SubclassingDlg(CppSupportPart* cppSupport, const QString &formFile,
 
97
                               QStringList &newFileNames, QWidget* parent,
 
98
                               const char* name,bool modal, WFlags fl)
 
99
: SubclassingDlgBase(parent,name,modal,fl),
 
100
m_newFileNames(newFileNames), m_cppSupport( cppSupport )
 
101
 
 
102
{
 
103
        m_formFile = formFile;
 
104
        readUiFile();
 
105
        m_creatingNewSubclass = true;
 
106
        
 
107
        KConfig *config = CppSupportFactory::instance()->config();
 
108
        if (config)
 
109
        {
 
110
                config->setGroup("Subclassing");
 
111
                reformatDefault_box->setChecked(config->readBoolEntry("Reformat Source", 0));
 
112
                if (reformatDefault_box->isChecked())
 
113
                        reformat_box->setChecked(true);
 
114
        }
 
115
}
 
116
 
 
117
 
 
118
SubclassingDlg::SubclassingDlg(CppSupportPart* cppSupport, const QString &formFile,
 
119
                               const QString &filename, QStringList &dummy,
 
120
                               QWidget* parent, const char* name, bool modal, WFlags fl)
 
121
: SubclassingDlgBase(parent, name, modal, fl),
 
122
m_newFileNames(dummy), m_cppSupport( cppSupport )
 
123
 
 
124
{
 
125
        m_formFile = formFile;
 
126
        m_creatingNewSubclass = false;
 
127
        m_filename = filename;
 
128
        
 
129
        KConfig *config = CppSupportFactory::instance()->config();
 
130
        if (config)
 
131
        {
 
132
                config->setGroup("Subclassing");
 
133
                reformatDefault_box->setChecked(config->readBoolEntry("Reformat Source", 0));
 
134
                if (reformatDefault_box->isChecked())
 
135
                        reformat_box->setChecked(true);
 
136
        }
 
137
        
 
138
        QStringList pathsplit(QStringList::split('/',filename));
 
139
        
 
140
        QString baseClass = readBaseClassName();
 
141
        if (!cppSupport->codeModel()->hasFile(filename+QString(".h")))
 
142
                return;
 
143
        ClassList myClasses = cppSupport->codeModel()->fileByName(filename+QString(".h"))->classList();
 
144
        for (ClassList::const_iterator classIt = myClasses.begin(); classIt != myClasses.end(); ++classIt)
 
145
        {
 
146
                kdDebug() << "base class " << baseClass << " class " << (*classIt)->name()
 
147
                        << " parents " << (*classIt)->baseClassList().join(",") << endl;
 
148
                if ( (*classIt)->baseClassList().findIndex(baseClass) != -1 )
 
149
                {
 
150
                        kdDebug() << "base class matched " << endl;
 
151
                        m_edClassName->setText((*classIt)->name());
 
152
                        m_edFileName->setText(pathsplit[pathsplit.count()-1]);
 
153
                        
 
154
                        FunctionList functionList = (*classIt)->functionList();
 
155
                        for (FunctionList::const_iterator methodIt = functionList.begin();
 
156
                             methodIt != functionList.end(); ++methodIt)
 
157
                        {
 
158
                                m_parsedMethods << (*methodIt)->name() + "(";
 
159
                        }
 
160
                }
 
161
        }
 
162
        readUiFile();
 
163
        m_btnOk->setEnabled(true);
 
164
}
 
165
 
 
166
bool SubclassingDlg::alreadyInSubclass(const QString &method)
 
167
{
 
168
        for (uint i=0;i<m_parsedMethods.count();i++)
 
169
        {
 
170
                if (method.find(m_parsedMethods[i])==0)
 
171
                        return true;
 
172
        }
 
173
        return false;
 
174
}
 
175
 
 
176
void SubclassingDlg::readUiFile()
 
177
{
 
178
        QStringList splitPath = QStringList::split('/',m_formFile);
 
179
        m_formName = QStringList::split('.',splitPath[splitPath.count()-1])[0]; // "somedlg.ui" = "somedlg"
 
180
        splitPath.pop_back();
 
181
        m_formPath = "/" + splitPath.join("/"); // join path to ui-file
 
182
        
 
183
        m_btnOk->setEnabled(false);
 
184
        QDomDocument doc;
 
185
        
 
186
        DomUtil::openDOMFile(doc,m_formFile);
 
187
        m_baseClassName = DomUtil::elementByPathExt(doc,WIDGET_CLASS_NAME).text();
 
188
        
 
189
        m_baseCaption = DomUtil::elementByPathExt(doc,WIDGET_CAPTION_NAME).text();
 
190
        setCaption(i18n("Create Subclass of ")+m_baseClassName);
 
191
        
 
192
  // Special widget specific slots
 
193
        SlotItem *newSlot;
 
194
        m_qtBaseClassName = DomUtil::elementByPathExt(doc,"widget").attribute("class","QDialog");
 
195
        
 
196
        if ( (m_qtBaseClassName=="QMainWindow") || (m_qtBaseClassName=="QWidget") )
 
197
                m_canBeModal = false;
 
198
        else
 
199
                m_canBeModal = true;
 
200
        if (m_qtBaseClassName != "QWidget")
 
201
        {
 
202
                newSlot = new SLOT_ACCEPT;
 
203
                newSlot->setOn(false);
 
204
                if (alreadyInSubclass("accept()"))
 
205
                        newSlot->setAllreadyInSubclass();
 
206
                m_slotView->insertItem(newSlot);
 
207
                m_slots << newSlot;
 
208
                
 
209
                newSlot = new SLOT_REJECT;
 
210
                newSlot->setOn(false);
 
211
                if (alreadyInSubclass("reject()"))
 
212
                        newSlot->setAllreadyInSubclass();
 
213
                m_slotView->insertItem(newSlot);
 
214
                m_slots << newSlot;
 
215
        }
 
216
        
 
217
        if (m_qtBaseClassName == "QWizard")
 
218
        {
 
219
                newSlot = new SLOT_NEXT;
 
220
                m_slotView->insertItem(newSlot);
 
221
                if (alreadyInSubclass("next()"))
 
222
                        newSlot->setAllreadyInSubclass();
 
223
                m_slots << newSlot;
 
224
                newSlot = new SLOT_BACK;
 
225
                m_slotView->insertItem(newSlot);
 
226
                if (alreadyInSubclass("back()"))
 
227
                        newSlot->setAllreadyInSubclass();
 
228
                m_slots << newSlot;
 
229
                newSlot = new SLOT_HELP;
 
230
                newSlot->setOn(false);
 
231
                if (alreadyInSubclass("help()"))
 
232
                        newSlot->setAllreadyInSubclass();
 
233
                m_slotView->insertItem(newSlot);
 
234
                m_slots << newSlot;
 
235
        }
 
236
        
 
237
        QDomElement slotsElem = DomUtil::elementByPathExt(doc,WIDGET_SLOTS);
 
238
        QDomNodeList slotnodes = slotsElem.childNodes();
 
239
        
 
240
        for (unsigned int i=0; i<slotnodes.count();i++)
 
241
        {
 
242
                QDomElement slotelem = slotnodes.item(i).toElement();
 
243
                newSlot = new SlotItem(m_slotView,slotelem.text(),
 
244
                                       slotelem.attributeNode("specifier").value(),
 
245
                                       slotelem.attributeNode("access").value(),
 
246
                                       slotelem.attributeNode("returnType").value(),false);
 
247
                m_slotView->insertItem(newSlot);
 
248
                if (alreadyInSubclass(slotelem.text()))
 
249
                        newSlot->setAllreadyInSubclass();
 
250
                m_slots << newSlot;
 
251
        }
 
252
        
 
253
        QDomElement funcsElem = DomUtil::elementByPathExt(doc,WIDGET_FUNCTIONS);
 
254
        QDomNodeList funcnodes = funcsElem.childNodes();
 
255
        SlotItem *newFunc;
 
256
        for (unsigned int i=0; i<funcnodes.count();i++)
 
257
        {
 
258
                QDomElement funcelem = funcnodes.item(i).toElement();
 
259
                newFunc = new SlotItem(m_slotView,funcelem.text(),
 
260
                                       funcelem.attributeNode("specifier").value(),
 
261
                                       funcelem.attributeNode("access").value(),
 
262
                                       funcelem.attributeNode("returnType").value(),true);
 
263
                m_slotView->insertItem(newFunc);
 
264
                if (alreadyInSubclass(funcelem.text()))
 
265
                        newFunc->setAllreadyInSubclass();
 
266
                m_slots << newFunc;
 
267
        }
 
268
}
 
269
 
 
270
SubclassingDlg::~SubclassingDlg()
 
271
{
 
272
}
 
273
 
 
274
 
 
275
void SubclassingDlg::updateDlg()
 
276
{
 
277
}
 
278
 
 
279
void SubclassingDlg::replace(QString &string, const QString& search, const QString& replace)
 
280
{
 
281
        int nextPos = string.find(search);
 
282
        unsigned int searchLength = search.length();
 
283
        while (nextPos>-1)
 
284
        {
 
285
                string = string.replace(nextPos,searchLength,replace);
 
286
                nextPos = string.find(search,nextPos+replace.length());
 
287
        }
 
288
}
 
289
 
 
290
bool SubclassingDlg::loadBuffer(QString &buffer, const QString& filename)
 
291
{
 
292
  // open file and buffer it
 
293
        QFile dataFile(filename);
 
294
        if (!dataFile.open(IO_ReadOnly))
 
295
                return false;
 
296
        char *temp = new char[dataFile.size()+1];
 
297
        dataFile.readBlock(temp,dataFile.size());
 
298
        temp[dataFile.size()]='\0';
 
299
        buffer = temp;
 
300
        delete temp;
 
301
        dataFile.close();
 
302
        return true;
 
303
}
 
304
 
 
305
bool SubclassingDlg::replaceKeywords(QString &buffer,bool canBeModal)
 
306
{
 
307
        replace(buffer,"$NEWFILENAMEUC$",m_edFileName->text().upper());
 
308
        replace(buffer,"$BASEFILENAMELC$",m_formName.lower());
 
309
        replace(buffer,"$BASEFILENAME$",m_formName);
 
310
        replace(buffer,"$NEWCLASS$",m_edClassName->text());
 
311
        replace(buffer,"$BASECLASS$",m_baseClassName);
 
312
        replace(buffer,"$NEWFILENAMELC$",m_edFileName->text().lower());
 
313
        if (canBeModal)
 
314
        {
 
315
                replace(buffer,"$CAN_BE_MODAL_H$",", bool modal = FALSE");
 
316
                replace(buffer,"$CAN_BE_MODAL_CPP1$",", bool modal");
 
317
                replace(buffer,"$CAN_BE_MODAL_CPP2$",", modal");
 
318
        }
 
319
        else
 
320
        {
 
321
                replace(buffer,"$CAN_BE_MODAL_H$","");
 
322
                replace(buffer,"$CAN_BE_MODAL_CPP1$","");
 
323
                replace(buffer,"$CAN_BE_MODAL_CPP2$","");
 
324
        }
 
325
        
 
326
        return true;
 
327
}
 
328
 
 
329
bool SubclassingDlg::saveBuffer(QString &buffer, const QString& filename)
 
330
{
 
331
        // save buffer
 
332
        
 
333
        QFile dataFile(filename);
 
334
        if (!dataFile.open(IO_WriteOnly | IO_Truncate))
 
335
                return false;
 
336
        dataFile.writeBlock((buffer+"\n").ascii(),(buffer+"\n").length());
 
337
        dataFile.close();
 
338
        return true;
 
339
}
 
340
 
 
341
 
 
342
void SubclassingDlg::accept()
 
343
{
 
344
        KConfig *config = CppSupportFactory::instance()->config();
 
345
        if (config)
 
346
        {
 
347
                config->setGroup("Subclassing");
 
348
                config->writeEntry("Reformat Source", reformatDefault_box->isChecked());
 
349
        }
 
350
        
 
351
        unsigned int i;
 
352
        
 
353
  // h - file
 
354
        
 
355
        QString public_slot =
 
356
                "/*$PUBLIC_SLOTS$*/\n  ";
 
357
        
 
358
        QString protected_slot =
 
359
                "/*$PROTECTED_SLOTS$*/\n  ";
 
360
        
 
361
        QString public_func =
 
362
                "/*$PUBLIC_FUNCTIONS$*/\n  ";
 
363
        
 
364
        QString protected_func =
 
365
                "/*$PROTECTED_FUNCTIONS$*/\n  ";
 
366
        
 
367
        QString buffer;
 
368
        if (m_creatingNewSubclass)
 
369
        {
 
370
                loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_template.h"));
 
371
                buffer = FileTemplate::read(m_cppSupport, "h") + buffer;
 
372
                QFileInfo fi(m_filename + ".h");
 
373
                QString module = fi.baseName();
 
374
                QString basefilename = fi.baseName(true);
 
375
                buffer.replace(QRegExp("\\$MODULE\\$"),module);
 
376
                buffer.replace(QRegExp("\\$FILENAME\\$"),basefilename);
 
377
        }
 
378
        else
 
379
                loadBuffer(buffer,m_filename+".h");
 
380
        
 
381
        replaceKeywords(buffer,m_canBeModal);
 
382
        for (i=0; i<m_slots.count(); i++)
 
383
        {
 
384
                SlotItem *slitem = m_slots[i];
 
385
                if (!slitem->isOn() ||
 
386
                    slitem->m_alreadyInSubclass)
 
387
                        continue;
 
388
                QString declBuild;
 
389
                if (slitem->m_access=="public")
 
390
                        if (!slitem->m_isFunc)
 
391
                                declBuild = public_slot;
 
392
                else
 
393
                        declBuild = public_func;
 
394
                if (slitem->m_access=="protected")
 
395
                        if (!slitem->m_isFunc)
 
396
                                declBuild = protected_slot;
 
397
                else
 
398
                        declBuild = protected_func;
 
399
                if (!(slitem->m_specifier=="non virtual"))
 
400
                        declBuild += "virtual ";
 
401
                declBuild += slitem->m_returnType + " ";
 
402
                QString spacer;
 
403
                if (slitem->m_access=="public")
 
404
                {
 
405
                        if (!slitem->m_isFunc)
 
406
                        {
 
407
                                declBuild += spacer.fill(' ',43-declBuild.length()) + slitem->m_methodName + ";";
 
408
                                replace(buffer,"/*$PUBLIC_SLOTS$*/",declBuild);
 
409
                        }
 
410
                        else
 
411
                        {
 
412
                                declBuild += spacer.fill(' ',47-declBuild.length()) + slitem->m_methodName + ";";
 
413
                                replace(buffer,"/*$PUBLIC_FUNCTIONS$*/",declBuild);
 
414
                        }
 
415
                }
 
416
                if (slitem->m_access=="protected")
 
417
                {
 
418
                        if (!slitem->m_isFunc)
 
419
                        {
 
420
                                declBuild += spacer.fill(' ',46-declBuild.length()) + slitem->m_methodName + ";";
 
421
                                replace(buffer,"/*$PROTECTED_SLOTS$*/",declBuild);
 
422
                        }
 
423
                        else
 
424
                        {
 
425
                                declBuild += spacer.fill(' ',50-declBuild.length()) + slitem->m_methodName + ";";
 
426
                                replace(buffer,"/*$PROTECTED_FUNCTIONS$*/",declBuild);
 
427
                        }
 
428
                }
 
429
        }
 
430
        
 
431
        if (reformat_box->isChecked())
 
432
        {
 
433
                KDevSourceFormatter *fmt = m_cppSupport->extension<KDevSourceFormatter>("KDevelop/SourceFormatter");
 
434
                if (fmt)
 
435
                        buffer = fmt->formatSource(buffer);
 
436
        }
 
437
        
 
438
        if (m_creatingNewSubclass)
 
439
                saveBuffer(buffer,m_formPath + "/" + m_edFileName->text()+".h");
 
440
        else
 
441
                saveBuffer(buffer,m_filename+".h");
 
442
        
 
443
  // cpp - file
 
444
        
 
445
        QString implementation =
 
446
                "/*$SPECIALIZATION$*/\n"
 
447
                "$RETURNTYPE$ $NEWCLASS$::$METHOD$\n"
 
448
                "{\n"
 
449
                "}\n";
 
450
        
 
451
        QString implementation_callbase =
 
452
                "/*$SPECIALIZATION$*/\n"
 
453
                "$RETURNTYPE$ $NEWCLASS$::$METHOD$\n"
 
454
                "{\n"
 
455
                "  $QTBASECLASS$::$METHOD$;\n"
 
456
                "}\n";
 
457
        
 
458
        
 
459
        if (m_creatingNewSubclass)
 
460
        {
 
461
                loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_template.cpp"));
 
462
                buffer = FileTemplate::read(m_cppSupport, "cpp") + buffer;
 
463
                QFileInfo fi(m_filename + ".cpp");
 
464
                QString module = fi.baseName();
 
465
                QString basefilename = fi.baseName(true);
 
466
                buffer.replace(QRegExp("\\$MODULE\\$"),module);
 
467
                buffer.replace(QRegExp("\\$FILENAME\\$"),basefilename);
 
468
                if ( (m_cppSupport->project()) && (m_cppSupport->project()->options() & KDevProject::UsesAutotoolsBuildSystem))
 
469
                        buffer += "\n#include \"$NEWFILENAMELC$.moc\"\n";
 
470
        }
 
471
        else
 
472
                loadBuffer(buffer,m_filename+".cpp");
 
473
        
 
474
        replaceKeywords(buffer,m_canBeModal);
 
475
        for (i=0; i<m_slots.count(); i++)
 
476
        {
 
477
                SlotItem *slitem = m_slots[i];
 
478
                if (!slitem->isOn() ||
 
479
                    slitem->m_alreadyInSubclass)
 
480
                        continue;
 
481
        QString impl = slitem->m_callBaseClass ? implementation_callbase : implementation;
 
482
                replace(impl,"$RETURNTYPE$",slitem->m_returnType);
 
483
                replace(impl,"$NEWCLASS$",m_edClassName->text());
 
484
                replace(impl,"$METHOD$", slitem->m_methodName);
 
485
                replace(impl,"$QTBASECLASS$", m_qtBaseClassName);
 
486
                replace(buffer,"/*$SPECIALIZATION$*/",impl);
 
487
        }
 
488
        
 
489
        if (reformat_box->isChecked())
 
490
        {
 
491
                KDevSourceFormatter *fmt = m_cppSupport->extension<KDevSourceFormatter>("KDevelop/SourceFormatter");
 
492
                if (fmt)
 
493
                        buffer = fmt->formatSource(buffer);
 
494
        }
 
495
        
 
496
        if (m_creatingNewSubclass)
 
497
                saveBuffer(buffer,m_formPath + "/" + m_edFileName->text()+".cpp");
 
498
        else
 
499
                saveBuffer(buffer,m_filename+".cpp");
 
500
        
 
501
        if (m_creatingNewSubclass)
 
502
        {
 
503
                m_newFileNames.append(m_formPath + "/" + m_edFileName->text()+".cpp");
 
504
                m_newFileNames.append(m_formPath + "/" + m_edFileName->text()+".h");
 
505
        }
 
506
        SubclassingDlgBase::accept();
 
507
}
 
508
 
 
509
void SubclassingDlg::onChangedClassName()
 
510
{
 
511
  m_edFileName->setText(m_edClassName->text().lower());
 
512
  if (m_edFileName->text().isEmpty() ||
 
513
      m_edClassName->text().isEmpty())
 
514
    m_btnOk->setEnabled(false);
 
515
  else
 
516
    m_btnOk->setEnabled(true);
 
517
}
 
518
 
 
519
QString SubclassingDlg::readBaseClassName()
 
520
{
 
521
        QDomDocument doc;
 
522
        DomUtil::openDOMFile(doc,m_formFile);
 
523
        return DomUtil::elementByPathExt(doc,WIDGET_CLASS_NAME).text();
 
524
}
 
525
 
 
526
//kate: indent-mode csands; tab-width 4; space-indent off;