diff options
Diffstat (limited to 'languages/cpp/subclassingdlg.cpp')
-rw-r--r-- | languages/cpp/subclassingdlg.cpp | 536 |
1 files changed, 536 insertions, 0 deletions
diff --git a/languages/cpp/subclassingdlg.cpp b/languages/cpp/subclassingdlg.cpp new file mode 100644 index 00000000..fa5aece9 --- /dev/null +++ b/languages/cpp/subclassingdlg.cpp @@ -0,0 +1,536 @@ +/*************************************************************************** + * Copyright (C) 2002 by Jakob Simon-Gaarde * + * [email protected] * + * Copyright (C) 2003 by Alexander Dymo * + * [email protected] * + * * + * 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. * + * * + ***************************************************************************/ + +#include "subclassingdlg.h" +#include "cppsupportpart.h" +#include "backgroundparser.h" +#include "store_walker.h" +#include "cppsupportfactory.h" +#include "kdevsourceformatter.h" +#include "kdevapi.h" +#include "kdevproject.h" +#include "filetemplate.h" +#include "codemodel.h" + +#include <qradiobutton.h> +#include <qstringlist.h> +#include <qcheckbox.h> +#include <qmessagebox.h> +#include <kfiledialog.h> +#include <klineedit.h> +#include <qpushbutton.h> +#include <domutil.h> +#include <qdom.h> +#include <kstandarddirs.h> +#include <kdebug.h> +#include <klocale.h> +#include <qfile.h> +#include <qregexp.h> +#include <kconfig.h> + + +#define WIDGET_CAPTION_NAME "widget/property|name=caption/string" +#define WIDGET_CLASS_NAME "class" +#define WIDGET_SLOTS "slots" +#define WIDGET_FUNCTIONS "functions" + +// All widgets +#define SLOT_ACCEPT SlotItem(m_slotView,"accept()","virtual","protected","void",false,true) +#define SLOT_REJECT SlotItem(m_slotView,"reject()","virtual","protected","void",false,true) + +// Wizards +#define SLOT_BACK SlotItem(m_slotView,"back()","virtual","protected","void",false,true) +#define SLOT_NEXT SlotItem(m_slotView,"next()","virtual","protected","void",false,true) +#define SLOT_HELP SlotItem(m_slotView,"help()","virtual","protected","void",false,true) + + +SlotItem::SlotItem(QListView *parent,const QString &methodName, + const QString &specifier, + const QString &access, const QString &returnType, + bool isFunc,bool callBaseClass) +: QCheckListItem(parent,methodName,QCheckListItem::CheckBox) +{ + setOn(true); + m_methodName = methodName; + m_access = access.isEmpty() ? (const QString) "public" : access; + m_specifier = specifier.isEmpty() ? (const QString) "virtual" : specifier; + m_returnType = returnType.isEmpty() ? (const QString) "void" : returnType; + m_isFunc = isFunc; + m_callBaseClass = callBaseClass; + setText(0,m_methodName); + setText(1,m_access); + setText(2,m_specifier); + setText(3,m_returnType); + setText(4,m_isFunc ? "Function" : "Slot"); + if (m_access=="private" || m_specifier=="non virtual") + { + setOn(false); + setEnabled(false); + } + if (m_specifier=="pure virtual") + { + setOn(true); + setEnabled(false); + } + m_alreadyInSubclass = false; +} + +void SlotItem::setAllreadyInSubclass() +{ + setOn(true); + setEnabled(false); + m_alreadyInSubclass = true; +} + + +SubclassingDlg::SubclassingDlg(CppSupportPart* cppSupport, const QString &formFile, + QStringList &newFileNames, QWidget* parent, + const char* name,bool modal, WFlags fl) +: SubclassingDlgBase(parent,name,modal,fl), +m_newFileNames(newFileNames), m_cppSupport( cppSupport ) + +{ + m_formFile = formFile; + readUiFile(); + m_creatingNewSubclass = true; + + KConfig *config = CppSupportFactory::instance()->config(); + if (config) + { + config->setGroup("Subclassing"); + reformatDefault_box->setChecked(config->readBoolEntry("Reformat Source", 0)); + if (reformatDefault_box->isChecked()) + reformat_box->setChecked(true); + } +} + + +SubclassingDlg::SubclassingDlg(CppSupportPart* cppSupport, const QString &formFile, + const QString &filename, QStringList &dummy, + QWidget* parent, const char* name, bool modal, WFlags fl) +: SubclassingDlgBase(parent, name, modal, fl), +m_newFileNames(dummy), m_cppSupport( cppSupport ) + +{ + m_formFile = formFile; + m_creatingNewSubclass = false; + m_filename = filename; + + KConfig *config = CppSupportFactory::instance()->config(); + if (config) + { + config->setGroup("Subclassing"); + reformatDefault_box->setChecked(config->readBoolEntry("Reformat Source", 0)); + if (reformatDefault_box->isChecked()) + reformat_box->setChecked(true); + } + + QStringList pathsplit(QStringList::split('/',filename)); + + QString baseClass = readBaseClassName(); + if (!cppSupport->codeModel()->hasFile(filename+QString(".h"))) + return; + ClassList myClasses = cppSupport->codeModel()->fileByName(filename+QString(".h"))->classList(); + for (ClassList::const_iterator classIt = myClasses.begin(); classIt != myClasses.end(); ++classIt) + { + kdDebug() << "base class " << baseClass << " class " << (*classIt)->name() + << " parents " << (*classIt)->baseClassList().join(",") << endl; + if ( (*classIt)->baseClassList().findIndex(baseClass) != -1 ) + { + kdDebug() << "base class matched " << endl; + m_edClassName->setText((*classIt)->name()); + m_edFileName->setText(pathsplit[pathsplit.count()-1]); + + FunctionList functionList = (*classIt)->functionList(); + for (FunctionList::const_iterator methodIt = functionList.begin(); + methodIt != functionList.end(); ++methodIt) + { + m_parsedMethods << (*methodIt)->name() + "("; + } + } + } + readUiFile(); + m_btnOk->setEnabled(true); +} + +bool SubclassingDlg::alreadyInSubclass(const QString &method) +{ + for (uint i=0;i<m_parsedMethods.count();i++) + { + if (method.find(m_parsedMethods[i])==0) + return true; + } + return false; +} + +void SubclassingDlg::readUiFile() +{ + QStringList splitPath = QStringList::split('/',m_formFile); + m_formName = QStringList::split('.',splitPath[splitPath.count()-1])[0]; // "somedlg.ui" = "somedlg" + splitPath.pop_back(); + m_formPath = "/" + splitPath.join("/"); // join path to ui-file + + m_btnOk->setEnabled(false); + QDomDocument doc; + + DomUtil::openDOMFile(doc,m_formFile); + m_baseClassName = DomUtil::elementByPathExt(doc,WIDGET_CLASS_NAME).text(); + + m_baseCaption = DomUtil::elementByPathExt(doc,WIDGET_CAPTION_NAME).text(); + setCaption(i18n("Create Subclass of ")+m_baseClassName); + + // Special widget specific slots + SlotItem *newSlot; + m_qtBaseClassName = DomUtil::elementByPathExt(doc,"widget").attribute("class","QDialog"); + + if ( (m_qtBaseClassName=="QMainWindow") || (m_qtBaseClassName=="QWidget") ) + m_canBeModal = false; + else + m_canBeModal = true; + if (m_qtBaseClassName != "QWidget") + { + newSlot = new SLOT_ACCEPT; + newSlot->setOn(false); + if (alreadyInSubclass("accept()")) + newSlot->setAllreadyInSubclass(); + m_slotView->insertItem(newSlot); + m_slots << newSlot; + + newSlot = new SLOT_REJECT; + newSlot->setOn(false); + if (alreadyInSubclass("reject()")) + newSlot->setAllreadyInSubclass(); + m_slotView->insertItem(newSlot); + m_slots << newSlot; + } + + if (m_qtBaseClassName == "QWizard") + { + newSlot = new SLOT_NEXT; + m_slotView->insertItem(newSlot); + if (alreadyInSubclass("next()")) + newSlot->setAllreadyInSubclass(); + m_slots << newSlot; + newSlot = new SLOT_BACK; + m_slotView->insertItem(newSlot); + if (alreadyInSubclass("back()")) + newSlot->setAllreadyInSubclass(); + m_slots << newSlot; + newSlot = new SLOT_HELP; + newSlot->setOn(false); + if (alreadyInSubclass("help()")) + newSlot->setAllreadyInSubclass(); + m_slotView->insertItem(newSlot); + m_slots << newSlot; + } + + QDomElement slotsElem = DomUtil::elementByPathExt(doc,WIDGET_SLOTS); + QDomNodeList slotnodes = slotsElem.childNodes(); + + for (unsigned int i=0; i<slotnodes.count();i++) + { + QDomElement slotelem = slotnodes.item(i).toElement(); + newSlot = new SlotItem(m_slotView,slotelem.text(), + slotelem.attributeNode("specifier").value(), + slotelem.attributeNode("access").value(), + slotelem.attributeNode("returnType").value(),false); + m_slotView->insertItem(newSlot); + if (alreadyInSubclass(slotelem.text())) + newSlot->setAllreadyInSubclass(); + m_slots << newSlot; + } + + QDomElement funcsElem = DomUtil::elementByPathExt(doc,WIDGET_FUNCTIONS); + QDomNodeList funcnodes = funcsElem.childNodes(); + SlotItem *newFunc; + for (unsigned int i=0; i<funcnodes.count();i++) + { + QDomElement funcelem = funcnodes.item(i).toElement(); + newFunc = new SlotItem(m_slotView,funcelem.text(), + funcelem.attributeNode("specifier").value(), + funcelem.attributeNode("access").value(), + funcelem.attributeNode("returnType").value(),true); + m_slotView->insertItem(newFunc); + if (alreadyInSubclass(funcelem.text())) + newFunc->setAllreadyInSubclass(); + m_slots << newFunc; + } +} + +SubclassingDlg::~SubclassingDlg() +{ +} + + +void SubclassingDlg::updateDlg() +{ +} + +void SubclassingDlg::replace(QString &string, const QString& search, const QString& replace) +{ + int nextPos = string.find(search); + unsigned int searchLength = search.length(); + while (nextPos>-1) + { + string = string.replace(nextPos,searchLength,replace); + nextPos = string.find(search,nextPos+replace.length()); + } +} + +bool SubclassingDlg::loadBuffer(QString &buffer, const QString& filename) +{ + // open file and buffer it + QFile dataFile(filename); + if (!dataFile.open(IO_ReadOnly)) + return false; + char *temp = new char[dataFile.size()+1]; + dataFile.readBlock(temp,dataFile.size()); + temp[dataFile.size()]='\0'; + buffer = temp; + delete [] temp; + dataFile.close(); + return true; +} + +bool SubclassingDlg::replaceKeywords(QString &buffer,bool canBeModal) +{ + replace(buffer,"$NEWFILENAMEUC$",m_edFileName->text().upper()); + replace(buffer,"$BASEFILENAMELC$",m_formName.lower()); + replace(buffer,"$BASEFILENAME$",m_formName); + replace(buffer,"$NEWCLASS$",m_edClassName->text()); + replace(buffer,"$QTBASECLASS$", m_qtBaseClassName ); + replace(buffer,"$BASECLASS$",m_baseClassName); + replace(buffer,"$NEWFILENAMELC$",m_edFileName->text().lower()); + if (canBeModal) + { + replace(buffer,"$CAN_BE_MODAL_H$",", bool modal = FALSE"); + replace(buffer,"$CAN_BE_MODAL_CPP1$",", bool modal"); + replace(buffer,"$CAN_BE_MODAL_CPP2$",", modal"); + } + else + { + replace(buffer,"$CAN_BE_MODAL_H$",""); + replace(buffer,"$CAN_BE_MODAL_CPP1$",""); + replace(buffer,"$CAN_BE_MODAL_CPP2$",""); + } + + return true; +} + +bool SubclassingDlg::saveBuffer(QString &buffer, const QString& filename) +{ + // save buffer + + QFile dataFile(filename); + if (!dataFile.open(IO_WriteOnly | IO_Truncate)) + return false; + dataFile.writeBlock((buffer+"\n").ascii(),(buffer+"\n").length()); + dataFile.close(); + return true; +} + + +void SubclassingDlg::accept() +{ + KConfig *config = CppSupportFactory::instance()->config(); + if (config) + { + config->setGroup("Subclassing"); + config->writeEntry("Reformat Source", reformatDefault_box->isChecked()); + } + + unsigned int i; + + // h - file + + QString public_slot = + "/*$PUBLIC_SLOTS$*/\n "; + + QString protected_slot = + "/*$PROTECTED_SLOTS$*/\n "; + + QString public_func = + "/*$PUBLIC_FUNCTIONS$*/\n "; + + QString protected_func = + "/*$PROTECTED_FUNCTIONS$*/\n "; + + QString buffer; + int qtVersion = DomUtil::readIntEntry( *m_cppSupport->project()->projectDom(), "/kdevcppsupport/qt/version", 3 ); + if (m_creatingNewSubclass) + { + if ( qtVersion == 3 ) + loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_template.h")); + else + loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_qt4_template.h")); + + buffer = FileTemplate::read(m_cppSupport, "h") + buffer; + QFileInfo fi(m_filename + ".h"); + QString module = fi.baseName(); + QString basefilename = fi.baseName(true); + buffer.replace(QRegExp("\\$MODULE\\$"),module); + buffer.replace(QRegExp("\\$FILENAME\\$"),basefilename); + } + else + loadBuffer(buffer,m_filename+".h"); + + replaceKeywords(buffer,m_canBeModal); + for (i=0; i<m_slots.count(); i++) + { + SlotItem *slitem = m_slots[i]; + if (!slitem->isOn() || + slitem->m_alreadyInSubclass) + continue; + QString declBuild; + if (slitem->m_access=="public") + if (!slitem->m_isFunc) + declBuild = public_slot; + else + declBuild = public_func; + if (slitem->m_access=="protected") + if (!slitem->m_isFunc) + declBuild = protected_slot; + else + declBuild = protected_func; + if (!(slitem->m_specifier=="non virtual")) + declBuild += "virtual "; + declBuild += slitem->m_returnType + " "; + QString spacer; + if (slitem->m_access=="public") + { + if (!slitem->m_isFunc) + { + declBuild += spacer.fill(' ',43-declBuild.length()) + slitem->m_methodName + ";"; + replace(buffer,"/*$PUBLIC_SLOTS$*/",declBuild); + } + else + { + declBuild += spacer.fill(' ',47-declBuild.length()) + slitem->m_methodName + ";"; + replace(buffer,"/*$PUBLIC_FUNCTIONS$*/",declBuild); + } + } + if (slitem->m_access=="protected") + { + if (!slitem->m_isFunc) + { + declBuild += spacer.fill(' ',46-declBuild.length()) + slitem->m_methodName + ";"; + replace(buffer,"/*$PROTECTED_SLOTS$*/",declBuild); + } + else + { + declBuild += spacer.fill(' ',50-declBuild.length()) + slitem->m_methodName + ";"; + replace(buffer,"/*$PROTECTED_FUNCTIONS$*/",declBuild); + } + } + } + + if (reformat_box->isChecked()) + { + KDevSourceFormatter *fmt = m_cppSupport->extension<KDevSourceFormatter>("KDevelop/SourceFormatter"); + if (fmt) + buffer = fmt->formatSource(buffer); + } + + if (m_creatingNewSubclass) + saveBuffer(buffer,m_formPath + "/" + m_edFileName->text()+".h"); + else + saveBuffer(buffer,m_filename+".h"); + + // cpp - file + + QString implementation = + "/*$SPECIALIZATION$*/\n" + "$RETURNTYPE$ $NEWCLASS$::$METHOD$\n" + "{\n" + "}\n"; + + QString implementation_callbase = + "/*$SPECIALIZATION$*/\n" + "$RETURNTYPE$ $NEWCLASS$::$METHOD$\n" + "{\n" + " $QTBASECLASS$::$METHOD$;\n" + "}\n"; + + + if (m_creatingNewSubclass) + { + if ( qtVersion == 3 ) + loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_template.cpp")); + else + loadBuffer(buffer,::locate("data", "kdevcppsupport/subclassing/subclass_qt4_template.cpp")); + + buffer = FileTemplate::read(m_cppSupport, "cpp") + buffer; + QFileInfo fi(m_filename + ".cpp"); + QString module = fi.baseName(); + QString basefilename = fi.baseName(true); + buffer.replace(QRegExp("\\$MODULE\\$"),module); + buffer.replace(QRegExp("\\$FILENAME\\$"),basefilename); + if ( (m_cppSupport->project()) && (m_cppSupport->project()->options() & KDevProject::UsesAutotoolsBuildSystem)) + buffer += "\n#include \"$NEWFILENAMELC$.moc\"\n"; + } + else + loadBuffer(buffer,m_filename+".cpp"); + + replaceKeywords(buffer,m_canBeModal); + for (i=0; i<m_slots.count(); i++) + { + SlotItem *slitem = m_slots[i]; + if (!slitem->isOn() || + slitem->m_alreadyInSubclass) + continue; + QString impl = slitem->m_callBaseClass ? implementation_callbase : implementation; + replace(impl,"$RETURNTYPE$",slitem->m_returnType); + replace(impl,"$NEWCLASS$",m_edClassName->text()); + replace(impl,"$METHOD$", slitem->m_methodName); + replace(impl,"$QTBASECLASS$", m_qtBaseClassName); + replace(buffer,"/*$SPECIALIZATION$*/",impl); + } + + if (reformat_box->isChecked()) + { + KDevSourceFormatter *fmt = m_cppSupport->extension<KDevSourceFormatter>("KDevelop/SourceFormatter"); + if (fmt) + buffer = fmt->formatSource(buffer); + } + + if (m_creatingNewSubclass) + saveBuffer(buffer,m_formPath + "/" + m_edFileName->text()+".cpp"); + else + saveBuffer(buffer,m_filename+".cpp"); + + if (m_creatingNewSubclass) + { + m_newFileNames.append(m_formPath + "/" + m_edFileName->text()+".cpp"); + m_newFileNames.append(m_formPath + "/" + m_edFileName->text()+".h"); + } + SubclassingDlgBase::accept(); +} + +void SubclassingDlg::onChangedClassName() +{ + m_edFileName->setText(m_edClassName->text().lower()); + if (m_edFileName->text().isEmpty() || + m_edClassName->text().isEmpty()) + m_btnOk->setEnabled(false); + else + m_btnOk->setEnabled(true); +} + +QString SubclassingDlg::readBaseClassName() +{ + QDomDocument doc; + DomUtil::openDOMFile(doc,m_formFile); + return DomUtil::elementByPathExt(doc,WIDGET_CLASS_NAME).text(); +} + +//kate: indent-mode csands; tab-width 4; space-indent off; |