File indexing completed on 2024-03-24 15:43:44

0001 //
0002 // C++ Implementation: clist
0003 //
0004 // Description: Viewer of the object model.
0005 //
0006 /*
0007 Copyright 2008-2011 Tomas Mecir <kmuddy@kmuddy.com>
0008 
0009 This program is free software; you can redistribute it and/or
0010 modify it under the terms of the GNU General Public License as
0011 published by the Free Software Foundation; either version 2 of 
0012 the License, or (at your option) any later version.
0013 
0014 This program is distributed in the hope that it will be useful,
0015 but WITHOUT ANY WARRANTY; without even the implied warranty of
0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017 GNU General Public License for more details.
0018 
0019 You should have received a copy of the GNU General Public License
0020 along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include "clistviewer.h"
0024 
0025 #include "clist.h"
0026 #include "clistmanager.h"
0027 #include "clistgroup.h"
0028 #include <KActionCollection>
0029 #include <KLocalizedString>
0030 #include <kmessagebox.h>
0031 
0032 #include <QAction>
0033 #include <QContextMenuEvent>
0034 #include <QHeaderView>
0035 #include <QIcon>
0036 #include <QInputDialog>
0037 #include <QMenu>
0038 #include <QStandardItemModel>
0039 #include <QRegExpValidator>
0040 
0041 struct cListViewer::Private {
0042   cList *list;
0043   cListObject *currentItem;
0044   QStandardItemModel *emptyModel;
0045   QMenu *objectMenu, *groupMenu, *outsideMenu;
0046   QRegExpValidator *validator;
0047   KActionCollection *col;
0048 };
0049 
0050 cListViewer::cListViewer (QWidget *parent)
0051   : QTreeView (parent)
0052 {
0053   d = new Private;
0054   d->currentItem = nullptr;
0055   d->emptyModel = new QStandardItemModel;
0056   setList (nullptr);
0057   header()->hide();  // no header
0058   d->validator = new QRegExpValidator (QRegExp("^[0-9A-Za-z_ ]+$"), this);
0059   d->col = new KActionCollection (this);
0060 
0061   // create the actions and popup menus
0062   QAction *actDeleteObj = new QAction (this);
0063   actDeleteObj->setText (i18n ("Delete object"));
0064   actDeleteObj->setIcon (QIcon::fromTheme ("list-remove"));
0065   connect (actDeleteObj, &QAction::triggered, this, &cListViewer::deleteObject);
0066   d->col->addAction ("DeleteObject", actDeleteObj);
0067   QAction *actDeleteGroup = new QAction (this);
0068   actDeleteGroup->setText (i18n ("Delete group"));
0069   connect (actDeleteGroup, &QAction::triggered, this, &cListViewer::deleteObject);
0070   d->col->addAction ("DeleteGroup", actDeleteGroup);
0071   QAction *actAddSubGroup = new QAction (this);
0072   actAddSubGroup->setText (i18n ("Add subgroup"));
0073   actAddSubGroup->setIcon (QIcon::fromTheme ("folder-new"));
0074   connect (actAddSubGroup, &QAction::triggered, this, &cListViewer::addGroup);
0075   d->col->addAction ("AddSubGroup", actAddSubGroup);
0076   QAction *actAddGroup = new QAction (this);
0077   actAddGroup->setText (i18n ("Add group"));
0078   actAddGroup->setIcon (QIcon::fromTheme ("folder-new"));
0079   connect (actAddGroup, &QAction::triggered, this, &cListViewer::addGroup);
0080   d->col->addAction ("AddGroup", actAddGroup);
0081   QAction *actAddObject = new QAction (this);
0082   actAddObject->setText (i18n ("Add object"));
0083   actAddObject->setIcon (QIcon::fromTheme ("list-add"));
0084   connect (actAddObject, &QAction::triggered, this, &cListViewer::addObject);
0085   d->col->addAction ("AddObject", actAddObject);
0086 
0087   d->outsideMenu = new QMenu (this);
0088   d->outsideMenu->addAction (actAddGroup);
0089   d->outsideMenu->addAction (actAddObject);
0090   d->objectMenu = new QMenu (this);
0091   d->objectMenu->addAction (actDeleteObj);
0092   d->groupMenu = new QMenu (this);
0093   d->groupMenu->addAction (actAddObject);
0094   d->groupMenu->addAction (actAddSubGroup);
0095   d->groupMenu->addAction (actDeleteGroup);
0096 
0097   setSelectionMode (SingleSelection);
0098 
0099   setDragDropMode (InternalMove);
0100   setDragEnabled (true);
0101   setAcceptDrops (true);
0102   setDropIndicatorShown (true);
0103 }
0104 
0105 cListViewer::~cListViewer ()
0106 {
0107   delete d->col;
0108   delete d->validator;
0109   delete d->emptyModel;
0110   delete d;
0111 }
0112 
0113 void cListViewer::setList (cList *l)
0114 {
0115   d->list = l;
0116   d->currentItem = nullptr;
0117   setModel (l ? l->model() : d->emptyModel);
0118 }
0119 
0120 void cListViewer::selectObject (cListObject *obj)
0121 {
0122   QModelIndex index = obj->list()->indexOf (obj);
0123   scrollTo (index);
0124   setCurrentIndex (index);
0125 }
0126 
0127 KActionCollection *cListViewer::actionCollection ()
0128 {
0129   return d->col;
0130 }
0131 
0132 void cListViewer::currentChanged (const QModelIndex &current, const QModelIndex &)
0133 {
0134   if (!d->list) return;
0135   d->currentItem = d->list->objectAt (current);
0136   emit itemActivated (d->currentItem);
0137 }
0138 
0139 void cListViewer::contextMenuEvent (QContextMenuEvent *event)
0140 {
0141   if (!d->list) return;
0142   // we need to figure out which object we clicked on, and display the
0143   // appropriate context menu
0144   QMenu *menu = d->outsideMenu;
0145   QModelIndex index = indexAt (event->pos());
0146   if (index.isValid()) {
0147     d->currentItem = d->list->objectAt (index);
0148     menu = d->currentItem->isGroup() ? d->groupMenu : d->objectMenu;
0149   }
0150   menu->exec (event->globalPos());
0151 }
0152 
0153 void cListViewer::deleteObject () {
0154   if (!d->list) return;
0155   // verify that the object still exists
0156   if (!cListManager::self()->objectId (d->currentItem)) return;
0157   
0158   // ask for confirmation
0159   QString message1;
0160   QString message2;
0161   if (d->currentItem->isGroup()) {
0162     message1 = i18n ("Do you really want to delete this group?");
0163     message2 = i18n ("Delete group");
0164   } else {
0165     message1 = i18n ("Do you really want to delete this %1?", d->list->objName());
0166     message2 = i18n ("Delete %1", d->list->objName());
0167   }
0168   if (KMessageBox::questionTwoActions (this, message1, message2, KGuiItem(i18n("Delete")), KStandardGuiItem::cancel()) != KMessageBox::PrimaryAction) return;
0169 
0170   // verify that the object still exists
0171   if (!cListManager::self()->objectId (d->currentItem)) return;
0172 
0173   // delete the object
0174   if (d->currentItem->isGroup())
0175     d->list->removeGroup ((cListGroup *) d->currentItem);
0176   else
0177     d->list->deleteObject (d->currentItem);
0178 }
0179 
0180 void cListViewer::addGroup () {
0181   if (!d->list) return;
0182   cListObject *obj = d->currentItem;
0183   // nothing selected ? use root
0184   if (!obj) obj = d->list->rootGroup();
0185   // verify that the group still exists
0186   if (!cListManager::self()->objectId (obj)) return;
0187   // selected object not a group ? use its parent
0188   if ((!obj->isGroup())) obj = obj->parentGroup();
0189 
0190   // ask for group name
0191   bool ok = false;
0192   QString name = QInputDialog::getText (this, i18n ("Create Group"), i18n ("Please enter the group name:"), QLineEdit::Normal, QString(), &ok);
0193   if (!ok) return;
0194   int pos = 0;
0195   if (d->validator->validate(name, pos) != QValidator::Acceptable) {
0196     KMessageBox::error (this, i18n ("Cannot create the group, as the provided name is not valid."));
0197     return;
0198   }
0199 
0200   // check if such group exists yet
0201   cListGroup *g = d->list->group (name);
0202   if (g) {
0203     KMessageBox::error (this, i18n ("Cannot create the group, as a group with this name already exists."));
0204     return;
0205   }
0206 
0207   // verify that the group still exists
0208   if (!cListManager::self()->objectId (obj)) return;
0209 
0210   // add a subgroup to the given group
0211   d->list->addGroup ((cListGroup *) obj, name);
0212   // and select it
0213   selectObject (d->list->group (name));
0214 }
0215 
0216 void cListViewer::addObject () {
0217   if (!d->list) return;
0218   cListObject *obj = d->currentItem;
0219   if (!obj) obj = d->list->rootGroup();  // nothing selected ? use root
0220   // verify that the group still exists
0221   if (!cListManager::self()->objectId (obj)) return;
0222   // selected object not a group ? use its parent
0223   if ((!obj->isGroup())) obj = obj->parentGroup();
0224 
0225   // create the object
0226   cListObject *o = d->list->newObject();
0227   d->list->addToGroup ((cListGroup *) obj, o);
0228   // and select it
0229   selectObject (o);
0230 }
0231 
0232 void cListViewer::moveDown ()
0233 {
0234   cListObject *obj = d->currentItem;
0235   if (!obj) return;
0236   obj->parentGroup()->moveObjectDown (obj->positionInGroup());
0237   selectObject (obj);
0238 }
0239 
0240 void cListViewer::moveUp ()
0241 {
0242   cListObject *obj = d->currentItem;
0243   if (!obj) return;
0244   obj->parentGroup()->moveObjectUp (obj->positionInGroup());
0245   selectObject (obj);
0246 }
0247 
0248 void cListViewer::moveLeft ()
0249 {
0250   cListObject *obj = d->currentItem;
0251   if (!obj) return;
0252   // find parent group - it must not be the root group
0253   cListGroup *parent = obj->parentGroup();
0254   if (parent == d->list->rootGroup()) return;
0255 
0256   // move the object to the parent's parent, under the current parent
0257   int pos = parent->positionInGroup ();
0258   cList *list = obj->list();
0259   list->addToGroup (parent->parentGroup(), obj);
0260   parent->parentGroup()->moveObjectToPosition (obj, pos + 1);
0261   selectObject (obj);
0262 }
0263 
0264 void cListViewer::moveRight ()
0265 {
0266   cListObject *obj = d->currentItem;
0267   if (!obj) return;
0268   // the object above us must be a group
0269   // we become the last child of that group
0270   int pos = obj->positionInGroup ();
0271   if (pos == 0) return;
0272   cListObject *g = obj->parentGroup()->objectAt (pos - 1);
0273   if (!g->isGroup()) return;
0274   obj->list()->addToGroup ((cListGroup *) g, obj);
0275 
0276   selectObject (obj);
0277 }
0278 
0279 #include "moc_clistviewer.cpp"