//=============================================================================
//
// 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 option) 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 "KviRegExp.h"
#include "KviTalVBox.h"
#include "kvi_fileextensions.h"
#include "KviModuleManager.h"
#include <QList>
#include <QSplitter>
#include <QLayout>
#include <QToolTip>
#include <QPushButton>
#include <QDir>
#include <QMessageBox>
#include <QInputDialog>
#include <QMouseEvent>
#include <QPainter>
#include <QBrush>
#include <QStringList>
#include <QLabel>
extern ClassEditorWindow * g_pClassEditorWindow;
extern KviModule * g_pClassEditorModule;
ClassEditorTreeWidget::ClassEditorTreeWidget(QWidget * pParent)
: QTreeWidget(pParent)
{
setColumnCount(1);
setHeaderLabel(__tr2qs_ctx("Class", "editor"));
setSelectionMode(QAbstractItemView::ExtendedSelection);
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 = nullptr;
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 = nullptr;
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 = nullptr;
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 = nullptr;
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<QString, ClassEditorTreeWidgetItem>(100, false);
m_pClasses->setAutoDelete(false);
m_pLastEditedItem = nullptr;
m_pLastClickedItem = nullptr;
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->setContentsMargins(0, 0, 0, 0);
m_pTreeWidget = new ClassEditorTreeWidget(pVBox);
pVBox = new KviTalVBox(m_pSplitter);
KviTalHBox * pHBox = new KviTalHBox(pVBox);
pHBox->setSpacing(0);
pHBox->setContentsMargins(0, 0, 0, 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->setContentsMargins(0, 0, 0, 0);
pHBox = new KviTalHBox(pVBox);
pHBox->setSpacing(0);
pHBox->setContentsMargins(0, 0, 0, 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();
m_pTreeWidget->setSortingEnabled(true);
currentItemChanged(nullptr, nullptr);
}
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 nullptr;
}
ClassEditorTreeWidgetItem * ClassEditorWidget::findItem(const QString & szFullName)
{
bool bFound;
QStringList lNamespaces = szFullName.split("::");
if(lNamespaces.count() == 0)
return nullptr;
ClassEditorTreeWidgetItem * pItem = findTopLevelItem(lNamespaces.at(0));
if(!pItem)
return nullptr;
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 nullptr;
}
return (ClassEditorTreeWidgetItem *)pItem;
}
ClassEditorTreeWidgetItem * ClassEditorWidget::createFullItem(const QString & szFullName)
{
bool bFound;
int i;
QStringList lNamespaces = szFullName.split("::");
if(lNamespaces.count() == 0)
return nullptr;
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 nullptr;
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; j < pItem->childCount(); 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<QString, KviKvsObjectClass> it(*KviKvsKernel::instance()->objectController()->classDict());
KviKvsObjectClass * pClass = nullptr;
ClassEditorTreeWidgetItem * pClassItem = nullptr;
while(KviKvsObjectClass * pClass = it.current())
{
if(pClass->isBuiltin())
m_pClasses->insert(it.currentKey(), nullptr);
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<QString, KviKvsObjectFunctionHandler> 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; i < szFunctionsList.count(); i++)
{
QString szCode;
KviKvsObjectFunctionHandler * pHandler = pClass->lookupFunctionHandler(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);
}
}
}
bool ClassEditorWidget::hasSelectedItems()
{
return m_pTreeWidget->selectedItems().count() ? true : false;
}
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("Name Already Exists - KVIrc", "editor"),
__tr2qs_ctx("This function name is already in use. Please choose another one.", "editor"));
g_pClassEditorModule->unlock();
return;
}
}
pFunction->setName(szNewFunctionName);
pFunction->setReminder(szNewReminder);
currentItemChanged(pFunction, pFunction);
pFunction->setInternalFunction(bInternal);
pParentClass->setClassNotBuilt(true);
KviPointerList<ClassEditorTreeWidgetItem> 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 nullptr;
}
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("Name Already Exists - KVIrc", "editor"),
__tr2qs_ctx("This class name is already in use. Please choose another one.", "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"));
g_pClassEditorModule->unlock();
szNewName = "";
continue;
}*/
ClassEditorTreeWidgetItem * pNewItem = nullptr;
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<ClassEditorTreeWidgetItem> 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("Enter a New Name - KVIrc", "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 - KVIrc", "editor"),
__tr2qs_ctx("This class name is already in use. Please choose another one.", "editor"));
}
else
{
QMessageBox::information(this,
__tr2qs_ctx("Name Already Exists - KVIrc", "editor"),
__tr2qs_ctx("This namespace name is already in use. Please choose another one.", "editor"));
}
g_pClassEditorModule->unlock();
return;
}
KviPointerList<ClassEditorTreeWidgetItem> 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<QString, ClassEditorTreeWidgetItem> * pEntry = m_pClasses->findRef(pList.at(u));
if(pEntry)
{
KviPointerList<ClassEditorTreeWidgetItem> 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 = nullptr;
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 += ": <b>";
szLabelText += szClassName;
szLabelText += "</b>";
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 += ": <b>";
szLabelText += szClassName;
szLabelText += "</b>, ";
szLabelText += __tr2qs_ctx("inherits from class ", "editor");
szLabelText += ": <b>";
szLabelText += pClassItem->inheritsClass();
szLabelText += "</b>";
m_pClassNameLabel->setText(szLabelText);
szLabelText = __tr2qs_ctx("Member Function", "editor");
if(m_pLastEditedItem->isMethod())
{
szLabelText += ": <b>";
szLabelText += m_pLastEditedItem->text(0);
szLabelText += "</b>";
m_pFunctionNameRenameButton->setEnabled(true);
if(m_pLastEditedItem->reminder().isEmpty())
m_pReminderLabel->hide();
else
{
QString szReminderText = __tr2qs_ctx("Reminder text.", "editor");
szReminderText += ": <b>";
szReminderText += m_pLastEditedItem->reminder();
szReminderText += "</b>";
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<QString, ClassEditorTreeWidgetItem> lFunctions;
lFunctions.setAutoDelete(false);
ClassEditorTreeWidgetItem * pItem = nullptr;
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: <b>$" + szFunctionsList.at(i) + "</b><br>";
if(!lFunctions.find(szFunctionsList.at(i))->reminder().isEmpty())
szBuffer += "Parameters reminder: " + lFunctions.find(szFunctionsList.at(i))->reminder() + "<br>";
szBuffer += "<br>";
}
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::Save)),
__tr2qs_ctx("Export Selected...", "editor"),
this, SLOT(exportSelected()));
pAction->setEnabled(bHasSelected);
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::Save)),
__tr2qs_ctx("Export Selected in Single Files...", "editor"),
this, SLOT(exportSelectedSepFiles()));
pAction->setEnabled(bHasSelected);
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::Save)),
__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<QString, ClassEditorTreeWidgetItem> 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);
}
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<ClassEditorTreeWidgetItem> * 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("Warning While Exporting - KVIrc", "editor"), __tr2qs_ctx("Must select an entry from the list to export!", "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)
{
QMessageBox pMsgBox;
pMsgBox.setWindowTitle(__tr2qs_ctx("Confirm Replacing File - KVIrc", "editor"));
pMsgBox.setText(QString(__tr2qs_ctx("The file \"%1\" exists. Do you want to replace it?", "editor")).arg(szFileName));
pMsgBox.setIcon(QMessageBox::Question);
QAbstractButton * pYesButton = pMsgBox.addButton(__tr2qs_ctx("Yes", "editor"), QMessageBox::YesRole);
QAbstractButton * pAlwaysButton = pMsgBox.addButton(__tr2qs_ctx("Yes to All", "editor"), QMessageBox::YesRole);
QAbstractButton * pNoButton = pMsgBox.addButton( __tr2qs_ctx("No", "editor"), QMessageBox::NoRole);
pMsgBox.setDefaultButton(qobject_cast<QPushButton *>(pNoButton));
pMsgBox.exec();
if(pMsgBox.clickedButton() == pYesButton)
{
KviFileUtils::writeFile(szCompletePath, szTmp);
} else if(pMsgBox.clickedButton() == pAlwaysButton) {
KviFileUtils::writeFile(szCompletePath, szTmp);
bReplaceAll = true;
} else if(pMsgBox.clickedButton() == pNoButton || pMsgBox.clickedButton() == nullptr) {
// nothing
}
}
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<ClassEditorTreeWidgetItem> list;
list.setAutoDelete(false);
if(bSelectedOnly)
appendSelectedClassItems(&list);
else
appendAllClassItems(&list);
if(bSingleFiles)
{
exportSelectionInSinglesFiles(&list);
return;
}
ClassEditorTreeWidgetItem * pTempItem = nullptr;
KviPointerList<ClassEditorTreeWidgetItem> 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<ClassEditorTreeWidgetItem> 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("Warning While Exporting - KVIrc", "editor"), __tr2qs_ctx("The exported class file could be empty: cowardly refusing to write it", "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 to Classes File Failed - KVIrc", "editor"), __tr2qs_ctx("Unable to write to the classes file.", "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<int> 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<ClassEditorTreeWidgetItem> * pList)
{
QList<QTreeWidgetItem *> 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<ClassEditorTreeWidgetItem> * 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<ClassEditorTreeWidgetItem> * pList)
{
KviPointerHashTableIterator<QString, ClassEditorTreeWidgetItem> it(*m_pClasses);
while(it.current())
{
pList->append(it.current());
++it;
}
}
void ClassEditorWidget::appendAllClassItemsRecursive(KviPointerList<ClassEditorTreeWidgetItem> * 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<ClassEditorTreeWidgetItem> & lRemovedItems)
{
if(pItem->isClass())
{
KviPointerList<ClassEditorTreeWidgetItem> 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<ClassEditorTreeWidgetItem> & 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 += "<br>";
szMsg += __tr2qs_ctx("Please note that all the child classes/functions will also be deleted.", "editor");
}
else if(pItem->isMethod())
{
szMsg = QString(__tr2qs_ctx("Do you really want to remove the function \"%1\"?", "editor")).arg(szName);
}
g_pClassEditorModule->lock();
QMessageBox pMsgBox;
pMsgBox.setWindowTitle(__tr2qs_ctx("Confirm Removing Item - KVIrc", "editor"));
pMsgBox.setText(szMsg);
pMsgBox.setIcon(QMessageBox::Question);
QAbstractButton * pYesButton = pMsgBox.addButton(__tr2qs_ctx("Yes", "editor"), QMessageBox::YesRole);
QAbstractButton * pAlwaysButton = pMsgBox.addButton(__tr2qs_ctx("Yes to All", "editor"), QMessageBox::YesRole);
QAbstractButton * pNoButton = pMsgBox.addButton(__tr2qs_ctx("No", "editor"), QMessageBox::NoRole);
pMsgBox.setDefaultButton(qobject_cast<QPushButton *>(pNoButton));
pMsgBox.exec();
g_pClassEditorModule->unlock();
if(pMsgBox.clickedButton() == pYesButton)
{
// nothing
} else if(pMsgBox.clickedButton() == pAlwaysButton) {
*pbYesToAll = true;
} else if(pMsgBox.clickedButton() == pNoButton || pMsgBox.clickedButton() == nullptr) {
return false;
}
}
if(pItem == m_pLastEditedItem)
m_pLastEditedItem = nullptr;
if(pItem == m_pLastClickedItem)
m_pLastClickedItem = nullptr;
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("Removing file %s from disk", 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<ClassEditorTreeWidgetItem> 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<ClassEditorTreeWidgetItem> lRemovedItems;
lRemovedItems.setAutoDelete(false);
QList<QTreeWidgetItem *> 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("Invalid or Missing Name - KVIrc", "editor"),
__tr2qs_ctx("You must specify a valid name for the namespace.", "editor"));
g_pClassEditorModule->unlock();
continue;
}
// we allow only [\w:]+
KviRegExp re("[\\w:]+");
if(!re.exactMatch(szNewName))
{
g_pClassEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Namespace names can contain only letters, digits, underscores and '::' namespace separators.", "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("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Stray ':' character in namespace name: did you mean ...<namespace>::<name>?", "editor"));
g_pClassEditorModule->unlock();
szNewName = "";
continue;
}
if(szTmp.indexOf("@@", Qt::CaseInsensitive) != -1)
{
g_pClassEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Found an empty namespace in namespace name.", "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("Enter a Filename - KVIrc", "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<QString, ClassEditorTreeWidgetItem> it(*m_pClasses);
KviPointerList<ClassEditorTreeWidgetItem> linkedClasses;
linkedClasses.setAutoDelete(false);
KviPointerList<ClassEditorTreeWidgetItem> 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<ClassEditorTreeWidgetItem> 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);
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<QString> 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<QString> 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<QString, ClassEditorTreeWidgetItem> 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<ClassEditorTreeWidgetItem> & lInheritedClasses)
{
KviPointerHashTableIterator<QString, ClassEditorTreeWidgetItem> it(*m_pClasses);
while(it.current())
{
if(KviQString::equalCI(szClass, it.current()->inheritsClass()))
lInheritedClasses.append(it.current());
++it;
}
}
ClassEditorWindow::ClassEditorWindow()
: KviWindow(KviWindow::ScriptEditor, "classeditor", nullptr)
{
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 = nullptr;
}
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<QString, ClassEditorTreeWidgetItem> * 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->setContentsMargins(0, 0, 0, 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);
KviRegExp 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"));
}
QRegularExpressionValidator * pValidator = new QRegularExpressionValidator(re, this);
m_pClassNameLineEdit->setValidator(pValidator);
m_pClassNameLineEdit->setObjectName("functionameineedit");
pHBox = new KviTalHBox(this);
pHBox->setSpacing(0);
pHBox->setContentsMargins(0, 0, 0, 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<QString, ClassEditorTreeWidgetItem> pClassesIt(*pClasses);
QStringList szClasses;
while(pClassesIt.current())
{
if(!KviQString::equalCI(pClassesIt.currentKey(), szClassName))
szClasses.append(pClassesIt.currentKey());
++pClassesIt;
}
KviPointerHashTableIterator<QString, KviKvsObjectClass> 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->setContentsMargins(0, 0, 0, 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()
= default;
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->setContentsMargins(0, 0, 0, 0);
pLayout->addWidget(pHBox, 0, 0);
QLabel * pLabel = new QLabel(pHBox);
pLabel->setObjectName("classnamelabel");
pLabel->setText("Class: <b>" + szClassName + "</b>");
pHBox = new KviTalHBox(this);
pHBox->setSpacing(0);
pHBox->setContentsMargins(0, 0, 0, 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
KviRegExp re("[\\w]+");
QRegularExpressionValidator * pValidator = new QRegularExpressionValidator(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->setContentsMargins(0, 0, 0, 0);
pLayout->addWidget(pHBox, 2, 0);
pLabel = new QLabel(pHBox);
pLabel->setObjectName("reminderlabel");
pLabel->setWordWrap(true);
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->setContentsMargins(0, 0, 0, 0);
pLayout->addWidget(pHBox, 3, 0);
pLabel = new QLabel(pHBox);
pLabel->setObjectName("functionnamelabel");
pLabel->setText(__tr2qs_ctx("Set as <b>Internal</b> 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->setContentsMargins(0, 0, 0, 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()
= default;
void KviClassEditorFunctionDialog::textChanged(const QString & szText)
{
m_pNewFunctionButton->setEnabled(!szText.isEmpty());
}