00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "subclassingdlg.h"
00015 #include "cppsupportpart.h"
00016 #include "backgroundparser.h"
00017 #include "store_walker.h"
00018 #include "cppsupportfactory.h"
00019 #include "kdevsourceformatter.h"
00020 #include "kdevproject.h"
00021 #include "filetemplate.h"
00022 #include "codemodel.h"
00023
00024 #include <qradiobutton.h>
00025 #include <qstringlist.h>
00026 #include <qcheckbox.h>
00027 #include <qmessagebox.h>
00028 #include <kfiledialog.h>
00029 #include <klineedit.h>
00030 #include <qpushbutton.h>
00031 #include <domutil.h>
00032 #include <qdom.h>
00033 #include <kstandarddirs.h>
00034 #include <kdebug.h>
00035 #include <klocale.h>
00036 #include <qfile.h>
00037 #include <qregexp.h>
00038 #include <kconfig.h>
00039
00040
00041 #define WIDGET_CAPTION_NAME "widget/property|name=caption/string"
00042 #define WIDGET_CLASS_NAME "class"
00043 #define WIDGET_SLOTS "slots"
00044 #define WIDGET_FUNCTIONS "functions"
00045
00046
00047 #define SLOT_ACCEPT SlotItem(m_slotView,"accept()","virtual","protected","void",false,true)
00048 #define SLOT_REJECT SlotItem(m_slotView,"reject()","virtual","protected","void",false,true)
00049
00050
00051 #define SLOT_BACK SlotItem(m_slotView,"back()","virtual","protected","void",false,true)
00052 #define SLOT_NEXT SlotItem(m_slotView,"next()","virtual","protected","void",false,true)
00053 #define SLOT_HELP SlotItem(m_slotView,"help()","virtual","protected","void",false,true)
00054
00055
00056 SlotItem::SlotItem(QListView *parent,const QString &methodName,
00057 const QString &specifier,
00058 const QString &access, const QString &returnType,
00059 bool isFunc,bool callBaseClass)
00060 : QCheckListItem(parent,methodName,QCheckListItem::CheckBox)
00061 {
00062 setOn(true);
00063 m_methodName = methodName;
00064 m_access = access.isEmpty() ? (const QString) "public" : access;
00065 m_specifier = specifier.isEmpty() ? (const QString) "virtual" : specifier;
00066 m_returnType = returnType.isEmpty() ? (const QString) "void" : returnType;
00067 m_isFunc = isFunc;
00068 m_callBaseClass = callBaseClass;
00069 setText(0,m_methodName);
00070 setText(1,m_access);
00071 setText(2,m_specifier);
00072 setText(3,m_returnType);
00073 setText(4,m_isFunc ? "Function" : "Slot");
00074 if (m_access=="private" ||
00075 m_specifier=="non virtual")
00076 {
00077 setOn(false);
00078 setEnabled(false);
00079 }
00080 if (m_specifier=="pure virtual")
00081 {
00082 setOn(true);
00083 setEnabled(false);
00084 }
00085 m_alreadyInSubclass = false;
00086 }
00087
00088 void SlotItem::setAllreadyInSubclass()
00089 {
00090 setOn(true);
00091 setEnabled(false);
00092 m_alreadyInSubclass = true;
00093 }
00094
00095
00096 SubclassingDlg::SubclassingDlg(CppSupportPart* cppSupport, const QString &formFile,QStringList &newFileNames,
00097 QWidget* parent, const char* name,bool modal, WFlags fl)
00098 : SubclassingDlgBase(parent,name,modal,fl),
00099 m_newFileNames(newFileNames), m_cppSupport( cppSupport )
00100
00101 {
00102 m_formFile = formFile;
00103 readUiFile();
00104 m_creatingNewSubclass = true;
00105
00106 KConfig *config = CppSupportFactory::instance()->config();
00107 if (config)
00108 {
00109 config->setGroup("Subclassing");
00110 reformatDefault_box->setChecked(config->readBoolEntry("Reformat Source", 0));
00111 if (reformatDefault_box->isChecked())
00112 reformat_box->setChecked(true);
00113 }
00114 }
00115
00116
00117 SubclassingDlg::SubclassingDlg(CppSupportPart* cppSupport, const QString &formFile,const QString &filename,QStringList &dummy,
00118 QWidget* parent, const char* name,bool modal, WFlags fl)
00119 : SubclassingDlgBase(parent,name,modal,fl),
00120 m_newFileNames(dummy), m_cppSupport( cppSupport )
00121
00122 {
00123 m_formFile = formFile;
00124 m_creatingNewSubclass = false;
00125 m_filename = filename;
00126
00127 KConfig *config = CppSupportFactory::instance()->config();
00128 if (config)
00129 {
00130 config->setGroup("Subclassing");
00131 reformatDefault_box->setChecked(config->readBoolEntry("Reformat Source", 0));
00132 if (reformatDefault_box->isChecked())
00133 reformat_box->setChecked(true);
00134 }
00135
00136 QStringList pathsplit(QStringList::split('/',filename));
00137
00138 QString baseClass = readBaseClassName();
00139 if (!cppSupport->codeModel()->hasFile(filename+QString(".h")))
00140 return;
00141 ClassList myClasses = cppSupport->codeModel()->fileByName(filename+QString(".h"))->classList();
00142 for (ClassList::const_iterator classIt = myClasses.begin(); classIt != myClasses.end(); ++classIt)
00143 {
00144 kdDebug() << "base class " << baseClass << " class " << (*classIt)->name()
00145 << " parents " << (*classIt)->baseClassList().join(",") << endl;
00146 if ( (*classIt)->baseClassList().findIndex(baseClass) != -1 )
00147 {
00148 kdDebug() << "base class matched " << endl;
00149 m_edClassName->setText((*classIt)->name());
00150 m_edFileName->setText(pathsplit[pathsplit.count()-1]);
00151
00152 FunctionList functionList = (*classIt)->functionList();
00153 for (FunctionList::const_iterator methodIt = functionList.begin();
00154 methodIt != functionList.end(); ++methodIt)
00155 {
00156 m_parsedMethods << (*methodIt)->name() + "(";
00157 }
00158 }
00159 }
00160 readUiFile();
00161 m_btnOk->setEnabled(true);
00162 }
00163
00164 bool SubclassingDlg::alreadyInSubclass(const QString &method)
00165 {
00166 for (uint i=0;i<m_parsedMethods.count();i++)
00167 if (method.find(m_parsedMethods[i])==0)
00168 return true;
00169 return false;
00170 }
00171
00172 void SubclassingDlg::readUiFile()
00173 {
00174 QStringList splitPath = QStringList::split('/',m_formFile);
00175 m_formName = QStringList::split('.',splitPath[splitPath.count()-1])[0];
00176 splitPath.pop_back();
00177 m_formPath = "/" + splitPath.join("/");
00178
00179 m_btnOk->setEnabled(false);
00180 QDomDocument doc;
00181
00182 DomUtil::openDOMFile(doc,m_formFile);
00183 m_baseClassName = DomUtil::elementByPathExt(doc,WIDGET_CLASS_NAME).text();
00184
00185 m_baseCaption = DomUtil::elementByPathExt(doc,WIDGET_CAPTION_NAME).text();
00186 setCaption(i18n("Create Subclass of ")+m_baseClassName);
00187
00188
00189 SlotItem *newSlot;
00190 m_qtBaseClassName = DomUtil::elementByPathExt(doc,"widget").attribute("class","QDialog");
00191
00192 if ( (m_qtBaseClassName=="QMainWindow") || (m_qtBaseClassName=="QWidget") )
00193 m_canBeModal = false;
00194 else
00195 m_canBeModal = true;
00196 if (m_qtBaseClassName != "QWidget")
00197 {
00198 newSlot = new SLOT_ACCEPT;
00199 newSlot->setOn(false);
00200 if (alreadyInSubclass("accept()"))
00201 newSlot->setAllreadyInSubclass();
00202 m_slotView->insertItem(newSlot);
00203 m_slots << newSlot;
00204
00205 newSlot = new SLOT_REJECT;
00206 newSlot->setOn(false);
00207 if (alreadyInSubclass("reject()"))
00208 newSlot->setAllreadyInSubclass();
00209 m_slotView->insertItem(newSlot);
00210 m_slots << newSlot;
00211 }
00212
00213 if (m_qtBaseClassName == "QWizard")
00214 {
00215 newSlot = new SLOT_NEXT;
00216 m_slotView->insertItem(newSlot);
00217 if (alreadyInSubclass("next()"))
00218 newSlot->setAllreadyInSubclass();
00219 m_slots << newSlot;
00220 newSlot = new SLOT_BACK;
00221 m_slotView->insertItem(newSlot);
00222 if (alreadyInSubclass("back()"))
00223 newSlot->setAllreadyInSubclass();
00224 m_slots << newSlot;
00225 newSlot = new SLOT_HELP;
00226 newSlot->setOn(false);
00227 if (alreadyInSubclass("help()"))
00228 newSlot->setAllreadyInSubclass();
00229 m_slotView->insertItem(newSlot);
00230 m_slots << newSlot;
00231 }
00232
00233 QDomElement slotsElem = DomUtil::elementByPathExt(doc,WIDGET_SLOTS);
00234 QDomNodeList slotnodes = slotsElem.childNodes();
00235
00236 for (unsigned int i=0; i<slotnodes.count();i++)
00237 {
00238 QDomElement slotelem = slotnodes.item(i).toElement();
00239 newSlot = new SlotItem(m_slotView,slotelem.text(),
00240 slotelem.attributeNode("specifier").value(),
00241 slotelem.attributeNode("access").value(),
00242 slotelem.attributeNode("returnType").value(),false);
00243 m_slotView->insertItem(newSlot);
00244 if (alreadyInSubclass(slotelem.text()))
00245 newSlot->setAllreadyInSubclass();
00246 m_slots << newSlot;
00247 }
00248
00249 QDomElement funcsElem = DomUtil::elementByPathExt(doc,WIDGET_FUNCTIONS);
00250 QDomNodeList funcnodes = funcsElem.childNodes();
00251 SlotItem *newFunc;
00252 for (unsigned int i=0; i<funcnodes.count();i++)
00253 {
00254 QDomElement funcelem = funcnodes.item(i).toElement();
00255 newFunc = new SlotItem(m_slotView,funcelem.text(),
00256 funcelem.attributeNode("specifier").value(),
00257 funcelem.attributeNode("access").value(),
00258 funcelem.attributeNode("returnType").value(),true);
00259 m_slotView->insertItem(newFunc);
00260 if (alreadyInSubclass(funcelem.text()))
00261 newFunc->setAllreadyInSubclass();
00262 m_slots << newFunc;
00263 }
00264 }
00265
00266 SubclassingDlg::~SubclassingDlg()
00267
00268 {
00269 }
00270
00271
00272 void SubclassingDlg::updateDlg()
00273
00274 {
00275 }
00276
00277 void SubclassingDlg::replace(QString &string, const QString& search, const QString& replace)
00278
00279 {
00280 int nextPos = string.find(search);
00281 unsigned int searchLength = search.length();
00282 while (nextPos>-1)
00283 {
00284 string = string.replace(nextPos,searchLength,replace);
00285 nextPos = string.find(search,nextPos+replace.length());
00286 }
00287 }
00288
00289 bool SubclassingDlg::loadBuffer(QString &buffer, const QString& filename)
00290
00291 {
00292
00293 QFile dataFile(filename);
00294 if (!dataFile.open(IO_ReadOnly))
00295 return false;
00296 char *temp = new char[dataFile.size()+1];
00297 dataFile.readBlock(temp,dataFile.size());
00298 temp[dataFile.size()]='\0';
00299 buffer = temp;
00300 delete temp;
00301 dataFile.close();
00302 return true;
00303 }
00304
00305 bool SubclassingDlg::replaceKeywords(QString &buffer,bool canBeModal)
00306
00307 {
00308 replace(buffer,"$NEWFILENAMEUC$",m_edFileName->text().upper());
00309 replace(buffer,"$BASEFILENAMELC$",m_formName.lower());
00310 replace(buffer,"$BASEFILENAME$",m_formName);
00311 replace(buffer,"$NEWCLASS$",m_edClassName->text());
00312 replace(buffer,"$BASECLASS$",m_baseClassName);
00313 replace(buffer,"$NEWFILENAMELC$",m_edFileName->text().lower());
00314 if (canBeModal)
00315 {
00316 replace(buffer,"$CAN_BE_MODAL_H$",", bool modal = FALSE");
00317 replace(buffer,"$CAN_BE_MODAL_CPP1$",", bool modal");
00318 replace(buffer,"$CAN_BE_MODAL_CPP2$",", modal");
00319 }
00320 else
00321 {
00322 replace(buffer,"$CAN_BE_MODAL_H$","");
00323 replace(buffer,"$CAN_BE_MODAL_CPP1$","");
00324 replace(buffer,"$CAN_BE_MODAL_CPP2$","");
00325 }
00326
00327 return true;
00328 }
00329
00330 bool SubclassingDlg::saveBuffer(QString &buffer, const QString& filename)
00331
00332 {
00333
00334
00335 QFile dataFile(filename);
00336 if (!dataFile.open(IO_WriteOnly | IO_Truncate))
00337 return false;
00338 dataFile.writeBlock((buffer+"\n").ascii(),(buffer+"\n").length());
00339 dataFile.close();
00340 return true;
00341 }
00342
00343
00344 void SubclassingDlg::accept()
00345
00346 {
00347 KConfig *config = CppSupportFactory::instance()->config();
00348 if (config)
00349 {
00350 config->setGroup("Subclassing");
00351 config->writeEntry("Reformat Source", reformatDefault_box->isChecked());
00352 }
00353
00354 unsigned int i;
00355
00356
00357
00358 QString public_slot =
00359 "/*$PUBLIC_SLOTS$*/\n ";
00360
00361 QString protected_slot =
00362 "/*$PROTECTED_SLOTS$*/\n ";
00363
00364 QString public_func =
00365 "/*$PUBLIC_FUNCTIONS$*/\n ";
00366
00367 QString protected_func =
00368 "/*$PROTECTED_FUNCTIONS$*/\n ";
00369
00370 QString buffer;
00371 if (m_creatingNewSubclass)
00372 {
00373 loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_template.h"));
00374 buffer = FileTemplate::read(m_cppSupport, "h") + buffer;
00375 QFileInfo fi(m_filename + ".h");
00376 QString module = fi.baseName();
00377 QString basefilename = fi.baseName(true);
00378 buffer.replace(QRegExp("\\$MODULE\\$"),module);
00379 buffer.replace(QRegExp("\\$FILENAME\\$"),basefilename);
00380 }
00381 else
00382 loadBuffer(buffer,m_filename+".h");
00383 replaceKeywords(buffer,m_canBeModal);
00384 for (i=0; i<m_slots.count(); i++)
00385 {
00386 SlotItem *slitem = m_slots[i];
00387 if (!slitem->isOn() ||
00388 slitem->m_alreadyInSubclass)
00389 continue;
00390 QString declBuild;
00391 if (slitem->m_access=="public")
00392 if (!slitem->m_isFunc)
00393 declBuild = public_slot;
00394 else
00395 declBuild = public_func;
00396 if (slitem->m_access=="protected")
00397 if (!slitem->m_isFunc)
00398 declBuild = protected_slot;
00399 else
00400 declBuild = protected_func;
00401 if (!(slitem->m_specifier=="non virtual"))
00402 declBuild += "virtual ";
00403 declBuild += slitem->m_returnType + " ";
00404 QString spacer;
00405 if (slitem->m_access=="public")
00406 {
00407 if (!slitem->m_isFunc)
00408 {
00409 declBuild += spacer.fill(' ',43-declBuild.length()) + slitem->m_methodName + ";";
00410 replace(buffer,"/*$PUBLIC_SLOTS$*/",declBuild);
00411 }
00412 else
00413 {
00414 declBuild += spacer.fill(' ',47-declBuild.length()) + slitem->m_methodName + ";";
00415 replace(buffer,"/*$PUBLIC_FUNCTIONS$*/",declBuild);
00416 }
00417 }
00418 if (slitem->m_access=="protected")
00419 {
00420 if (!slitem->m_isFunc)
00421 {
00422 declBuild += spacer.fill(' ',46-declBuild.length()) + slitem->m_methodName + ";";
00423 replace(buffer,"/*$PROTECTED_SLOTS$*/",declBuild);
00424 }
00425 else
00426 {
00427 declBuild += spacer.fill(' ',50-declBuild.length()) + slitem->m_methodName + ";";
00428 replace(buffer,"/*$PROTECTED_FUNCTIONS$*/",declBuild);
00429 }
00430 }
00431 }
00432
00433 if (reformat_box->isChecked())
00434 buffer = m_cppSupport->sourceFormatter()->formatSource(buffer);
00435
00436 if (m_creatingNewSubclass)
00437 saveBuffer(buffer,m_formPath + "/" + m_edFileName->text()+".h");
00438 else
00439 saveBuffer(buffer,m_filename+".h");
00440
00441
00442
00443 QString implementation =
00444 "/*$SPECIALIZATION$*/\n"
00445 "$RETURNTYPE$ $NEWCLASS$::$METHOD$\n"
00446 "{\n"
00447 "}\n";
00448
00449 QString implementation_callbase =
00450 "/*$SPECIALIZATION$*/\n"
00451 "$RETURNTYPE$ $NEWCLASS$::$METHOD$\n"
00452 "{\n"
00453 " $QTBASECLASS$::$METHOD$;\n"
00454 "}\n";
00455
00456
00457 if (m_creatingNewSubclass)
00458 {
00459 loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_template.cpp"));
00460 buffer = FileTemplate::read(m_cppSupport, "cpp") + buffer;
00461 QFileInfo fi(m_filename + ".cpp");
00462 QString module = fi.baseName();
00463 QString basefilename = fi.baseName(true);
00464 buffer.replace(QRegExp("\\$MODULE\\$"),module);
00465 buffer.replace(QRegExp("\\$FILENAME\\$"),basefilename);
00466 if ( (m_cppSupport->project()) && (m_cppSupport->project()->options() & KDevProject::UsesAutotoolsBuildSystem))
00467 {
00468 buffer += "\n#include \"$NEWFILENAMELC$.moc\"\n";
00469 }
00470 }
00471 else
00472 loadBuffer(buffer,m_filename+".cpp");
00473 replaceKeywords(buffer,m_canBeModal);
00474 for (i=0; i<m_slots.count(); i++)
00475 {
00476 SlotItem *slitem = m_slots[i];
00477 if (!slitem->isOn() ||
00478 slitem->m_alreadyInSubclass)
00479 continue;
00480 QString impl = slitem->m_callBaseClass ? implementation_callbase : implementation;
00481 replace(impl,"$RETURNTYPE$",slitem->m_returnType);
00482 replace(impl,"$NEWCLASS$",m_edClassName->text());
00483 replace(impl,"$METHOD$", slitem->m_methodName);
00484 replace(impl,"$QTBASECLASS$", m_qtBaseClassName);
00485 replace(buffer,"/*$SPECIALIZATION$*/",impl);
00486 }
00487
00488 if (reformat_box->isChecked())
00489 buffer = m_cppSupport->sourceFormatter()->formatSource(buffer);
00490
00491 if (m_creatingNewSubclass)
00492 saveBuffer(buffer,m_formPath + "/" + m_edFileName->text()+".cpp");
00493 else
00494 saveBuffer(buffer,m_filename+".cpp");
00495
00496 if (m_creatingNewSubclass)
00497 {
00498 m_newFileNames.append(m_formPath + "/" + m_edFileName->text()+".cpp");
00499 m_newFileNames.append(m_formPath + "/" + m_edFileName->text()+".h");
00500 }
00501 SubclassingDlgBase::accept();
00502 }
00503
00504 void SubclassingDlg::onChangedClassName()
00505
00506 {
00507 m_edFileName->setText(m_edClassName->text().lower());
00508 if (m_edFileName->text().isEmpty() ||
00509 m_edClassName->text().isEmpty())
00510 m_btnOk->setEnabled(false);
00511 else
00512 m_btnOk->setEnabled(true);
00513 }
00514
00515 QString SubclassingDlg::readBaseClassName( )
00516 {
00517 QDomDocument doc;
00518 DomUtil::openDOMFile(doc,m_formFile);
00519 return DomUtil::elementByPathExt(doc,WIDGET_CLASS_NAME).text();
00520 }