//============================================================================= // // File : ClassEditorWindow.cpp // Creation date : Mon Feb 15 2010 14:35:55 CEST by Carbone Alessandro // // This file is part of the KVIrc IRC client distribution // Copyright (C) 2010 Alessandro Carbone (elfonol at gmail dot com) // // 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 opinion) 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. // //============================================================================= #include "ClassEditorWindow.h" #include "KviIconManager.h" #include "KviOptions.h" #include "KviLocale.h" #include "KviImageDialog.h" #include "KviConfigurationFile.h" #include "KviFileDialog.h" #include "KviFileUtils.h" #include "KviScriptEditor.h" #include "kvi_debug.h" #include "KviApplication.h" #include "KviMainWindow.h" #include "KviQString.h" #include "KviKvsKernel.h" #include "KviKvsObjectClass.h" #include "KviKvsObjectController.h" #include "KviCommandFormatter.h" #include "KviModule.h" #include "KviTalVBox.h" #include "kvi_fileextensions.h" #include "KviModuleManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern ClassEditorWindow * g_pClassEditorWindow; extern KviModule * g_pClassEditorModule; ClassEditorTreeWidget::ClassEditorTreeWidget(QWidget * pParent) : QTreeWidget(pParent) { setColumnCount (1); setHeaderLabel(__tr2qs_ctx("Class","editor")); setSelectionMode(QAbstractItemView::ExtendedSelection); setSortingEnabled(true); setRootIsDecorated(true); setAnimated(true); } ClassEditorTreeWidget::~ClassEditorTreeWidget() { //remove and delete all items clear(); } void ClassEditorTreeWidget::mousePressEvent(QMouseEvent * e) { if(e->button() == Qt::RightButton) { QTreeWidgetItem * pItem = itemAt(e->pos()); if(pItem) emit rightButtonPressed(pItem,QCursor::pos()); } QTreeWidget::mousePressEvent(e); } ClassEditorTreeWidgetItem::ClassEditorTreeWidgetItem(QTreeWidget * pTreeWidget, Type eType, const QString & szName) : QTreeWidgetItem(pTreeWidget), KviHeapObject(), m_eType(eType) { setName(szName); m_szInheritsClassName = ""; m_iPos = 0; m_bInternal = false; m_bClassModified = false; QPixmap * pIcon = 0; if(eType == ClassEditorTreeWidgetItem::Namespace) pIcon = g_pIconManager->getSmallIcon(KviIconManager::NameSpace); else pIcon = g_pIconManager->getSmallIcon(KviIconManager::Class); setIcon(0,QIcon(*pIcon)); } ClassEditorTreeWidgetItem::ClassEditorTreeWidgetItem(ClassEditorTreeWidgetItem * pParentItem, Type eType, const QString & szName) : QTreeWidgetItem(pParentItem), m_eType(eType) { setFlags(Qt::ItemIsEditable|Qt::ItemIsEnabled|Qt::ItemIsSelectable); setName(szName); m_szInheritsClassName = ""; m_bInternal = false; m_iPos = 0; m_bClassModified = false; QPixmap * pIcon = 0; if(eType == ClassEditorTreeWidgetItem::Namespace) pIcon = g_pIconManager->getSmallIcon(KviIconManager::NameSpace); else if(eType == ClassEditorTreeWidgetItem::Class) pIcon = g_pIconManager->getSmallIcon(KviIconManager::Class); else pIcon = g_pIconManager->getSmallIcon(KviIconManager::Function); setIcon(0,QIcon(*pIcon)); } void ClassEditorTreeWidgetItem::setClassNotBuilt(bool bModified) { m_bClassModified = bModified; QPixmap * pIcon = 0; if(bModified) pIcon = g_pIconManager->getSmallIcon(KviIconManager::ClassNotBuilt); else pIcon = g_pIconManager->getSmallIcon(KviIconManager::Class); setIcon(0,QIcon(*pIcon)); } void ClassEditorTreeWidgetItem::setName(const QString & szName) { m_szName = szName; setText(0,m_szName); } void ClassEditorTreeWidgetItem::setType(Type eType) { m_eType = eType; QPixmap * pIcon = 0; if(eType == ClassEditorTreeWidgetItem::Namespace) pIcon = g_pIconManager->getSmallIcon(KviIconManager::NameSpace); else if(eType == ClassEditorTreeWidgetItem::Class) pIcon = g_pIconManager->getSmallIcon(KviIconManager::Class); else pIcon = g_pIconManager->getSmallIcon(KviIconManager::Function); setIcon(0,QIcon(*pIcon)); } ClassEditorWidget::ClassEditorWidget(QWidget * pParent) : QWidget(pParent) { m_pClasses = new KviPointerHashTable(100,false); m_pClasses->setAutoDelete(false); m_pLastEditedItem = 0; m_pLastClickedItem = 0; m_szDir = QDir::homePath(); QGridLayout * pLayout = new QGridLayout(this); m_pSplitter = new QSplitter(Qt::Horizontal,this); m_pSplitter->setChildrenCollapsible(false); pLayout->addWidget(m_pSplitter,0,0); KviTalVBox * pVBox = new KviTalVBox(m_pSplitter); pVBox->setSpacing(0); pVBox->setMargin(0); m_pTreeWidget = new ClassEditorTreeWidget(pVBox); pVBox = new KviTalVBox(m_pSplitter); KviTalHBox * pHBox = new KviTalHBox(pVBox); pHBox->setSpacing(0); pHBox->setMargin(0); m_pClassNameLabel = new QLabel(__tr2qs_ctx("No item selected","editor"),pHBox); pHBox->setStretchFactor(m_pClassNameLabel,2); m_pClassNameLabel->setWordWrap(true); m_pClassNameRenameButton = new QPushButton(__tr2qs_ctx("Rename","editor"),pHBox); m_pClassNameRenameButton->setToolTip(__tr2qs_ctx("Edit the class or namespace name","editor")); m_pClassNameRenameButton->setEnabled(false); connect(m_pClassNameRenameButton,SIGNAL(clicked()),this,SLOT(renameItem())); pHBox = new KviTalHBox(pVBox); pHBox->setSpacing(0); pHBox->setMargin(0); pHBox = new KviTalHBox(pVBox); pHBox->setSpacing(0); pHBox->setMargin(0); m_pFunctionNameLabel = new QLabel(__tr2qs_ctx("No item selected","editor"),pHBox); pHBox->setStretchFactor(m_pFunctionNameLabel,2); m_pFunctionNameRenameButton = new QPushButton(__tr2qs_ctx("Rename","editor"),pHBox); m_pFunctionNameRenameButton->setToolTip(__tr2qs_ctx("Edit the function member name","editor")); m_pFunctionNameRenameButton->setEnabled(false); connect(m_pFunctionNameRenameButton,SIGNAL(clicked()),this,SLOT(renameFunction())); m_pReminderLabel = new QLabel(__tr2qs_ctx("No item selected","editor"),pVBox); m_pReminderLabel->hide(); m_pReminderLabel->setWordWrap(true); m_pEditor = KviScriptEditor::createInstance(pVBox); m_pEditor->setFocus(); connect(m_pEditor,SIGNAL(find(const QString &)),this,SLOT(slotFindWord(const QString &))); connect(m_pEditor,SIGNAL(replaceAll(const QString &,const QString &)),this,SLOT(slotReplaceAll(const QString &,const QString &))); m_pContextPopup = new QMenu(this); oneTimeSetup(); currentItemChanged(0,0); } ClassEditorWidget::~ClassEditorWidget() { m_pClasses->clear(); delete m_pClasses; } void ClassEditorWidget::buildFullItemPath(ClassEditorTreeWidgetItem * pItem, QString & szBuffer) { if(!pItem) return; szBuffer.prepend(pItem->name() + "::"); pItem = (ClassEditorTreeWidgetItem *)pItem->parent(); while(pItem) { QString szTmp = pItem->name(); if(!szTmp.isEmpty()) { szBuffer.prepend("::"); szBuffer.prepend(szTmp); } pItem = (ClassEditorTreeWidgetItem *)pItem->parent(); } } QString ClassEditorWidget::buildFullClassName(ClassEditorTreeWidgetItem * pItem) { if(!pItem) return QString(); QString szName = pItem->name(); ClassEditorTreeWidgetItem * pNItem = (ClassEditorTreeWidgetItem *)pItem->parent(); while(pNItem) { QString szTmp = pNItem->name(); if(!szTmp.isEmpty()) { szName.prepend("::"); szName.prepend(szTmp); } pNItem = (ClassEditorTreeWidgetItem *)pNItem->parent(); } return szName; } ClassEditorTreeWidgetItem * ClassEditorWidget::findTopLevelItem(const QString & szName) { for(int i=0; i < m_pTreeWidget->topLevelItemCount(); i++) { if(KviQString::equalCI(m_pTreeWidget->topLevelItem(i)->text(0),szName)) return (ClassEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i); } return 0; } ClassEditorTreeWidgetItem * ClassEditorWidget::findItem(const QString & szFullName) { bool bFound; QStringList lNamespaces = szFullName.split("::"); if(lNamespaces.count() == 0) return 0; ClassEditorTreeWidgetItem * pItem = findTopLevelItem(lNamespaces.at(0)); if(!pItem) return 0; for(int i=1; i < lNamespaces.count(); i++) { bFound = false; for(int j=0; j < pItem->childCount(); j++) { if (KviQString::equalCI(pItem->child(j)->text(0),lNamespaces.at(i))) { pItem=( ClassEditorTreeWidgetItem *)pItem->child(j); bFound = true; break; } } if(!bFound) return 0; } return (ClassEditorTreeWidgetItem *)pItem; } ClassEditorTreeWidgetItem * ClassEditorWidget::createFullItem(const QString & szFullName) { bool bFound; int i; QStringList lNamespaces = szFullName.split("::"); if(lNamespaces.count() == 0) return 0; if(lNamespaces.count() == 1) { ClassEditorTreeWidgetItem * pItem = findTopLevelItem(lNamespaces.at(0)); if(pItem) return pItem; return new ClassEditorTreeWidgetItem(m_pTreeWidget,ClassEditorTreeWidgetItem::Class,lNamespaces.at(0)); } ClassEditorTreeWidgetItem * pItem = findTopLevelItem(lNamespaces.at(0)); if(!pItem) pItem = new ClassEditorTreeWidgetItem(m_pTreeWidget,ClassEditorTreeWidgetItem::Namespace,lNamespaces.at(0)); for(i=1; i < lNamespaces.count()-1; i++) { bFound = false; for(int j=0; j < pItem->childCount();j++) { if(KviQString::equalCI(pItem->child(j)->text(0),lNamespaces.at(i))) { pItem = (ClassEditorTreeWidgetItem *)pItem->child(j); bFound = true; break; } } if(!bFound) pItem = new ClassEditorTreeWidgetItem(pItem,ClassEditorTreeWidgetItem::Namespace,lNamespaces.at(i)); } return new ClassEditorTreeWidgetItem(pItem,ClassEditorTreeWidgetItem::Class,lNamespaces.at(i)); } ClassEditorTreeWidgetItem * ClassEditorWidget::createFullNamespace(const QString & szFullName) { bool bFound; int i; QStringList lNamespaces = szFullName.split("::"); if(lNamespaces.count() == 0) return 0; ClassEditorTreeWidgetItem * pItem = findTopLevelItem(lNamespaces.at(0)); if(!pItem) pItem = new ClassEditorTreeWidgetItem(m_pTreeWidget,ClassEditorTreeWidgetItem::Namespace,lNamespaces.at(0)); if(lNamespaces.count() == 1) return pItem; for(i=1; i < lNamespaces.count(); i++) { bFound = false; for(int j=0;jchildCount();j++) { if(KviQString::equalCI(pItem->child(j)->text(0),lNamespaces.at(i)) && (( ClassEditorTreeWidgetItem *)pItem->child(j))->isNamespace()) { pItem = (ClassEditorTreeWidgetItem *)pItem->child(j); bFound = true; break; } } if(!bFound) pItem = new ClassEditorTreeWidgetItem(pItem,ClassEditorTreeWidgetItem::Namespace,lNamespaces.at(i)); } return pItem; } void ClassEditorWidget::oneTimeSetup() { QStringList sl; QString szClassName; QString szPath; g_pApp->getLocalKvircDirectory(szPath,KviApplication::Classes); QDir d(szPath); QString szExtension = QString("*%1").arg(KVI_FILEEXTENSION_SCRIPT); // *.kvs sl = d.entryList(QStringList(szExtension), QDir::Files | QDir::NoDotAndDotDot); g_pModuleManager->getModule("objects"); KviPointerHashTableIterator it(*KviKvsKernel::instance()->objectController()->classDict()); KviKvsObjectClass * pClass = 0; ClassEditorTreeWidgetItem * pClassItem = 0; while(KviKvsObjectClass * pClass = it.current()) { if(pClass->isBuiltin()) m_pClasses->insert(it.currentKey(),0); else { QString szTmp; szTmp = it.currentKey(); szTmp.replace("::","--"); szTmp.append(".kvs"); if(sl.indexOf(szTmp) == -1) { szClassName = it.currentKey(); pClassItem = createFullItem(szClassName); createFullClass(it.current(),pClassItem,szClassName); } } ++it; } for(int i=0; i < sl.count(); i++) { szClassName = sl.at(i); szClassName.replace("--","::"); szClassName.chop(4); pClassItem = createFullItem(szClassName); pClass = KviKvsKernel::instance()->objectController()->lookupClass(szClassName); if(pClass) createFullClass(pClass, pClassItem, szClassName); } loadNotBuiltClasses(); connect(m_pTreeWidget,SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)),this,SLOT(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *))); m_pTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_pTreeWidget,SIGNAL(customContextMenuRequested(const QPoint &)),this,SLOT(customContextMenuRequested(const QPoint &))); } void ClassEditorWidget::createFullClass(KviKvsObjectClass * pClass, ClassEditorTreeWidgetItem * pClassItem, const QString & szClassName) { KviPointerHashTableIterator it(* pClass->getHandlers()); QStringList szFunctionsList; while(it.current()) { szFunctionsList.append(it.currentKey()); ++it; } szFunctionsList.sort(); ClassEditorTreeWidgetItem *pFunctionItem; m_pClasses->insert(szClassName,pClassItem); KviKvsObjectClass * pParentClass = pClass->parentClass(); pClassItem->setInheritsClass(pParentClass->name()); for(int i=0;ilookupFunctionHandler(szFunctionsList.at(i)); if (pClass->isScriptHandler(szFunctionsList.at(i)) && !pHandler->isClone()) { pFunctionItem=findFunction(szFunctionsList.at(i), pClassItem); if(!pFunctionItem) pFunctionItem = new ClassEditorTreeWidgetItem(pClassItem,ClassEditorTreeWidgetItem::Method,szFunctionsList.at(i)); pClass->getFunctionCode(szCode,*pHandler); pFunctionItem->setBuffer(szCode); pFunctionItem->setReminder(pClass->reminder(pHandler)); if(pHandler->flags() & KviKvsObjectFunctionHandler::Internal) pFunctionItem->setInternalFunction(true); } //++it; } } /* void ClassEditorWidget::classRefresh(const QString & szName) { if(m_bSaving) return; ClassEditorTreeWidgetItem * item; KviKvsScript * class = KviKvsClassManager::instance()->classDict()->find(szName); item = createFullItem(szName); if(item!=m_pLastEditedItem) { item->setBuffer(class->code()); return; } if( QMessageBox::warning(0,__tr2qs_ctx("OverWrite Current Class","editor"), __tr2qs_ctx("An external script has changed the class you are currently editing. Do you want to accept the external changes?","editor"), QMessageBox::Yes,QMessageBox::No|QMessageBox::Default|QMessageBox::Escape) != QMessageBox::Yes ) return; item->setBuffer(class->code()); m_pEditor->setText(class->code()); } */ bool ClassEditorWidget::hasSelectedItems() { return m_pTreeWidget->selectedItems().count() ? 1 : 0; } bool ClassEditorWidget::classExists(QString & szFullItemName) { if(m_pClasses->find(szFullItemName)) return true; else return false; } void ClassEditorWidget::renameFunction() { if(!m_pLastEditedItem) return; ClassEditorTreeWidgetItem * pFunction = m_pLastEditedItem; QString szClassName = buildFullClassName((ClassEditorTreeWidgetItem *)pFunction->parent()); QString szFunctionName = pFunction->name(); QString szReminder = pFunction->reminder(); QString szNewReminder = szReminder; ClassEditorTreeWidgetItem * pParentClass = (ClassEditorTreeWidgetItem *) pFunction->parent(); QString szNewFunctionName = szFunctionName; bool bInternal = pFunction->isInternalFunction(); if(!askForFunction(szNewFunctionName,szNewReminder,&bInternal,szClassName,true)) return; if(KviQString::equalCS(szFunctionName,szNewFunctionName) && bInternal == pFunction->isInternalFunction()) { if(!KviQString::equalCS(szNewReminder,szReminder)) { pFunction->setReminder(szNewReminder); KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(szClassName); if(pClass) { KviKvsObjectFunctionHandler * pHandler = pClass->lookupFunctionHandler(szFunctionName); if(pHandler) { pClass->setReminder(szNewReminder,pHandler); QString szPath; QString szFileName = szClassName.toLower(); szFileName += ".kvs"; szFileName.replace("::","--"); g_pApp->getLocalKvircDirectory(szPath,KviApplication::Classes,szFileName); pClass->save(szPath); } } currentItemChanged(pFunction,pFunction); } else { g_pClassEditorModule->lock(); QMessageBox::information(this, __tr2qs_ctx("Function already exists","editor"), __tr2qs_ctx("This name is already in use. Please choose another one.","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); g_pClassEditorModule->unlock(); return; } } pFunction->setName(szNewFunctionName); pFunction->setReminder(szNewReminder); currentItemChanged(pFunction,pFunction); pFunction->setInternalFunction(bInternal); pParentClass->setClassNotBuilt(true); KviPointerList lInheritedClasses; lInheritedClasses.setAutoDelete(false); searchInheritedClasses(szClassName,lInheritedClasses); for(unsigned int i=0; i < lInheritedClasses.count(); i++) lInheritedClasses.at(i)->setClassNotBuilt(true); activateItem(pFunction); } ClassEditorTreeWidgetItem * ClassEditorWidget::findFunction(const QString & szFunctionName, ClassEditorTreeWidgetItem * pClass) { for(int i=0; i < pClass->childCount(); i++) { if(KviQString::equalCI(szFunctionName,((ClassEditorTreeWidgetItem *)pClass->child(i))->name())) return (ClassEditorTreeWidgetItem *) pClass->child(i); } return 0; } void ClassEditorWidget::renameItem() { if(!m_pLastEditedItem) return; if(m_pLastEditedItem->isClass()) renameClass(m_pLastEditedItem); else if(m_pLastEditedItem->isNamespace()) renameNamespace(m_pLastEditedItem); else { // is function ClassEditorTreeWidgetItem * pParent = (ClassEditorTreeWidgetItem *)m_pLastEditedItem->parent(); if(pParent->isClass()) renameClass(pParent); } } void ClassEditorWidget::renameClass(ClassEditorTreeWidgetItem * pClassItem) { QString szClassName = buildFullClassName(pClassItem); QString szNewClassName = szClassName; QString szInheritsClassName = pClassItem->inheritsClass(); QString szNewInheritsClassName = szInheritsClassName; bool bOk = askForClassName(szNewClassName,szNewInheritsClassName,true); if(!bOk) return; if(classExists(szNewClassName) && KviQString::equalCS(szClassName,szNewClassName) && KviQString::equalCS(szInheritsClassName,szNewInheritsClassName)) { g_pClassEditorModule->lock(); QMessageBox::information(this, __tr2qs_ctx("Class already exists","editor"), __tr2qs_ctx("This name is already in use. Please choose another one.","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); g_pClassEditorModule->unlock(); return; } /*if(szNewClassName.tmp.indexOf("@@",Qt::CaseInsensitive) != -1) { g_pClassEditorModule->lock(); QMessageBox::information(this, __tr2qs_ctx("Bad Namespace Name","editor"), __tr2qs_ctx("Found an empty namespace in namespace name","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); g_pClassEditorModule->unlock(); szNewName = ""; continue; }*/ ClassEditorTreeWidgetItem * pNewItem = 0; m_pClasses->removeRef(pClassItem); cutItem(pClassItem); if(szNewClassName.contains("::")) { pNewItem = createFullNamespace(szNewClassName.left(szNewClassName.lastIndexOf("::"))); pClassItem->setName(szNewClassName.section("::",-1,-1)); pNewItem->addChild(pClassItem); } else { pClassItem->setName(szNewClassName); m_pTreeWidget->addTopLevelItem(pClassItem); } m_pClasses->insert(szNewClassName,pClassItem); pClassItem->setInheritsClass(szNewInheritsClassName); pClassItem->setClassNotBuilt(true); KviPointerList lInheritedClasses; lInheritedClasses.setAutoDelete(false); searchInheritedClasses(szClassName,lInheritedClasses); for(unsigned int i=0; i < lInheritedClasses.count(); i++) { lInheritedClasses.at(i)->setClassNotBuilt(true); lInheritedClasses.at(i)->setExpanded(true); lInheritedClasses.at(i)->setInheritsClass(szNewClassName); } if(pNewItem) { activateItem(pNewItem); pNewItem->setExpanded(true); } else { activateItem(pClassItem); pClassItem->setExpanded(true); } qDebug("delete class %s caused by rename",szClassName.toUtf8().data()); KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(szClassName); if(pClass) KviKvsKernel::instance()->objectController()->deleteClass(pClass); } void ClassEditorWidget::cutItem(ClassEditorTreeWidgetItem * pItem) { int iIdx = m_pTreeWidget->indexOfTopLevelItem(pItem); if(iIdx!=-1) m_pTreeWidget->takeTopLevelItem(iIdx); else { ClassEditorTreeWidgetItem * pParent = (ClassEditorTreeWidgetItem *)pItem->parent(); pParent->removeChild(pItem); } } void ClassEditorWidget::renameNamespace(ClassEditorTreeWidgetItem * pOldNamespaceItem) { QString szOldNameSpaceName = buildFullClassName(m_pLastEditedItem); QString szNewNameSpaceName; if(!askForNamespaceName(__tr2qs_ctx("Rename Namespace","editor"),__tr2qs_ctx("Please enter the new name for the namespace","editor"),szOldNameSpaceName,szNewNameSpaceName)) return; if(KviQString::equalCI(szOldNameSpaceName,szNewNameSpaceName)) return; ClassEditorTreeWidgetItem * pNewItem = findItem(szNewNameSpaceName); if(pNewItem) { g_pClassEditorModule->lock(); if(pNewItem->isClass()) { QMessageBox::information(this, __tr2qs_ctx("Name already exists as Class name","editor"), __tr2qs_ctx("This name is already in use as Class name. Please choose another one.","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); } else { QMessageBox::information(this, __tr2qs_ctx("Namespace already exists","editor"), __tr2qs_ctx("This name is already in use. Please choose another one.","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); } g_pClassEditorModule->unlock(); return; } KviPointerList pList; pList.setAutoDelete(false); appendAllClassItemsRecursive(&pList,pOldNamespaceItem); cutItem(pOldNamespaceItem); if(szNewNameSpaceName.contains("::")) { pNewItem=createFullNamespace(szNewNameSpaceName.left(szNewNameSpaceName.lastIndexOf("::"))); pOldNamespaceItem->setName(szNewNameSpaceName.section("::",-1,-1)); pNewItem->addChild(pOldNamespaceItem); } else { m_pTreeWidget->addTopLevelItem(pOldNamespaceItem); pOldNamespaceItem->setName(szNewNameSpaceName); } for(unsigned int u=0; u < pList.count(); u++) { KviPointerHashTableEntry * pEntry = m_pClasses->findRef(pList.at(u)); if(pEntry) { KviPointerList lInheritedClasses; lInheritedClasses.setAutoDelete(false); QString szOldName = pEntry->key(); QString szNewName = buildFullClassName(pList.at(u)); searchInheritedClasses(szOldName,lInheritedClasses); for(unsigned int v=0; v < lInheritedClasses.count(); v++) { lInheritedClasses.at(v)->setClassNotBuilt(true); lInheritedClasses.at(v)->setExpanded(true); lInheritedClasses.at(v)->setInheritsClass(szNewName); } m_pClasses->removeRef(pList.at(u)); m_pClasses->insert(szNewName,pList.at(u)); pList.at(u)->setClassNotBuilt(true); KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(szOldName); if(pClass) KviKvsKernel::instance()->objectController()->deleteClass(pClass); } } if(pNewItem) { activateItem(pNewItem); pNewItem->setExpanded(true); } else { activateItem(pOldNamespaceItem); pOldNamespaceItem->setExpanded(true); } //searchReplace(szOldNameSpaceName+"::",true,szNewNameSpaceName+"::"); } void ClassEditorWidget::saveLastEditedItem() { if(!m_pLastEditedItem) return; if(!m_pEditor->isModified() || m_pLastEditedItem->isNamespace() || m_pLastEditedItem->isClass()) return; ((ClassEditorTreeWidgetItem *)m_pLastEditedItem)->setCursorPosition(m_pEditor->getCursor()); QString newCode; m_pEditor->getText(newCode); ((ClassEditorTreeWidgetItem *)m_pLastEditedItem)->setBuffer(newCode); ((ClassEditorTreeWidgetItem *)m_pLastEditedItem->parent())->setClassNotBuilt(true); } void ClassEditorWidget::currentItemChanged(QTreeWidgetItem * pTree, QTreeWidgetItem *) { saveLastEditedItem(); m_pLastEditedItem = (ClassEditorTreeWidgetItem *)pTree; if(!m_pLastEditedItem) { m_pClassNameLabel->setText(__tr2qs_ctx("No item selected","editor")); m_pClassNameRenameButton->setEnabled(false); m_pEditor->setText(""); m_pEditor->setEnabled(false); return; } ClassEditorTreeWidgetItem * pClassItem = 0; if(m_pLastEditedItem->isMethod()) pClassItem = (ClassEditorTreeWidgetItem *)m_pLastEditedItem->parent(); else pClassItem = m_pLastEditedItem; QString szClassName = buildFullClassName(pClassItem); if(m_pLastEditedItem->isNamespace()) { QString szLabelText = __tr2qs_ctx("Namespace","editor"); szLabelText += ": "; szLabelText += szClassName; szLabelText += ""; m_pClassNameLabel->setText(szLabelText); m_pClassNameRenameButton->setEnabled(true); m_pFunctionNameRenameButton->setEnabled(false); //m_pinheritsClassNameLabel->setText(""); m_pFunctionNameLabel->setText(""); m_pEditor->setText(""); m_pEditor->setEnabled(false); m_pTreeWidget->setFocus(); return; } QString szLabelText = __tr2qs_ctx("Class","editor"); szLabelText += ": "; szLabelText += szClassName; szLabelText += ", "; szLabelText += __tr2qs_ctx("inherits from class ","editor"); szLabelText += ": "; szLabelText += pClassItem->inheritsClass(); szLabelText += ""; m_pClassNameLabel->setText(szLabelText); szLabelText = __tr2qs_ctx("Member Function","editor"); if(m_pLastEditedItem->isMethod()) { szLabelText += ": "; szLabelText += m_pLastEditedItem->text(0); szLabelText += ""; m_pFunctionNameRenameButton->setEnabled(true); if(m_pLastEditedItem->reminder().isEmpty()) m_pReminderLabel->hide(); else { QString szReminderText =__tr2qs_ctx("Reminder text.","editor"); szReminderText += ": "; szReminderText += m_pLastEditedItem->reminder(); szReminderText += ""; m_pReminderLabel->setText(szReminderText); m_pReminderLabel->show(); } m_pFunctionNameLabel->setText(szLabelText); m_pFunctionNameLabel->show(); m_pFunctionNameRenameButton->show(); } else { m_pReminderLabel->hide(); m_pFunctionNameLabel->hide(); m_pClassNameRenameButton->setEnabled(true); m_pFunctionNameRenameButton->hide(); } if(m_pLastEditedItem->isClass()) { m_pFunctionNameRenameButton->setEnabled(false); m_pEditor->setText(""); m_pEditor->setEnabled(true); m_pTreeWidget->setFocus(); QString szBuffer; QStringList szFunctionsList; KviPointerHashTable lFunctions; lFunctions.setAutoDelete(false); ClassEditorTreeWidgetItem * pItem = 0; for(int i=0; i < pTree->childCount(); i++) { pItem = ((ClassEditorTreeWidgetItem *)pTree->child(i)); szFunctionsList.append(pItem->name()); lFunctions.insert(pItem->name(),pItem); } szFunctionsList.sort(); for(int i=0; i < szFunctionsList.count(); i++) { szBuffer += "Member Function: $" + szFunctionsList.at(i) + "
"; if(!lFunctions.find(szFunctionsList.at(i))->reminder().isEmpty()) szBuffer+="Parameters reminder: "+lFunctions.find(szFunctionsList.at(i))->reminder()+"
"; szBuffer+="
"; } m_pEditor->setUnHighlightedText(szBuffer); m_pEditor->setReadOnly(true); return; } m_pEditor->setReadOnly(false); m_pEditor->setText(((ClassEditorTreeWidgetItem *)pTree)->buffer()); m_pEditor->setFocus(); m_pEditor->setCursorPosition(((ClassEditorTreeWidgetItem *)pTree)->cursorPosition()); m_pEditor->setEnabled(true); } void ClassEditorWidget::customContextMenuRequested(QPoint pnt) { m_pContextPopup->clear(); m_pLastClickedItem = (ClassEditorTreeWidgetItem *)m_pTreeWidget->itemAt(pnt); QAction *pAction = m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::NameSpace)), __tr2qs_ctx("Add Namespace","editor"), this,SLOT(newNamespace())); if(!m_pLastClickedItem) pAction->setEnabled(true); else pAction->setEnabled(m_pLastClickedItem->isNamespace()); pAction = m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::Class)), __tr2qs_ctx("Add Class","editor"), this,SLOT(newClass())); if(!m_pLastClickedItem) pAction->setEnabled(true); else pAction->setEnabled(m_pLastClickedItem->isNamespace()); pAction = m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::Function)), __tr2qs_ctx("Add Member Function","editor"), this,SLOT(newMemberFunction())); if(!m_pLastClickedItem) pAction->setEnabled(false); else pAction->setEnabled(m_pLastClickedItem->isClass()| m_pLastClickedItem->isMethod()); bool bHasItems = m_pTreeWidget->topLevelItemCount(); bool bHasSelected = hasSelectedItems(); m_pContextPopup->addSeparator(); pAction = m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::Discard)), __tr2qs_ctx("Remove Selected","editor"), this,SLOT(removeSelectedItems())); pAction->setEnabled(bHasSelected); m_pContextPopup->addSeparator(); m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::Floppy)), __tr2qs_ctx("Export Selected...","editor"), this,SLOT(exportSelected())); pAction->setEnabled(bHasSelected); m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::Floppy)), __tr2qs_ctx("Export Selected in singles files...","editor"), this,SLOT(exportSelectedSepFiles())); pAction->setEnabled(bHasSelected); m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::Floppy)), __tr2qs_ctx("Export All...","editor"), this,SLOT(exportAll())); pAction->setEnabled(bHasItems); m_pContextPopup->addSeparator(); m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::Search)), __tr2qs_ctx("Find In Classes...","editor"), this,SLOT(slotFind())); pAction->setEnabled(bHasItems); m_pContextPopup->addAction( *(g_pIconManager->getSmallIcon(KviIconManager::NameSpace)), __tr2qs_ctx("Collapse All Items","editor"), this,SLOT(slotCollapseItems())); pAction->setEnabled(bHasItems); m_pContextPopup->popup(m_pTreeWidget->mapToGlobal(pnt)); } void ClassEditorWidget::searchReplace(const QString & szSearch, bool bReplace, const QString & szReplace) { KviPointerHashTableIterator it (*m_pClasses); while(it.current()) { ClassEditorTreeWidgetItem * pItem = it.current(); for(int j=0; j < pItem->childCount(); j++) { bool bOpened = false; if(((ClassEditorTreeWidgetItem *)pItem->child(j))->buffer().indexOf(szSearch,0,Qt::CaseInsensitive) != -1) { pItem->child(j)->setBackground(0, QColor(255,0,0,128)); if(bReplace) { QString &buffer=(QString &)((ClassEditorTreeWidgetItem *)pItem->child(j))->buffer(); pItem->setClassNotBuilt(true); buffer.replace(szSearch,szReplace,Qt::CaseInsensitive); } if(!bOpened) { openParentItems(pItem->child(j)); bOpened = true; } } else { pItem->child(j)->setBackground(0, QColor(255,255,255)); } } ++it; } } void ClassEditorWidget::slotFind() { g_pClassEditorModule->lock(); bool bOk; QString szSearch = QInputDialog::getText(this, __tr2qs_ctx("Find In Classes","editor"), __tr2qs_ctx("Please enter the text to be searched for. The matching function will be highlighted.","editor"), QLineEdit::Normal, "", &bOk); g_pClassEditorModule->unlock(); if(!bOk) return; if(szSearch.isEmpty()) return; m_pEditor->setFindText(szSearch); searchReplace(szSearch); } void ClassEditorWidget::slotFindWord(const QString & szSearch) { m_pEditor->setFindText(szSearch); } void ClassEditorWidget::recursiveCollapseItems(ClassEditorTreeWidgetItem * pItem) { if(!pItem) return; for(int i=0; i < pItem->childCount(); i++) { if(pItem->child(i)->childCount()) { pItem->child(i)->setExpanded(false); recursiveCollapseItems((ClassEditorTreeWidgetItem *)pItem->child(i)); } } } void ClassEditorWidget::slotCollapseItems() { for(int i=0; i < m_pTreeWidget->topLevelItemCount(); i++) { if(m_pTreeWidget->topLevelItem(i)->childCount()) { m_pTreeWidget->topLevelItem(i)->setExpanded(false); recursiveCollapseItems((ClassEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i)); } } } void ClassEditorWidget::slotReplaceAll(const QString & szFind, const QString & szReplace) { m_pEditor->setFindText(szReplace); searchReplace(szFind,true,szReplace); /* for (int i=0;itopLevelItemCount();i++) { recursiveSearchReplace(szFind,(ClassEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i),true,szReplace); } */ } void ClassEditorWidget::exportClassBuffer(QString & szBuffer, ClassEditorTreeWidgetItem * pItem) { QString szTmp = pItem->buffer(); KviCommandFormatter::blockFromBuffer(szTmp); QString szName = buildFullClassName(pItem); szBuffer = "class(\""; szBuffer += szName; if(!pItem->inheritsClass().isEmpty()) { szBuffer += "\",\""; szBuffer += pItem->inheritsClass(); } szBuffer += "\")\n{\n"; for(int i=0; i < pItem->childCount(); i++) { ClassEditorTreeWidgetItem * pFunction = (ClassEditorTreeWidgetItem *)pItem->child(i); if(pFunction->isMethod()) { szBuffer += "\t"; if(pFunction->isInternalFunction()) szBuffer += "internal "; szBuffer += "function "; szBuffer += pFunction->name(); szBuffer += "(" + pFunction->reminder() + ")\n"; QString szCode=pFunction->buffer(); KviCommandFormatter::blockFromBuffer(szCode); KviCommandFormatter::indent(szCode); szBuffer += szCode; } } szBuffer += "}\n"; } void ClassEditorWidget::exportAll() { exportClasses(false); } void ClassEditorWidget::exportSelectedSepFiles() { exportClasses(true,true); } void ClassEditorWidget::exportSelected() { exportClasses(true); } void ClassEditorWidget::exportSelectionInSinglesFiles(KviPointerList * pList) { bool bReplaceAll = false; if(!m_szDir.endsWith(QString(KVI_PATH_SEPARATOR))) m_szDir += KVI_PATH_SEPARATOR; if(!pList->first()) { g_pClassEditorModule->lock(); QMessageBox::warning(this,__tr2qs_ctx("Class Export","editor"),__tr2qs_ctx("There is no selection!","editor"),__tr2qs_ctx("OK","editor")); g_pClassEditorModule->unlock(); return; } g_pClassEditorModule->lock(); if(!KviFileDialog::askForDirectoryName( m_szDir, __tr2qs_ctx("Choose a Directory - KVIrc","editor"), m_szDir, QString(), false, true, this )) { g_pClassEditorModule->unlock(); return; } if(!m_szDir.endsWith(QString(KVI_PATH_SEPARATOR))) m_szDir += KVI_PATH_SEPARATOR; for(ClassEditorTreeWidgetItem * pItem = pList->first(); pItem; pItem = pList->next()) { QString szTmp; exportClassBuffer(szTmp,pItem); QString szFileName = buildFullClassName(pItem); szFileName += ".kvs"; szFileName.replace("::","_"); QString szCompletePath = m_szDir+szFileName; if(KviFileUtils::fileExists(szCompletePath) && !bReplaceAll) { QString szMsg = __tr2qs_ctx("The file \"%1\" exists. Do you want to replace it?","editor").arg(szFileName); int iRet = QMessageBox::question(this,__tr2qs_ctx("Replace file","editor"),szMsg,__tr2qs_ctx("Yes","editor"),__tr2qs_ctx("Yes to All","editor"),__tr2qs_ctx("No","editor")); if(iRet != 2) { KviFileUtils::writeFile(szCompletePath,szTmp); if(iRet == 1) bReplaceAll = true; } } else KviFileUtils::writeFile(szCompletePath,szTmp); } g_pClassEditorModule->unlock(); } void ClassEditorWidget::exportClasses(bool bSelectedOnly, bool bSingleFiles) { QString szOut; QString szNameFile; QString szFile; int iCount = 0; saveLastEditedItem(); KviPointerList list; list.setAutoDelete(false); if(bSelectedOnly) appendSelectedClassItems(&list); else appendAllClassItems(&list); if(bSingleFiles) { exportSelectionInSinglesFiles(&list); return; } ClassEditorTreeWidgetItem * pTempItem = 0; KviPointerList skiplist; skiplist.setAutoDelete(false); for(ClassEditorTreeWidgetItem * pItem = list.first(); pItem; pItem = list.next()) { pTempItem = pItem; if(skiplist.findRef(pItem)!=-1) continue; ClassEditorTreeWidgetItem *pParentClass = m_pClasses->find(pItem->inheritsClass()); KviPointerList linkedClasses; linkedClasses.setAutoDelete(false); linkedClasses.append(pItem); while(pParentClass) { if(skiplist.findRef(pParentClass)!=-1) break; linkedClasses.append(pParentClass); pParentClass = m_pClasses->find(pParentClass->inheritsClass()); } for(int i = linkedClasses.count()-1; i >= 0; i--) { iCount++; QString szTmp; exportClassBuffer(szTmp,linkedClasses.at(i)); skiplist.append(linkedClasses.at(i)); szOut += szTmp; szOut += "\n"; } } if(szOut.isEmpty()) { g_pClassEditorModule->lock(); QMessageBox::warning(this,__tr2qs_ctx("Class Export","editor"),__tr2qs_ctx("The exported file would be empty: cowardly refusing to write it","editor"),__tr2qs_ctx("OK","editor")); g_pClassEditorModule->unlock(); return; } QString szName = m_szDir; if(!szName.endsWith(QString(KVI_PATH_SEPARATOR))) szName += KVI_PATH_SEPARATOR; g_pClassEditorModule->lock(); if(iCount != 1) szNameFile = "classes"; else { QString szTmp = buildFullClassName(pTempItem); szNameFile = szTmp.replace("::","_"); } szName += szNameFile; szName += ".kvs"; if(!KviFileDialog::askForSaveFileName( szFile, __tr2qs_ctx("Choose a Filename - KVIrc","editor"), szName, KVI_FILTER_SCRIPT, false, true, true, this )) { g_pClassEditorModule->unlock(); return; } m_szDir=QFileInfo(szFile).absolutePath(); g_pClassEditorModule->unlock(); if(!KviFileUtils::writeFile(szFile,szOut)) { g_pClassEditorModule->lock(); QMessageBox::warning(this,__tr2qs_ctx("Write Failed - KVIrc","editor"),__tr2qs_ctx("Unable to write to the class file.","editor"),__tr2qs_ctx("OK","editor")); g_pClassEditorModule->unlock(); } } void ClassEditorWidget::saveProperties(KviConfigurationFile * pCfg) { pCfg->writeEntry("Sizes",m_pSplitter->sizes()); QString szName; if(m_pLastEditedItem) szName = buildFullClassName(m_pLastEditedItem); pCfg->writeEntry("LastClass",szName); } void ClassEditorWidget::loadProperties(KviConfigurationFile * pCfg) { QList def; def.append(20); def.append(80); m_pSplitter->setSizes(pCfg->readIntListEntry("Sizes",def)); QString szTmp = pCfg->readEntry("LastClass",QString()); ClassEditorTreeWidgetItem * pItem = findItem(szTmp); activateItem(pItem); } void ClassEditorWidget::appendSelectedClassItems(KviPointerList * pList) { QList list = m_pTreeWidget->selectedItems(); for(int i=0; i < list.count(); i++) { if(((ClassEditorTreeWidgetItem *)list.at(i))->isClass()) pList->append((ClassEditorTreeWidgetItem *)list.at(i)); else appendSelectedClassItemsRecursive(pList,list.at(i)); } } void ClassEditorWidget::appendSelectedClassItemsRecursive(KviPointerList * pList, QTreeWidgetItem * pStartFrom) { for(int i=0; i < pStartFrom->childCount(); i++) { if(((ClassEditorTreeWidgetItem *)pStartFrom->child(i))->isClass()) pList->append(((ClassEditorTreeWidgetItem *)pStartFrom->child(i))); else appendSelectedClassItemsRecursive(pList,pStartFrom->child(i)); } } void ClassEditorWidget::appendAllClassItems(KviPointerList * pList) { KviPointerHashTableIterator it (*m_pClasses); while(it.current()) { pList->append(it.current()); ++it; } } void ClassEditorWidget::appendAllClassItemsRecursive(KviPointerList * pList, QTreeWidgetItem * pStartFrom) { for(int i=0; i < pStartFrom->childCount(); i++) { if(((ClassEditorTreeWidgetItem *)pStartFrom->child(i))->isClass()) { pList->append((ClassEditorTreeWidgetItem *)pStartFrom->child(i)); } else { appendAllClassItemsRecursive(pList,pStartFrom->child(i)); } } } void ClassEditorWidget::removeItemChildren(ClassEditorTreeWidgetItem * pItem, KviPointerList & lRemovedItems) { if(pItem->isClass()) { KviPointerList lInheritedClasses; lInheritedClasses.setAutoDelete(false); searchInheritedClasses(buildFullClassName(pItem),lInheritedClasses); for(unsigned int u=0; u < lInheritedClasses.count(); u++) { lInheritedClasses.at(u)->setClassNotBuilt(true); lInheritedClasses.at(u)->setExpanded(true); lInheritedClasses.at(u)->setInheritsClass("object"); } } while(pItem->childCount() > 0) { ClassEditorTreeWidgetItem * pChild = (ClassEditorTreeWidgetItem *)(pItem->child(0)); if(pChild->childCount()) removeItemChildren(pChild,lRemovedItems); if(pChild->isClass()) { m_pClasses->removeRef(pChild); KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(buildFullClassName(pChild)); if(pClass) KviKvsKernel::instance()->objectController()->deleteClass(pClass); qDebug("removing class %s %p",buildFullClassName(pChild).toUtf8().data(), pClass); } pItem->removeChild(pChild); lRemovedItems.append(pItem); delete pChild; } } bool ClassEditorWidget::removeItem(ClassEditorTreeWidgetItem * pItem, KviPointerList & lRemovedItems, bool * pbYesToAll) { if(!pItem) return true; QString szMsg; QString szName = pItem->name(); if(!*pbYesToAll) { saveLastEditedItem(); if(pItem->isClass()) { szMsg = QString(__tr2qs_ctx("Do you really want to remove the class \"%1\"?","editor")).arg(szName); } else if(pItem->isNamespace()) { szMsg = QString(__tr2qs_ctx("Do you really want to remove the namespace \"%1\"?","editor")).arg(szName); szMsg += "
"; szMsg += __tr2qs_ctx("Please note that all the children classes/functions will be deleted too.","editor"); } else if(pItem->isMethod()) { szMsg = QString(__tr2qs_ctx("Do you really want to remove the function \"%1\"?","editor")).arg(szName); } g_pClassEditorModule->lock(); int iRet = QMessageBox::question(this,__tr2qs_ctx("Remove item","editor"),szMsg,__tr2qs_ctx("Yes","editor"),__tr2qs_ctx("Yes to All","editor"),__tr2qs_ctx("No","editor")); g_pClassEditorModule->unlock(); switch(iRet) { case 0: // nothing break; case 1: *pbYesToAll = true; break; default: return false; break; } } if(pItem == m_pLastEditedItem) m_pLastEditedItem = 0; if(pItem == m_pLastClickedItem) m_pLastClickedItem = 0; if(pItem->childCount()) removeItemChildren(pItem,lRemovedItems); if(pItem->isClass()) { m_pClasses->removeRef(pItem); KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(buildFullClassName(pItem)); qDebug("removing class %s %p",buildFullClassName(pItem).toUtf8().data(), pClass); if(pClass) KviKvsKernel::instance()->objectController()->deleteClass(pClass); else { QString szFileName = buildFullClassName(pItem); szFileName.replace("::","--"); szFileName.append(KVI_FILEEXTENSION_SCRIPT); QString szPath; g_pApp->getLocalKvircDirectory(szPath,KviApplication::Classes); QDir d(szPath); if(d.exists(szFileName)) { qDebug("rimuovo dal disco il file %s",szFileName.toUtf8().data()); d.remove(szFileName); } } } if(pItem->isMethod()) { updateClassHierarchy((ClassEditorTreeWidgetItem *)pItem->parent()); } lRemovedItems.append(pItem); delete pItem; return true; } void ClassEditorWidget::updateClassHierarchy(ClassEditorTreeWidgetItem * pClass) { pClass->setClassNotBuilt(true); KviPointerList lInheritedClasses; lInheritedClasses.setAutoDelete(false); searchInheritedClasses(pClass->name(),lInheritedClasses); for(unsigned int u=0; u < lInheritedClasses.count(); u++) { lInheritedClasses.at(u)->setClassNotBuilt(true); lInheritedClasses.at(u)->setInheritsClass(pClass->name()); lInheritedClasses.at(u)->setExpanded(true); } } void ClassEditorWidget::removeSelectedItems() { KviPointerList lRemovedItems; lRemovedItems.setAutoDelete(false); QList list = m_pTreeWidget->selectedItems(); bool bYesToAll = false; for(int i=0; i < list.count(); i++) { if(lRemovedItems.findRef((ClassEditorTreeWidgetItem *) list.at(i)) != -1) continue; if(!removeItem((ClassEditorTreeWidgetItem *) list.at(i),lRemovedItems,&bYesToAll)) return; } } bool ClassEditorWidget::askForClassName(QString & szClassName, QString & szInheritsClassName, bool bEdit) { KviClassEditorDialog * pDialog = new KviClassEditorDialog(this,"classdialog",m_pClasses,szClassName,szInheritsClassName,bEdit); szClassName = ""; g_pClassEditorModule->lock(); bool bOk = pDialog->exec(); g_pClassEditorModule->unlock(); if(bOk) { szClassName = pDialog->className(); szInheritsClassName = pDialog->inheritsClassName(); delete pDialog; return true; } delete pDialog; return false; } bool ClassEditorWidget::askForFunction(QString & szFunctionName, QString & szReminder, bool * bInternal, const QString & szClassName, bool bRenameMode) { KviClassEditorFunctionDialog * pDialog = new KviClassEditorFunctionDialog(this,"function",szClassName,szFunctionName,szReminder,*bInternal, bRenameMode); szFunctionName = ""; g_pClassEditorModule->lock(); bool bOk = pDialog->exec(); g_pClassEditorModule->unlock(); if(bOk) { szFunctionName = pDialog->functionName(); szReminder = pDialog->reminder(); *bInternal = pDialog->isInternalFunction(); delete pDialog; return true; } delete pDialog; return false; } bool ClassEditorWidget::askForNamespaceName(const QString & szAction, const QString & szText, const QString & szInitialText, QString & szNewName) { bool bOk = false; while(szNewName.isEmpty()) { g_pClassEditorModule->lock(); szNewName = QInputDialog::getText(this, szAction, szText, QLineEdit::Normal, szInitialText, &bOk); g_pClassEditorModule->unlock(); if(!bOk) return false; if(szNewName.isEmpty()) { g_pClassEditorModule->lock(); QMessageBox::warning(this, __tr2qs_ctx("Missing Namespace Name","editor"), __tr2qs_ctx("You must specify a valid name for the namespace","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); g_pClassEditorModule->unlock(); continue; } // we allow only [\w:]+ QRegExp re("[\\w:]+"); if(!re.exactMatch(szNewName)) { g_pClassEditorModule->lock(); QMessageBox::information(this, __tr2qs_ctx("Bad Namespace Name","editor"), __tr2qs_ctx("Namespace names can contain only letters, digits, underscores and '::' namespace separators","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); g_pClassEditorModule->unlock(); szNewName = ""; continue; } // make sure that we have only doubled "::" and not ":" or ":::..." QString szTmp = szNewName; szTmp.replace("::","@"); // @ is not allowed by the rule above if(szTmp.indexOf(":",Qt::CaseInsensitive) != -1) { g_pClassEditorModule->lock(); QMessageBox::information(this, __tr2qs_ctx("Bad Namespace Name","editor"), __tr2qs_ctx("Stray ':' character in namespace name: did you mean ...::?","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); g_pClassEditorModule->unlock(); szNewName = ""; continue; } if(szTmp.indexOf("@@",Qt::CaseInsensitive) != -1) { g_pClassEditorModule->lock(); QMessageBox::information(this, __tr2qs_ctx("Bad Namespace Name","editor"), __tr2qs_ctx("Found an empty namespace in namespace name","editor"), __tr2qs_ctx("OK, Let me try again...","editor")); g_pClassEditorModule->unlock(); szNewName = ""; continue; } } return true; } void ClassEditorWidget::openParentItems(QTreeWidgetItem * pItem) { if(pItem->parent()) { pItem->parent()->setExpanded(true); openParentItems(pItem->parent()); } } void ClassEditorWidget::activateItem(QTreeWidgetItem * pItem) { if(!pItem) return; openParentItems(pItem); m_pTreeWidget->setCurrentItem(pItem); } void ClassEditorWidget::newClass() { QString szClassName; QString szinheritsClassName; askForClassName(szClassName,szinheritsClassName,false); if(szClassName.isEmpty()) return; ClassEditorTreeWidgetItem * pItem = newItem(szClassName,ClassEditorTreeWidgetItem::Class); KviQString::escapeKvs(&szClassName, KviQString::EscapeSpace); KviQString::escapeKvs(&szinheritsClassName, KviQString::EscapeSpace); QString szClass = "class("; szClass += szClassName + "," + szinheritsClassName; szClass += "){}\n"; pItem->setInheritsClass(szinheritsClassName); activateItem(pItem); m_pClasses->insert(szClassName,pItem); KviKvsScript::run(szClass,g_pActiveWindow); } void ClassEditorWidget::newNamespace() { QString szName; if(!askForNamespaceName(__tr2qs_ctx("Add Namespace","editor"),__tr2qs_ctx("Please enter the name for the new namespace","editor"),"mynamespace",szName)) return; if(szName.isEmpty()) return; ClassEditorTreeWidgetItem * pItem = newItem(szName,ClassEditorTreeWidgetItem::Namespace); activateItem(pItem); } void ClassEditorWidget::newMemberFunction() { QString szFunctionName; QString szClassName; QString szReminder; if(m_pLastClickedItem->isMethod()) m_pLastClickedItem = (ClassEditorTreeWidgetItem*)m_pLastClickedItem->parent(); szClassName = buildFullClassName(m_pLastClickedItem); bool bInternal = false; if(!askForFunction(szFunctionName, szReminder,&bInternal,szClassName,false)) return; if(szFunctionName.isEmpty()) return; ClassEditorTreeWidgetItem * pItem = newItem(szFunctionName,ClassEditorTreeWidgetItem::Method); pItem->setInternalFunction(bInternal); if(!szReminder.isEmpty()) pItem->setReminder(szReminder); activateItem(pItem); ((ClassEditorTreeWidgetItem*)pItem->parent())->setClassNotBuilt(true); } ClassEditorTreeWidgetItem * ClassEditorWidget::newItem(QString & szName, ClassEditorTreeWidgetItem::Type eType) { if(m_pLastClickedItem) buildFullItemPath(m_pLastClickedItem,szName); QString szTmp; if(findItem(szName)) szName.append("1"); int iIdx = 2; while(findItem(szName)) { szTmp.setNum(iIdx); szName.chop(szTmp.length()); szName.append(szTmp); iIdx++; } ClassEditorTreeWidgetItem * pItem; pItem = createFullItem(szName); pItem->setType(eType); return pItem; } void ClassEditorWidget::build() { saveLastEditedItem(); KviPointerHashTableIterator it (*m_pClasses); KviPointerList linkedClasses; linkedClasses.setAutoDelete(false); KviPointerList skipClasses; skipClasses.setAutoDelete(false); bool bErrorWhilecompiling = false; while(it.current()) { ClassEditorTreeWidgetItem * pClass = it.current(); if(skipClasses.findRef(it.current()) != -1) { ++it; continue; } if(pClass->classNotBuilt()) { //qDebug("compiling %s",pClass->name().toUtf8().data()); ClassEditorTreeWidgetItem * pParentClass = m_pClasses->find(pClass->inheritsClass()); linkedClasses.append(pClass); //if (!pParentClass) qDebug("no parent class"); while(pParentClass) { if(pParentClass->classNotBuilt()) linkedClasses.append(pParentClass); pParentClass = m_pClasses->find(pParentClass->inheritsClass()); } for(int i = linkedClasses.count()-1; i >= 0; i--) { QString szFullClassName = buildFullClassName(linkedClasses.at(i)); KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(szFullClassName); if(pClass) KviKvsKernel::instance()->objectController()->deleteClass(pClass); QString szClass; exportClassBuffer(szClass, linkedClasses.at(i)); KviKvsScript::run(szClass,g_pActiveWindow); pClass = KviKvsKernel::instance()->objectController()->lookupClass(szFullClassName); if(!pClass) { bErrorWhilecompiling = true; QString szError = __tr2qs_ctx("Unable to compile class: ","editor"); szError += szFullClassName + "\n"; KviPointerList lInheritedClasses; lInheritedClasses.setAutoDelete(false); searchInheritedClasses(szFullClassName,lInheritedClasses); if(lInheritedClasses.count()) { szError += __tr2qs_ctx("These inherited classes will be not compiled too:","editor"); szError += "\n"; for(unsigned int u=0; u < lInheritedClasses.count(); u++) { szError += buildFullClassName(lInheritedClasses.at(u)) + "\n"; lInheritedClasses.at(u)->setClassNotBuilt(true); skipClasses.append(lInheritedClasses.at(u)); } } QMessageBox::critical(this,__tr2qs_ctx("Compilation error - KVIrc","editor"),szError, QMessageBox::Ok,QMessageBox::NoButton,QMessageBox::NoButton); break; } //else qDebug("class compiled %s :\n",szClass.toUtf8().data()); linkedClasses.at(i)->setClassNotBuilt(false); m_pEditor->setModified(false); } } ++it; } if(bErrorWhilecompiling) saveNotBuiltClasses(); else { QString szFileName = "libkviclasseditortmp.kvc"; QString szBuffer; g_pApp->getLocalKvircDirectory(szBuffer,KviApplication::ConfigPlugins,szFileName); KviConfigurationFile cfg(szBuffer,KviConfigurationFile::Write); cfg.clear(); cfg.sync(); } KviKvsKernel::instance()->objectController()->flushUserClasses(); } void ClassEditorWidget::loadNotBuiltClasses() { QString szFileName = "libkviclasseditortmp.kvc"; QString szBuffer; g_pApp->getLocalKvircDirectory(szBuffer,KviApplication::ConfigPlugins,szFileName); KviConfigurationFile cfg(szBuffer,KviConfigurationFile::Read); KviConfigurationFileIterator it(*(cfg.dict())); KviPointerList l; l.setAutoDelete(true); while(it.current()) { l.append(new QString(it.currentKey())); ++it; } for(QString * pszTmp = l.first(); pszTmp; pszTmp = l.next()) { cfg.setGroup(*pszTmp); ClassEditorTreeWidgetItem * pClassItem = createFullItem(*pszTmp); m_pClasses->insert(*pszTmp,pClassItem); pClassItem->setClassNotBuilt(true); KviConfigurationFileGroup * pDict = cfg.dict()->find(*pszTmp); if(pDict) { KviConfigurationFileGroupIterator it(*pDict); KviPointerList names; names.setAutoDelete(true); while(it.current()) { names.append(new QString(it.currentKey())); ++it; } for(QString * pszTmp = names.first(); pszTmp; pszTmp = names.next()) { if(KviQString::equalCI(*pszTmp,"@Inherits")) { pClassItem->setInheritsClass(cfg.readEntry(*pszTmp,"")); continue; } if((*pszTmp).left(9) == "@Reminder") continue; QString szCode = cfg.readEntry(*pszTmp,""); ClassEditorTreeWidgetItem * pFunctionItem = findFunction(*pszTmp, pClassItem); if(!pFunctionItem) pFunctionItem = new ClassEditorTreeWidgetItem(pClassItem,ClassEditorTreeWidgetItem::Method,*pszTmp); pFunctionItem->setBuffer(szCode); QString szEntry = "@Reminder|" + (*pszTmp); QString szReminder = cfg.readEntry(szEntry,""); pFunctionItem->setReminder(szReminder); } } } } void ClassEditorWidget::saveNotBuiltClasses() { saveLastEditedItem(); KviPointerHashTableIterator it (*m_pClasses); QString szFileName = "libkviclasseditortmp.kvc"; QString szBuffer; g_pApp->getLocalKvircDirectory(szBuffer,KviApplication::ConfigPlugins,szFileName); KviConfigurationFile cfg(szBuffer,KviConfigurationFile::Write); cfg.clear(); while(it.current()) { if(it.current()->classNotBuilt()) { KviKvsObjectClass * pClass = KviKvsKernel::instance()->objectController()->lookupClass(it.currentKey()); if(pClass) KviKvsKernel::instance()->objectController()->deleteClass(pClass); cfg.setGroup(it.currentKey()); cfg.writeEntry("@Inherits",it.current()->inheritsClass()); QString szReminderEntry; for(int i=0; i < it.current()->childCount(); i++) { if(!((ClassEditorTreeWidgetItem *)it.current()->child(i))->reminder().isEmpty()) { szReminderEntry="@Reminder|"+((ClassEditorTreeWidgetItem *)it.current()->child(i))->name(); cfg.writeEntry(szReminderEntry,((ClassEditorTreeWidgetItem *)it.current()->child(i))->reminder()); } cfg.writeEntry(((ClassEditorTreeWidgetItem *)it.current()->child(i))->name(),((ClassEditorTreeWidgetItem *)it.current()->child(i))->buffer()); } } ++it; } cfg.sync(); } void ClassEditorWidget::searchInheritedClasses(const QString szClass, KviPointerList & lInheritedClasses) { KviPointerHashTableIterator it (*m_pClasses); while(it.current()) { if(KviQString::equalCI(szClass,it.current()->inheritsClass())) lInheritedClasses.append(it.current()); ++it; } } ClassEditorWindow::ClassEditorWindow() : KviWindow(KviWindow::ScriptEditor,"classeditor",0) { g_pClassEditorWindow = this; setFixedCaption(__tr2qs_ctx("Class Editor","editor")); QGridLayout * pLayout = new QGridLayout(); m_pEditor = new ClassEditorWidget(this); pLayout->addWidget(m_pEditor,0,0,1,4); QPushButton * pBtn = new QPushButton(__tr2qs_ctx("&Build","editor"),this); pBtn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept))); pLayout->addWidget(pBtn,1,1); connect(pBtn,SIGNAL(clicked()),this,SLOT(buildClicked())); pBtn = new QPushButton(__tr2qs_ctx("&Save","editor"),this); pBtn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept))); pLayout->addWidget(pBtn,1,2); connect(pBtn,SIGNAL(clicked()),this,SLOT(saveClicked())); pBtn = new QPushButton(__tr2qs_ctx("Close","editor"),this); pBtn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Discard))); pLayout->addWidget(pBtn,1,3); connect(pBtn,SIGNAL(clicked()),this,SLOT(cancelClicked())); pLayout->setRowStretch(0,1); pLayout->setColumnStretch(0,1); setLayout(pLayout); } ClassEditorWindow::~ClassEditorWindow() { g_pClassEditorWindow = 0; } void ClassEditorWindow::buildClicked() { m_pEditor->build(); } void ClassEditorWindow::saveClicked() { m_pEditor->saveNotBuiltClasses(); } void ClassEditorWindow::cancelClicked() { close(); } QPixmap * ClassEditorWindow::myIconPtr() { return g_pIconManager->getSmallIcon(KviIconManager::ClassEditor); } void ClassEditorWindow::configGroupName(QString &szName) { szName = "classeditor"; } void ClassEditorWindow::saveProperties(KviConfigurationFile * pCfg) { m_pEditor->saveProperties(pCfg); } void ClassEditorWindow::loadProperties(KviConfigurationFile * pCfg) { m_pEditor->loadProperties(pCfg); } KviClassEditorDialog::KviClassEditorDialog(QWidget * pParent, const QString & szName, KviPointerHashTable * pClasses, const QString & szClassName, const QString & szInheritsClassName, bool bRenameMode) : QDialog(pParent) { setObjectName(szName); QGridLayout * pLayout = new QGridLayout(this); KviTalHBox * pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,0,0); QLabel * pLabel = new QLabel(pHBox); pLabel->setObjectName("classnamelabel"); pLabel->setText(__tr2qs_ctx("Please enter the name for the class:","editor")); m_pClassNameLineEdit = new QLineEdit(pHBox); m_pClassNameLineEdit->setObjectName("classnameineedit"); m_pClassNameLineEdit->setText(szClassName); pLabel->setBuddy(m_pClassNameLineEdit); QRegExp re; if(!bRenameMode) { // we allow only [\w:]+ class name re.setPattern("[\\w]+"); m_pClassNameLineEdit->setToolTip(__tr2qs_ctx("Class names can contain only letters, digits and underscores","editor")); } else { // in editor mode we allow [\w:]+ and namespace separator re.setPattern("[\\w]+(::[\\w]+)+"); m_pClassNameLineEdit->setToolTip(__tr2qs_ctx("In rename mode class names can contain only letters, digits and underscores and namespaces :: separator","editor")); } QRegExpValidator * pValidator = new QRegExpValidator(re,this); m_pClassNameLineEdit->setValidator(pValidator); m_pClassNameLineEdit->setObjectName("functionameineedit"); pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,1,0); pLabel = new QLabel(pHBox); pLabel->setObjectName("Inheritsclasslabel"); pLabel->setText(__tr2qs_ctx("Inherits Class:","editor")); m_pInheritsClassComboBox = new QComboBox(pHBox); pLabel->setBuddy(m_pInheritsClassComboBox); KviPointerHashTableIterator pClassesIt(*pClasses); QStringList szClasses; while(pClassesIt.current()) { if(!KviQString::equalCI(pClassesIt.currentKey(),szClassName)) szClasses.append(pClassesIt.currentKey()); ++pClassesIt; } KviPointerHashTableIterator pBuiltinClasses(*KviKvsKernel::instance()->objectController()->classDict()); while(pBuiltinClasses.current()) { if(pBuiltinClasses.current()->isBuiltin()) szClasses.append(pBuiltinClasses.currentKey()); ++pBuiltinClasses; } int iCurrentIdx; szClasses.sort(); for(int i=0; i < szClasses.count(); i++) m_pInheritsClassComboBox->addItem(szClasses.at(i)); if(szInheritsClassName.isEmpty()) iCurrentIdx = m_pInheritsClassComboBox->findText("object"); else { iCurrentIdx = m_pInheritsClassComboBox->findText(szInheritsClassName); if(iCurrentIdx == -1) iCurrentIdx = m_pInheritsClassComboBox->findText("object"); } m_pInheritsClassComboBox->setCurrentIndex(iCurrentIdx); m_pClassNameLineEdit->setFocus(); connect(m_pClassNameLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &))); pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,2,0); m_pNewClassButton = new QPushButton(pHBox); m_pNewClassButton->setObjectName("newclassbutton"); if(bRenameMode) m_pNewClassButton->setText(__tr2qs_ctx("&Rename Class","editor")); else { m_pNewClassButton->setText(__tr2qs_ctx("&Create Class","editor")); m_pNewClassButton->setEnabled(false); } connect(m_pNewClassButton, SIGNAL(clicked()), this, SLOT(accept())); QPushButton * pCancelButton = new QPushButton(pHBox); pCancelButton->setObjectName("cancelButton"); pCancelButton->setText(__tr2qs_ctx("&Cancel","editor")); connect(pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); setLayout(pLayout); } KviClassEditorDialog::~KviClassEditorDialog() { } void KviClassEditorDialog::textChanged(const QString & szText) { m_pNewClassButton->setEnabled(!szText.isEmpty()); } KviClassEditorFunctionDialog::KviClassEditorFunctionDialog(QWidget * pParent, const QString & szName, const QString & szClassName, const QString & szFunctionName, const QString & szReminder, bool bIsInternal, bool bRenameMode) : QDialog(pParent) { setObjectName(szName); QGridLayout * pLayout = new QGridLayout(this); KviTalHBox * pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,0,0); QLabel * pLabel = new QLabel(pHBox); pLabel->setObjectName("classnamelabel"); pLabel->setText("Class: "+szClassName+""); pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,1,0); pLabel = new QLabel(pHBox); pLabel->setObjectName("functionnamelabel"); pLabel->setText(__tr2qs_ctx("Please enter the name for the member function:","editor")); m_pFunctionNameLineEdit = new QLineEdit(pHBox); // we allow only [\w:]+ function name QRegExp re("[\\w]+"); QRegExpValidator * pValidator = new QRegExpValidator(re,this); m_pFunctionNameLineEdit->setValidator(pValidator); m_pFunctionNameLineEdit->setObjectName("functionameineedit"); m_pFunctionNameLineEdit->setToolTip(__tr2qs_ctx("Function names can contain only letters, digits and underscores","editor")); m_pFunctionNameLineEdit->setText(szFunctionName); pLabel->setBuddy(m_pFunctionNameLineEdit); pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,2,0); pLabel = new QLabel(pHBox); pLabel->setObjectName("reminderlabel"); pLabel->setWordWrap(1); pLabel->setText(__tr2qs_ctx("Please enter the optional reminder string for the member function:","editor")); m_pReminderLineEdit = new QLineEdit(pHBox); m_pReminderLineEdit->setText(szReminder); pLabel->setBuddy(m_pReminderLineEdit); pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,3,0); pLabel = new QLabel(pHBox); pLabel->setObjectName("functionnamelabel"); pLabel->setText(__tr2qs_ctx("Set as Internal Function: ","editor")); m_pInternalCheckBox = new QCheckBox(pHBox); m_pInternalCheckBox->setChecked(bIsInternal); m_pFunctionNameLineEdit->setFocus(); pLabel->setBuddy(m_pInternalCheckBox); connect(m_pFunctionNameLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &))); pHBox->setAlignment(m_pInternalCheckBox,Qt::AlignLeft); pHBox->setStretchFactor(m_pInternalCheckBox,70); pHBox->setStretchFactor(pLabel,30); pHBox = new KviTalHBox(this); pHBox->setSpacing(0); pHBox->setMargin(0); pLayout->addWidget(pHBox,4,0); m_pNewFunctionButton = new QPushButton(pHBox); m_pNewFunctionButton->setObjectName("newfunctionbutton"); if(!bRenameMode) m_pNewFunctionButton->setText(__tr2qs_ctx("&Add","editor")); else m_pNewFunctionButton->setText(__tr2qs_ctx("&Rename","editor")); if(szFunctionName.isEmpty()) m_pNewFunctionButton->setEnabled(false); connect(m_pNewFunctionButton, SIGNAL(clicked()), this, SLOT(accept())); QPushButton * pCancelButton = new QPushButton(pHBox); pCancelButton->setObjectName("cancelButton"); pCancelButton->setText(__tr2qs_ctx("&Cancel","editor")); connect(pCancelButton, SIGNAL(clicked()), this, SLOT(reject())); setLayout(pLayout); } KviClassEditorFunctionDialog::~KviClassEditorFunctionDialog() { } void KviClassEditorFunctionDialog::textChanged(const QString & szText) { m_pNewFunctionButton->setEnabled(!szText.isEmpty()); }