//=============================================================================
//
// File : AliasEditorWindow.cpp
// Creation date : Mon Dec 23 2002 14:36:18 by Szymon Stefanek
//
// This file is part of the KVIrc IRC client distribution
// Copyright (C) 2002-2010 Szymon Stefanek (pragma at kvirc dot net)
//
// 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 "AliasEditorWindow.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 "KviKvsAliasManager.h"
#include "KviCommandFormatter.h"
#include "KviModule.h"
#include "KviTalVBox.h"
#include "kvi_fileextensions.h"
#include <QList>
#include <QSplitter>
#include <QLayout>
#include <QToolTip>
#include <QPushButton>
#include <QDir>
#include <QMessageBox>
#include <QInputDialog>
#include <QRegExp>
#include <QTreeWidget>
#include <QMouseEvent>
#include <QList>
#include <QPainter>
#include <QBrush>
extern AliasEditorWindow * g_pAliasEditorWindow;
extern KviModule * g_pAliasEditorModule;
AliasEditorTreeWidgetItem::AliasEditorTreeWidgetItem(QTreeWidget * pTreeWidget, Type eType, const QString & szName)
: QTreeWidgetItem(pTreeWidget), KviHeapObject(), m_eType(eType), m_pParentItem(nullptr)
{
setName(szName);
m_cPos = 0;
if(eType == AliasEditorTreeWidgetItem::Namespace)
setIcon(0, QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::NameSpace))));
else
setIcon(0, QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Alias))));
}
AliasEditorTreeWidgetItem::AliasEditorTreeWidgetItem(AliasEditorTreeWidgetItem * pParentItem, Type eType, const QString & szName)
: QTreeWidgetItem(pParentItem), m_eType(eType), m_pParentItem(pParentItem)
{
setName(szName);
m_cPos = 0;
setFlags(Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
if(eType == AliasEditorTreeWidgetItem::Namespace)
setIcon(0, QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::NameSpace))));
else
setIcon(0, QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Alias))));
}
void AliasEditorTreeWidgetItem::setName(const QString & szName)
{
m_szName = szName;
setText(0, m_szName);
}
void AliasEditorTreeWidgetItem::setType(Type t)
{
m_eType = t;
if(t == AliasEditorTreeWidgetItem::Namespace)
setIcon(0, QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::NameSpace))));
else
setIcon(0, QIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Alias))));
}
AliasEditorTreeWidget::AliasEditorTreeWidget(QWidget * par)
: QTreeWidget(par)
{
setColumnCount(1);
setHeaderLabel(__tr2qs_ctx("Alias", "editor"));
setSelectionMode(QAbstractItemView::ExtendedSelection);
setSortingEnabled(true);
setRootIsDecorated(true);
setAnimated(true);
}
AliasEditorTreeWidget::~AliasEditorTreeWidget()
{
//remove and delete all items
clear();
}
AliasEditorWidget::AliasEditorWidget(QWidget * par)
: QWidget(par)
{
m_pAliases = new KviPointerList<AliasEditorTreeWidgetItem>;
m_pAliases->setAutoDelete(false);
m_bSaving = false;
m_pLastEditedItem = nullptr;
m_pLastClickedItem = nullptr;
m_szDir = QDir::homePath();
QGridLayout * l = new QGridLayout(this);
m_pSplitter = new QSplitter(Qt::Horizontal, this);
m_pSplitter->setChildrenCollapsible(false);
l->addWidget(m_pSplitter, 0, 0);
KviTalVBox * box = new KviTalVBox(m_pSplitter);
box->setSpacing(0);
box->setMargin(0);
m_pTreeWidget = new AliasEditorTreeWidget(box);
QPushButton * btn = new QPushButton(__tr2qs_ctx("&Export All to...", "editor"), box);
connect(btn, SIGNAL(clicked()), this, SLOT(exportAll()));
box = new KviTalVBox(m_pSplitter);
KviTalHBox * hbox = new KviTalHBox(box);
hbox->setSpacing(0);
hbox->setMargin(0);
m_pNameLabel = new QLabel(__tr2qs_ctx("No item selected", "editor"), hbox);
m_pRenameButton = new QPushButton(__tr2qs_ctx("Rename", "editor"), hbox);
m_pRenameButton->setEnabled(false);
connect(m_pRenameButton, SIGNAL(clicked()), this, SLOT(renameItem()));
hbox->setStretchFactor(m_pNameLabel, 2);
m_pRenameButton->setToolTip(__tr2qs_ctx("Edit the alias or namespace name", "editor"));
m_pEditor = KviScriptEditor::createInstance(box);
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(nullptr, nullptr);
}
AliasEditorWidget::~AliasEditorWidget()
{
KviScriptEditor::destroyInstance(m_pEditor);
delete m_pAliases;
}
void AliasEditorWidget::buildFullItemPath(AliasEditorTreeWidgetItem * it, QString & szBuffer)
{
if(it->isAlias())
it = it->parentItem();
if(!it)
return;
while(it)
{
QString tmp = it->name();
if(!tmp.isEmpty())
{
szBuffer.prepend("::");
szBuffer.prepend(tmp);
}
it = it->parentItem();
}
}
QString AliasEditorWidget::buildFullItemName(AliasEditorTreeWidgetItem * it)
{
if(!it)
return QString();
QString szName = it->name();
AliasEditorTreeWidgetItem * nit = it->parentItem();
while(nit)
{
QString tmp = nit->name();
if(!tmp.isEmpty())
{
szName.prepend("::");
szName.prepend(tmp);
}
nit = nit->parentItem();
}
return szName;
}
//FIXME this should be called something like "findNamespace"
AliasEditorTreeWidgetItem * AliasEditorWidget::findTopLevelItem(const QString & szName)
{
AliasEditorTreeWidgetItem * pItem = nullptr;
for(int i = 0; i < m_pTreeWidget->topLevelItemCount(); i++)
{
pItem = (AliasEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
if(pItem->text(0) == szName && pItem->isNamespace())
return (AliasEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i);
}
return nullptr;
}
AliasEditorTreeWidgetItem * AliasEditorWidget::findItem(const QString & szFullName)
{
QStringList lNamespaces = szFullName.split("::");
if(!lNamespaces.count())
return nullptr;
AliasEditorTreeWidgetItem * pItem = findTopLevelItem(lNamespaces.at(0));
if(!pItem)
return nullptr;
bool bFound;
int i;
int j;
for(i = 1; i < lNamespaces.count(); i++)
{
bFound = false;
for(j = 0; j < pItem->childCount(); j++)
{
if(KviQString::equalCI(pItem->child(j)->text(0), lNamespaces.at(i)))
{
pItem = (AliasEditorTreeWidgetItem *)pItem->child(j);
bFound = true;
break;
}
}
if(!bFound)
return nullptr;
}
return (AliasEditorTreeWidgetItem *)pItem;
}
AliasEditorTreeWidgetItem * AliasEditorWidget::createFullItem(const QString & szFullName)
{
QStringList lNamespaces = szFullName.split("::");
if(!lNamespaces.count())
return nullptr;
if(lNamespaces.count() == 1)
return new AliasEditorTreeWidgetItem(m_pTreeWidget, AliasEditorTreeWidgetItem::Alias, lNamespaces.at(0));
AliasEditorTreeWidgetItem * pItem = findTopLevelItem(lNamespaces.at(0));
if(!pItem)
pItem = new AliasEditorTreeWidgetItem(m_pTreeWidget, AliasEditorTreeWidgetItem::Namespace, lNamespaces.at(0));
bool bFound;
int i;
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 = (AliasEditorTreeWidgetItem *)pItem->child(j);
bFound = true;
break;
}
}
if(!bFound)
pItem = new AliasEditorTreeWidgetItem(pItem, AliasEditorTreeWidgetItem::Namespace, lNamespaces.at(i));
}
return new AliasEditorTreeWidgetItem(pItem, AliasEditorTreeWidgetItem::Alias, lNamespaces.at(i));
}
void AliasEditorWidget::oneTimeSetup()
{
KviPointerHashTable<QString, KviKvsScript> * a = KviKvsAliasManager::instance()->aliasDict();
if(!a)
return;
KviPointerHashTableIterator<QString, KviKvsScript> it(*a);
AliasEditorTreeWidgetItem * item;
while(it.current())
{
KviKvsScript * alias = it.current();
item = createFullItem(alias->name());
item->setBuffer(alias->code());
m_pAliases->append(item);
++it;
}
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 &)));
connect(m_pTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(itemRenamed(QTreeWidgetItem *, int)));
connect(KviKvsAliasManager::instance(), SIGNAL(aliasRefresh(const QString &)), this, SLOT(aliasRefresh(const QString &)));
m_pTreeWidget->sortItems(0, Qt::AscendingOrder);
}
void AliasEditorWidget::aliasRefresh(const QString & szName)
{
if(m_bSaving)
return;
AliasEditorTreeWidgetItem * item = nullptr;
KviKvsScript * alias = KviKvsAliasManager::instance()->aliasDict()->find(szName);
// search for old alias with same name
KviPointerList<AliasEditorTreeWidgetItem> l;
l.setAutoDelete(false);
appendAllItems(&l, AliasEditorTreeWidgetItem::Alias);
for(AliasEditorTreeWidgetItem * it = l.first(); it; it = l.next())
{
if(KviQString::equalCI(buildFullItemName(it), szName))
{
item = it;
break;
}
}
if(!item)
{
item = createFullItem(szName);
m_pAliases->append(item);
}
if(item != m_pLastEditedItem)
{
item->setBuffer(alias->code());
return;
}
if(
QMessageBox::warning(nullptr, __tr2qs_ctx("Confirm Overwriting Current - KVIrc", "editor"),
__tr2qs_ctx("An external script has changed the alias 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(alias->code());
m_pEditor->setText(alias->code());
}
void AliasEditorWidget::itemRenamed(QTreeWidgetItem * it, int col)
{
if(it != m_pLastEditedItem)
return;
((AliasEditorTreeWidgetItem *)it)->setName(it->text(col));
QString szNam = buildFullItemName((AliasEditorTreeWidgetItem *)it);
QString szLabelText;
if(((AliasEditorTreeWidgetItem *)it)->isNamespace())
szLabelText = __tr2qs_ctx("Namespace", "editor");
else
szLabelText = __tr2qs_ctx("Alias", "editor");
szLabelText += ": <b>";
szLabelText += szNam;
szLabelText += "</b>";
m_pNameLabel->setText(szLabelText);
}
bool AliasEditorWidget::hasSelectedItems()
{
return m_pTreeWidget->selectedItems().count() ? true : false;
}
bool AliasEditorWidget::itemExists(QTreeWidgetItem * pSearchFor)
{
if(!pSearchFor)
return false;
if(m_pAliases->findRef((AliasEditorTreeWidgetItem *)pSearchFor) != -1)
return true;
else
return false;
}
void AliasEditorWidget::appendAllItems(KviPointerList<AliasEditorTreeWidgetItem> * l, AliasEditorTreeWidgetItem::Type eType)
{
for(int i = 0; i < m_pTreeWidget->topLevelItemCount(); i++)
{
if(((AliasEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i))->type() == eType)
{
l->append(((AliasEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i)));
}
else
{
appendAllItemsRecursive(l, m_pTreeWidget->topLevelItem(i), eType);
}
}
}
void AliasEditorWidget::appendAllItemsRecursive(KviPointerList<AliasEditorTreeWidgetItem> * l, QTreeWidgetItem * pStartFrom, AliasEditorTreeWidgetItem::Type eType)
{
for(int i = 0; i < pStartFrom->childCount(); i++)
{
if(((AliasEditorTreeWidgetItem *)pStartFrom->child(i))->type() == eType)
{
l->append((AliasEditorTreeWidgetItem *)pStartFrom->child(i));
}
else
{
appendAllItemsRecursive(l, pStartFrom->child(i), eType);
}
}
}
bool AliasEditorWidget::aliasExists(QString & szFullItemName)
{
KviPointerList<AliasEditorTreeWidgetItem> l;
l.setAutoDelete(false);
appendAllItems(&l, AliasEditorTreeWidgetItem::Alias);
for(AliasEditorTreeWidgetItem * it = l.first(); it; it = l.next())
{
if(KviQString::equalCI(buildFullItemName(it), szFullItemName))
{
return true;
}
}
return false;
}
bool AliasEditorWidget::namespaceExists(QString & szFullItemName)
{
KviPointerList<AliasEditorTreeWidgetItem> l;
l.setAutoDelete(false);
appendAllItems(&l, AliasEditorTreeWidgetItem::Namespace);
for(AliasEditorTreeWidgetItem * it = l.first(); it; it = l.next())
{
if(KviQString::equalCI(buildFullItemName(it), szFullItemName))
{
return true;
}
}
return false;
}
void AliasEditorWidget::renameItem()
{
if(!m_pLastEditedItem)
return;
//if(itemExists(m_pLastEditedItem))return; // dead ?
QString szName = buildFullItemName(m_pLastEditedItem);
QString szNewName;
bool bAlias = m_pLastEditedItem->isAlias();
if(bAlias)
szNewName = askForAliasName(__tr2qs_ctx("Enter a New Name - KVIrc", "editor"), __tr2qs_ctx("Please enter the new name for the alias.", "editor"), szName);
else
szNewName = askForNamespaceName(__tr2qs_ctx("Enter a New Name - KVIrc", "editor"), __tr2qs_ctx("Please enter the new name for the namespace.", "editor"), szName);
if(szNewName.isEmpty())
return;
if(szName == szNewName)
return;
// check if there is already an alias with this name
if(bAlias)
{
if(aliasExists(szNewName))
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Name Already Exists - KVIrc", "editor"),
__tr2qs_ctx("This name is already in use. Please choose another one.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
return;
}
}
else
{
// check if there is already a namespace with this name
if(namespaceExists(szNewName))
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Name Already Exists - KVIrc", "editor"),
__tr2qs_ctx("This name is already in use. Please choose another one.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
return;
}
}
QString szCode;
int pntCursor;
if(bAlias)
{
m_pEditor->getText(szCode);
pntCursor = m_pEditor->getCursor();
}
QList<QTreeWidgetItem *> lChildren = m_pLastEditedItem->takeChildren();
bool bYesToAll = true;
removeItem(m_pLastEditedItem, &bYesToAll, true);
m_pLastEditedItem = nullptr; // make sure it's true (but it already should be because of removeItem())
m_pLastClickedItem = nullptr; // make sure it's true (but it already should be because of removeItem())
AliasEditorTreeWidgetItem * pItem = createFullItem(szNewName);
if(bAlias)
{
pItem->setBuffer(szCode);
pItem->setCursorPosition(pntCursor);
}
else
{
for(int i = 0; i < lChildren.count(); i++)
{
((AliasEditorTreeWidgetItem *)lChildren.at(i))->setParentItem(pItem);
pItem->insertChild(pItem->childCount(), lChildren.at(i));
}
}
activateItem(pItem);
m_pAliases->append(pItem);
}
// warning: this saves ONLY the body, not the name!
// the name is changed explicitly with renameItem(), when needed
void AliasEditorWidget::saveLastEditedItem()
{
if(!m_pLastEditedItem)
return;
if(!itemExists(m_pLastEditedItem) || !m_pEditor->isModified() || m_pLastEditedItem->isNamespace())
return;
((AliasEditorTreeWidgetItem *)m_pLastEditedItem)->setCursorPosition(m_pEditor->getCursor());
QString newCode;
m_pEditor->getText(newCode);
((AliasEditorTreeWidgetItem *)m_pLastEditedItem)->setBuffer(newCode);
}
void AliasEditorWidget::currentItemChanged(QTreeWidgetItem * it, QTreeWidgetItem *)
{
saveLastEditedItem();
m_pLastEditedItem = (AliasEditorTreeWidgetItem *)it;
if(!m_pLastEditedItem)
{
m_pNameLabel->setText(__tr2qs_ctx("No item selected", "editor"));
m_pRenameButton->setEnabled(false);
m_pEditor->setText("");
m_pEditor->setEnabled(false);
return;
}
QString szNam = buildFullItemName(m_pLastEditedItem);
if(m_pLastEditedItem->isNamespace())
{
QString szLabelText = __tr2qs_ctx("Namespace", "editor");
szLabelText += ": <b>";
szLabelText += szNam;
szLabelText += "</b>";
m_pNameLabel->setText(szLabelText);
m_pRenameButton->setEnabled(true);
m_pEditor->setText("");
m_pEditor->setEnabled(false);
m_pTreeWidget->setFocus();
return;
}
QString szLabelText = __tr2qs_ctx("Alias", "editor");
szLabelText += ": <b>";
szLabelText += szNam;
szLabelText += "</b>";
m_pNameLabel->setText(szLabelText);
m_pRenameButton->setEnabled(true);
m_pEditor->setText(((AliasEditorTreeWidgetItem *)it)->buffer());
m_pEditor->setFocus();
m_pEditor->setCursorPosition(((AliasEditorTreeWidgetItem *)it)->cursorPosition());
m_pEditor->setEnabled(true);
}
void AliasEditorWidget::customContextMenuRequested(const QPoint pnt)
{
m_pContextPopup->clear();
m_pLastClickedItem = (AliasEditorTreeWidgetItem *)m_pTreeWidget->itemAt(pnt);
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::Alias)),
__tr2qs_ctx("Add Alias", "editor"),
this, SLOT(newAlias()));
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::NameSpace)),
__tr2qs_ctx("Add Namespace", "editor"),
this, SLOT(newNamespace()));
bool bHasItems = m_pTreeWidget->topLevelItemCount();
bool bHasSelected = hasSelectedItems();
m_pContextPopup->addSeparator();
QAction * 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()))
->setEnabled(bHasSelected);
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::Save)),
__tr2qs_ctx("Export Selected into Single Files...", "editor"),
this, SLOT(exportSelectedSepFiles()))
->setEnabled(bHasSelected);
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::Save)),
__tr2qs_ctx("Export All...", "editor"),
this, SLOT(exportAll()))
->setEnabled(bHasItems);
m_pContextPopup->addSeparator();
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::Search)),
__tr2qs_ctx("Find in Aliases...", "editor"),
this, SLOT(slotFind()))
->setEnabled(bHasItems);
m_pContextPopup->addAction(
*(g_pIconManager->getSmallIcon(KviIconManager::NameSpace)),
__tr2qs_ctx("Collapse All Namespaces", "editor"),
this, SLOT(slotCollapseNamespaces()))
->setEnabled(bHasItems);
m_pContextPopup->popup(m_pTreeWidget->mapToGlobal(pnt));
}
void AliasEditorWidget::searchReplace(const QString & szSearch, bool bReplace, const QString & szReplace)
{
for(unsigned int i = 0; i < m_pAliases->count(); i++)
{
AliasEditorTreeWidgetItem * pItem = m_pAliases->at(i);
if(pItem->buffer().indexOf(szSearch, 0, Qt::CaseInsensitive) != -1)
{
pItem->setBackground(0, QColor(255, 0, 0, 128));
if(bReplace)
((QString &)pItem->buffer()).replace(szSearch, szReplace, Qt::CaseInsensitive);
openParentItems(pItem);
}
else
{
pItem->setBackground(0, QColor(255, 255, 255));
}
}
}
void AliasEditorWidget::slotFind()
{
g_pAliasEditorModule->lock();
bool bOk;
QString szSearch = QInputDialog::getText(this,
__tr2qs_ctx("Find in Aliases", "editor"),
__tr2qs_ctx("Please enter the text to be searched for. The matching aliases will be highlighted.", "editor"),
QLineEdit::Normal,
"",
&bOk);
g_pAliasEditorModule->unlock();
if(!bOk)
return;
if(szSearch.isEmpty())
return;
m_pEditor->setFindText(szSearch);
searchReplace(szSearch);
}
void AliasEditorWidget::slotFindWord(const QString & szSearch)
{
m_pEditor->setFindText(szSearch);
}
void AliasEditorWidget::recursiveCollapseNamespaces(AliasEditorTreeWidgetItem * it)
{
if(!it)
return;
for(int i = 0; i < it->childCount(); i++)
{
if(it->child(i)->childCount())
{
it->child(i)->setExpanded(false);
recursiveCollapseNamespaces((AliasEditorTreeWidgetItem *)it->child(i));
}
}
}
void AliasEditorWidget::slotCollapseNamespaces()
{
for(int i = 0; i < m_pTreeWidget->topLevelItemCount(); i++)
{
if(m_pTreeWidget->topLevelItem(i)->childCount())
{
m_pTreeWidget->topLevelItem(i)->setExpanded(false);
recursiveCollapseNamespaces((AliasEditorTreeWidgetItem *)m_pTreeWidget->topLevelItem(i));
}
}
}
void AliasEditorWidget::slotReplaceAll(const QString & szFind, const QString & szReplace)
{
m_pEditor->setFindText(szReplace);
searchReplace(szFind, true, szReplace);
}
void AliasEditorWidget::getExportAliasBuffer(QString & buffer, AliasEditorTreeWidgetItem * it)
{
QString szBuf = it->buffer();
KviCommandFormatter::blockFromBuffer(szBuf);
QString szNam = buildFullItemName(it);
buffer = "alias(";
buffer += szNam;
buffer += ")\n";
buffer += szBuf;
buffer += "\n";
}
void AliasEditorWidget::exportAll()
{
exportAliases(false);
}
void AliasEditorWidget::exportSelectedSepFiles()
{
exportAliases(true, true);
}
void AliasEditorWidget::exportSelected()
{
exportAliases(true);
}
void AliasEditorWidget::exportSelectionInSinglesFiles(KviPointerList<AliasEditorTreeWidgetItem> * l)
{
if(!m_szDir.endsWith(QString(KVI_PATH_SEPARATOR)))
m_szDir += KVI_PATH_SEPARATOR;
if(!l->first())
{
g_pAliasEditorModule->lock();
QMessageBox::warning(this, __tr2qs_ctx("Warning While Exporting - KVIrc", "editor"), __tr2qs_ctx("Must select an entry from the list to export!", "editor"), __tr2qs_ctx("OK", "editor"));
g_pAliasEditorModule->unlock();
return;
}
g_pAliasEditorModule->lock();
if(!KviFileDialog::askForDirectoryName(
m_szDir,
__tr2qs_ctx("Choose a Directory - KVIrc", "editor"),
m_szDir,
QString(),
false,
true,
this))
{
g_pAliasEditorModule->unlock();
return;
}
if(!m_szDir.endsWith(QString(KVI_PATH_SEPARATOR)))
m_szDir += KVI_PATH_SEPARATOR;
bool bReplaceAll = false;
for(AliasEditorTreeWidgetItem * it = l->first(); it; it = l->next())
{
QString tmp;
getExportAliasBuffer(tmp, it);
QString szFileName = buildFullItemName(it);
szFileName += ".kvs";
szFileName.replace("::", "_");
QString szCompletePath = m_szDir + szFileName;
if(KviFileUtils::fileExists(szCompletePath) && !bReplaceAll)
{
QString szMsg;
szMsg = QString(__tr2qs_ctx("The file \"%1\" exists. Do you want to replace it?", "editor")).arg(szFileName);
int ret = QMessageBox::question(this, __tr2qs_ctx("Confirm Replacing File - KVIrc", "editor"), szMsg, __tr2qs_ctx("Yes", "editor"), __tr2qs_ctx("Yes to All", "editor"), __tr2qs_ctx("No", "editor"));
if(ret != 2)
{
KviFileUtils::writeFile(szCompletePath, tmp);
if(ret == 1)
bReplaceAll = true;
}
}
else
{
KviFileUtils::writeFile(szCompletePath, tmp);
}
}
g_pAliasEditorModule->unlock();
}
void AliasEditorWidget::exportAliases(bool bSelectedOnly, bool bSingleFiles)
{
saveLastEditedItem();
KviPointerList<AliasEditorTreeWidgetItem> l;
l.setAutoDelete(false);
if(bSelectedOnly)
appendSelectedAliasItems(&l);
if(bSingleFiles)
{
exportSelectionInSinglesFiles(&l);
return;
}
QString szOut;
int count;
if(bSelectedOnly)
{
count = l.count();
buildAliasesFile(&l, szOut);
}
else
{
count = m_pAliases->count();
buildAliasesFile(m_pAliases, szOut);
}
QString szNameFile;
if(szOut.isEmpty())
{
g_pAliasEditorModule->lock();
QMessageBox::warning(this, __tr2qs_ctx("Warning While Exporting - KVIrc", "editor"), __tr2qs_ctx("The exported file could be empty: cowardly refusing to write it.", "editor"), __tr2qs_ctx("OK", "editor"));
g_pAliasEditorModule->unlock();
return;
}
QString szName = m_szDir;
if(!szName.endsWith(QString(KVI_PATH_SEPARATOR)))
szName += KVI_PATH_SEPARATOR;
QString szFile;
g_pAliasEditorModule->lock();
if(count == 1)
{
QString tmp = buildFullItemName(l.at(0));
szNameFile = tmp.replace("::", "_");
}
else
{
szNameFile = "aliases";
}
szName += szNameFile;
szName += ".kvs";
if(!KviFileDialog::askForSaveFileName(
szFile,
__tr2qs_ctx("Choose a Filename - KVIrc", "editor"),
szName,
KVI_FILTER_SCRIPT,
false,
true,
true,
this))
{
g_pAliasEditorModule->unlock();
return;
}
m_szDir = QFileInfo(szFile).absolutePath();
g_pAliasEditorModule->unlock();
if(!KviFileUtils::writeFile(szFile, szOut))
{
g_pAliasEditorModule->lock();
QMessageBox::warning(this, __tr2qs_ctx("Writing to File Failed - KVIrc", "editor"), __tr2qs_ctx("Unable to write to the aliases file.", "editor"), __tr2qs_ctx("OK", "editor"));
g_pAliasEditorModule->unlock();
}
}
void AliasEditorWidget::buildAliasesFile(KviPointerList<AliasEditorTreeWidgetItem> * l, QString & szBuffer)
{
for(AliasEditorTreeWidgetItem * it = l->first(); it; it = l->next())
{
QString tmp;
getExportAliasBuffer(tmp, it);
szBuffer += tmp;
szBuffer += "\n";
}
}
void AliasEditorWidget::saveProperties(KviConfigurationFile * cfg)
{
cfg->writeEntry("Sizes", m_pSplitter->sizes());
QString szName;
if(m_pLastEditedItem)
szName = buildFullItemName(m_pLastEditedItem);
cfg->writeEntry("LastAlias", szName);
}
void AliasEditorWidget::loadProperties(KviConfigurationFile * cfg)
{
QList<int> def;
def.append(20);
def.append(80);
m_pSplitter->setSizes(cfg->readIntListEntry("Sizes", def));
QString tmp = cfg->readEntry("LastAlias", QString());
AliasEditorTreeWidgetItem * it = findItem(tmp);
activateItem(it);
}
void AliasEditorWidget::appendSelectedAliasItems(KviPointerList<AliasEditorTreeWidgetItem> * l)
{
QList<QTreeWidgetItem *> list = m_pTreeWidget->selectedItems();
for(int i = 0; i < list.count(); i++)
{
if(((AliasEditorTreeWidgetItem *)list.at(i))->isAlias())
{
l->append((AliasEditorTreeWidgetItem *)list.at(i));
}
else
{
appendSelectedAliasItemsRecursive(l, list.at(i));
}
}
}
void AliasEditorWidget::appendSelectedAliasItemsRecursive(KviPointerList<AliasEditorTreeWidgetItem> * l, QTreeWidgetItem * pStartFrom)
{
for(int i = 0; i < pStartFrom->childCount(); i++)
{
if(((AliasEditorTreeWidgetItem *)pStartFrom->child(i))->isAlias())
l->append(((AliasEditorTreeWidgetItem *)pStartFrom->child(i)));
else
appendSelectedAliasItemsRecursive(l, pStartFrom->child(i));
}
}
void AliasEditorWidget::appendSelectedItems(KviPointerList<AliasEditorTreeWidgetItem> * l)
{
QList<QTreeWidgetItem *> list = m_pTreeWidget->selectedItems();
for(int i = 0; i < list.count(); i++)
{
l->append((AliasEditorTreeWidgetItem *)list.at(i));
}
}
void AliasEditorWidget::appendSelectedItemsRecursive(KviPointerList<AliasEditorTreeWidgetItem> * l, QTreeWidgetItem * pStartFrom)
{
for(int i = 0; i < pStartFrom->childCount(); i++)
{
l->append(((AliasEditorTreeWidgetItem *)pStartFrom->child(i)));
if(!((AliasEditorTreeWidgetItem *)pStartFrom->child(i))->isAlias())
appendSelectedAliasItemsRecursive(l, pStartFrom->child(i));
}
}
void AliasEditorWidget::removeItemChildren(AliasEditorTreeWidgetItem * it)
{
while(it->childCount() > 0)
{
AliasEditorTreeWidgetItem * pChild = (AliasEditorTreeWidgetItem *)(it->child(0));
if(pChild->childCount())
removeItemChildren(pChild);
delete pChild;
m_pAliases->removeRef(pChild);
}
}
bool AliasEditorWidget::removeItem(AliasEditorTreeWidgetItem * it, bool * pbYesToAll, bool)
{
if(!it)
return true;
QString szMsg;
QString szName = it->name();
if(!*pbYesToAll)
{
if(it->isAlias())
szMsg = QString(__tr2qs_ctx("Do you really want to remove the alias \"%1\"?", "editor")).arg(szName);
else
{
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 items will be deleted too.", "editor");
}
g_pAliasEditorModule->lock();
int ret = QMessageBox::question(this, __tr2qs_ctx("Confirm Removing Item - KVIrc", "editor"), szMsg, __tr2qs_ctx("Yes", "editor"), __tr2qs_ctx("Yes to All", "editor"), __tr2qs_ctx("No", "editor"));
g_pAliasEditorModule->unlock();
switch(ret)
{
case 0:
// nothing
break;
case 1:
*pbYesToAll = true;
break;
default:
return false;
break;
}
}
if(it == m_pLastEditedItem)
m_pLastEditedItem = nullptr;
if(it == m_pLastClickedItem)
m_pLastClickedItem = nullptr;
if(it->childCount())
removeItemChildren(it);
delete it;
m_pAliases->removeRef(it);
return true;
}
void AliasEditorWidget::removeSelectedItems()
{
KviPointerList<AliasEditorTreeWidgetItem> l;
l.setAutoDelete(false);
appendSelectedItems(&l);
bool bYesToAll = false;
for(AliasEditorTreeWidgetItem * it = l.first(); it; it = l.next())
{
if(!removeItem(it, &bYesToAll, false))
return;
}
}
QString AliasEditorWidget::askForAliasName(const QString & szAction, const QString & szText, const QString & szInitialText)
{
bool bOk = false;
QString szNewName;
while(szNewName.isEmpty())
{
g_pAliasEditorModule->lock();
szNewName = QInputDialog::getText(this,
szAction,
szText,
QLineEdit::Normal,
szInitialText,
&bOk);
g_pAliasEditorModule->unlock();
if(!bOk)
return QString();
if(szNewName.isEmpty())
{
g_pAliasEditorModule->lock();
QMessageBox::warning(this,
__tr2qs_ctx("Invalid or Missing Name - KVIrc", "editor"),
__tr2qs_ctx("You must specify a valid name for the alias.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
continue;
}
// we allow only [\w:]+
QRegExp re("[\\w:]+");
if(!re.exactMatch(szNewName))
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Aliases names can contain only letters, digits, underscores and '::' namespace separators.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
szNewName = "";
continue;
}
// make sure that we have only doubled "::" and not ":" or ":::..."
QString tmp = szNewName;
tmp.replace("::", "@"); // @ is not allowed by the rule above
if(tmp.indexOf(":", Qt::CaseInsensitive) != -1)
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Stray ':' character in alias name: did you mean ...<namespace>::<name>?", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
szNewName = "";
continue;
}
if(tmp.indexOf("@@", Qt::CaseInsensitive) != -1)
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Found an empty namespace in alias name.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
szNewName = "";
continue;
}
}
return szNewName;
}
QString AliasEditorWidget::askForNamespaceName(const QString & szAction, const QString & szText, const QString & szInitialText)
{
bool bOk = false;
QString szNewName;
while(szNewName.isEmpty())
{
g_pAliasEditorModule->lock();
szNewName = QInputDialog::getText(this,
szAction,
szText,
QLineEdit::Normal,
szInitialText,
&bOk);
g_pAliasEditorModule->unlock();
if(!bOk)
return QString();
if(szNewName.isEmpty())
{
g_pAliasEditorModule->lock();
QMessageBox::warning(this,
__tr2qs_ctx("Invalid or Missing Name - KVIrc", "editor"),
__tr2qs_ctx("You must specify a valid name for the namespace.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
continue;
}
// we allow only [\w:]+
QRegExp re("[\\w:]+");
if(!re.exactMatch(szNewName))
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Namespace names can contain only letters, digits, underscores and '::' namespace separators.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
szNewName = "";
continue;
}
// make sure that we have only doubled "::" and not ":" or ":::..."
QString tmp = szNewName;
tmp.replace("::", "@"); // @ is not allowed by the rule above
if(tmp.indexOf(":", Qt::CaseInsensitive) != -1)
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Stray ':' character in namespace name: did you mean... <namespace>::<name>?", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
szNewName = "";
continue;
}
if(tmp.indexOf("@@", Qt::CaseInsensitive) != -1)
{
g_pAliasEditorModule->lock();
QMessageBox::information(this,
__tr2qs_ctx("Invalid Name - KVIrc", "editor"),
__tr2qs_ctx("Found an empty namespace in namespace name.", "editor"),
__tr2qs_ctx("OK, Let me try again...", "editor"));
g_pAliasEditorModule->unlock();
szNewName = "";
continue;
}
}
return szNewName;
}
void AliasEditorWidget::openParentItems(QTreeWidgetItem * it)
{
if(it->parent())
{
it->parent()->setExpanded(true);
openParentItems(it->parent());
}
}
void AliasEditorWidget::activateItem(QTreeWidgetItem * it)
{
if(!it)
return;
openParentItems(it);
m_pTreeWidget->setCurrentItem(it);
}
void AliasEditorWidget::newAlias()
{
QString szNewName = askForAliasName(__tr2qs_ctx("Enter a Filename - KVIrc", "editor"), __tr2qs_ctx("Please enter the new name for the alias.", "editor"), "myfunction");
if(szNewName.isEmpty())
return;
newItem(szNewName, AliasEditorTreeWidgetItem::Alias);
}
void AliasEditorWidget::newNamespace()
{
QString szName = askForNamespaceName(__tr2qs_ctx("Enter a Filename - KVIrc", "editor"), __tr2qs_ctx("Please enter the new name for the namespace.", "editor"), "mynamespace");
if(szName.isEmpty())
return;
newItem(szName, AliasEditorTreeWidgetItem::Namespace);
}
void AliasEditorWidget::newItem(QString & szName, AliasEditorTreeWidgetItem::Type eType)
{
if(m_pLastClickedItem)
if(!itemExists(m_pLastClickedItem))
m_pLastClickedItem = nullptr;
if(m_pLastClickedItem)
buildFullItemPath(m_pLastClickedItem, szName);
int idx = 1;
QString szTmp;
if(findItem(szName))
szName.append("1");
while(findItem(szName))
{
szTmp.setNum(idx);
szName.chop(szTmp.length());
szName.append(szTmp);
idx++;
}
AliasEditorTreeWidgetItem * it;
it = createFullItem(szName);
it->setType(eType);
m_pAliases->append(it);
activateItem(it);
}
void AliasEditorWidget::commit()
{
m_bSaving = true;
saveLastEditedItem();
KviKvsAliasManager::instance()->clear();
for(unsigned int i = 0; i < m_pAliases->count(); i++)
{
//don't save empty aliases or namespace names
if(m_pAliases->at(i)->buffer().isEmpty())
continue;
QString szName = buildFullItemName(m_pAliases->at(i));
KviKvsScript * a = new KviKvsScript(szName, m_pAliases->at(i)->buffer());
KviKvsAliasManager::instance()->add(szName, a);
}
g_pApp->saveAliases();
m_bSaving = false;
}
AliasEditorWindow::AliasEditorWindow()
: KviWindow(KviWindow::ScriptEditor, "aliaseditor", nullptr)
{
g_pAliasEditorWindow = this;
setFixedCaption(__tr2qs_ctx("Alias Editor", "editor"));
QGridLayout * g = new QGridLayout();
m_pEditor = new AliasEditorWidget(this);
g->addWidget(m_pEditor, 0, 0, 1, 4);
QPushButton * btn = new QPushButton(__tr2qs_ctx("&OK", "editor"), this);
connect(btn, SIGNAL(clicked()), this, SLOT(okClicked()));
btn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept)));
g->addWidget(btn, 1, 1);
btn = new QPushButton(__tr2qs_ctx("&Apply", "editor"), this);
connect(btn, SIGNAL(clicked()), this, SLOT(applyClicked()));
btn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Accept)));
g->addWidget(btn, 1, 2);
btn = new QPushButton(__tr2qs_ctx("Cancel", "editor"), this);
connect(btn, SIGNAL(clicked()), this, SLOT(cancelClicked()));
btn->setIcon(*(g_pIconManager->getSmallIcon(KviIconManager::Discard)));
g->addWidget(btn, 1, 3);
g->setRowStretch(0, 1);
g->setColumnStretch(0, 1);
setLayout(g);
}
AliasEditorWindow::~AliasEditorWindow()
{
g_pAliasEditorWindow = nullptr;
}
void AliasEditorWindow::okClicked()
{
m_pEditor->commit();
close();
}
void AliasEditorWindow::applyClicked()
{
m_pEditor->commit();
}
void AliasEditorWindow::cancelClicked()
{
close();
}
QPixmap * AliasEditorWindow::myIconPtr()
{
return g_pIconManager->getSmallIcon(KviIconManager::AliasEditor);
}
void AliasEditorWindow::getConfigGroupName(QString & szName)
{
szName = "aliaseditor";
}
void AliasEditorWindow::saveProperties(KviConfigurationFile * cfg)
{
m_pEditor->saveProperties(cfg);
}
void AliasEditorWindow::loadProperties(KviConfigurationFile * cfg)
{
m_pEditor->loadProperties(cfg);
}