/*************************************************************************** CTree.cpp - description ------------------- begin : Mon Mar 27 2000 copyright : (C) 2000 by Alexander Theel email : alex.theel@gmx.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. * * * ***************************************************************************/ #include "CTree.h" #include "../icons/delete.xpm" #include "../icons/changeProperty.xpm" #include "../icons/addTreeElement.xpm" #include "../icons/upArrow.xpm" #include "../icons/downArrow.xpm" //#include "../icons/bookmark_add.xpm" #include #include #include #include "../information/xmlpersister.h" #include "../utilities/CIconManager.h" #define getIcon(x) CIconManager::getInstance().getIcon(x) /** * Constructor * 'Editor* editor' is the component to which the text to show will be presented * * setting up the gui and connections */ CTree::CTree( QWidget* pParent, CTuxCardsConfiguration& refTuxConfiguration ) : QListView( pParent ) , mpCollection( NULLPTR ) , mContextMenu( pParent ) , mPropertyDialog( pParent, refTuxConfiguration ) , mSearchDialog( pParent ) , mPressPos() , mbMousePressed( false ) , mAutoOpenTimer( pParent ) , mpOldCurrent( NULLPTR ) , mpDropElement( NULLPTR ) , miAutoOpenTime( 750 ) { // this addColumn(""); setSorting(-1); setRootIsDecorated(true); setAcceptDrops(true); viewport()->setAcceptDrops(true); connect( &mAutoOpenTimer, SIGNAL(timeout()), this, SLOT(timeoutEvent()) ); setVScrollBarMode(AlwaysOn); // Communication connect( this, SIGNAL(selectionChanged(QListViewItem*)), this, SLOT(selectionChanged(QListViewItem*)) ); connect( this, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint&, int)), this, SLOT(rightButtonPressed(QListViewItem*)) ); connect( this, SIGNAL(expanded(QListViewItem*)), this, SLOT(elementOpenedEvent(QListViewItem*)) ); connect( this, SIGNAL(collapsed(QListViewItem*)), this, SLOT(elementClosedEvent(QListViewItem*)) ); connect( this, SIGNAL(itemRenamed(QListViewItem*, int, const QString&)), this, SLOT(inPlaceRenaming(QListViewItem*, int, const QString&)) ); // searchdialog //searchDialog=new SearchDialog(this); connect( &mSearchDialog, SIGNAL(makeVisible(SearchPosition*)), this, SIGNAL(makeVisible(SearchPosition*)) ); // QObject::connect(searchWindow, SIGNAL(makeVisible(CTreeElement*, int, int, int)), // this, SLOT (makeVisible(CTreeElement*, int, int, int)) ); // connect(this, SIGNAL(TreeElementDeleted()), searchWindow, SLOT(close())); settingUpContextMenu(); } CTree::~CTree( void ) { mpCollection = NULLPTR; mpOldCurrent = NULLPTR; mpDropElement= NULLPTR; } void CTree::timeoutEvent( void ) { mAutoOpenTimer.stop(); if ( NULLPTR == mpDropElement ) return; if ( !mpDropElement->isOpen() ) { mpDropElement->setOpen( TRUE ); //mpDropElement->repaint(); } } // ------------------------------------------------------------------------------- void CTree::aboutToRemoveElement( CInformationElement* pIE ) // ------------------------------------------------------------------------------- { if ( (NULLPTR != mpOldCurrent) && (mpOldCurrent->getInformationElement() == pIE) ) mpOldCurrent = NULLPTR; // set to nullptr only if ( (NULLPTR != mpDropElement) && (mpDropElement->getInformationElement() == pIE) ) mpDropElement = NULLPTR; // set to nullptr only } void CTree::setColumnText(QString text){ QListView::setColumnText(0, text); } void CTree::settingUpContextMenu( void ) { QPixmap addIcon(addTreeElement_xpm); QPixmap changePropertyIcon(changeProperty_xpm); QPixmap removeTreeElementIcon(delete_xpm); QPixmap upIcon(upArrow_xpm); QPixmap downIcon(downArrow_xpm); //QPixmap bookmarkAddIcon(bookmark_add_xpm); //context = new QPopupMenu(this); mContextMenu.insertItem( getIcon("addTreeElement"), "Add Entry...", this, SLOT(addElement()) ); mContextMenu.insertItem( getIcon("changeProperty"), "Change Properties...",this, SLOT(changeActiveElementProperties()) ); mContextMenu.insertItem( getIcon("delete"), "Delete Entry", this, SLOT(askForDeletion()) ); mContextMenu.insertSeparator(); mContextMenu.insertItem( getIcon("upArrow"), "Move Entry Upwards", this, SLOT(moveElementUp()) ); mContextMenu.insertItem( getIcon("downArrow"), "Move Entry Downwards",this, SLOT(moveElementDown()) ); //mContextMenu.insertSeparator(); //mContextMenu.insertItem(bookmarkAddIcon, "add Entry to Bookmarks",this, SLOT(addEntryToBookmarks()) ); } // selection has changed either via mouse-click or via keyboard void CTree::selectionChanged( QListViewItem* pItem ) { //cout<<"selection Changed"<(pItem); if ( !pTreeElem ) return; mpCollection->setActiveElement(pTreeElem->getInformationElement()); // // saving currentText to the QListViewItem // getCurrentActive()->setText(editor->getText()); // getCurrentActive()=(CTreeElement*)x; // // editor->setText(getCurrentActive()->getText()); } void CTree::currentChanged( QListViewItem* pItem ){ //cout<<"CTree->currentChanged"<setSelected(pItem, TRUE); } void CTree::rightButtonPressed( QListViewItem* pItem ) { //cout<<"rightMouseButton"<(pItem); if ( !pTreeElem ) return; pTreeElem->getInformationElement()->setOpen(true); } void CTree::elementClosedEvent( QListViewItem* pItem ) { if (NULLPTR == pItem) return; CTreeElement* pTreeElem = dynamic_cast(pItem); if ( !pTreeElem ) return; pTreeElem->getInformationElement()->setOpen(false); } /******************************************************************************/ void CTree::contentsMousePressEvent( QMouseEvent* pE ) { //cout<<"contentsMousePressEvent()"<button()) return; QPoint p( contentsToViewport( pE->pos() ) ); CTreeElement* pItem = dynamic_cast(itemAt(p)); if ( NULLPTR == pItem ) return; // if the user clicked into the root decoration of the item, don't try to start a drag! if ( p.x() > header()->cellPos( header()->mapToActual(0) ) + treeStepSize() * ( pItem->depth() + ( rootIsDecorated() ? 1 : 0) ) + itemMargin() || p.x() < header()->cellPos( header()->mapToActual(0) ) ) { mPressPos = pE->pos(); mbMousePressed = true; } } void CTree::contentsMouseMoveEvent( QMouseEvent* pE ) { if ( (NULLPTR == mpCollection) || (NULLPTR == pE) ) return; if ( mbMousePressed && (mPressPos - pE->pos()).manhattanLength() > QApplication::startDragDistance() ) { //cout<<"contentsMouseMoveEvent()"<toXML(getCurrentActive()), this, "TuxCards InformationCollection" ); pDragObject->setSubtype("xml"); //dragObject->setPixmap(QPixmap(picture_xpm),QPoint(8,8)); pDragObject->drag(); } } } void CTree::contentsMouseReleaseEvent( QMouseEvent* ) { mbMousePressed = false; } /******************************************************************************/ void CTree::contentsDragEnterEvent( QDragEnterEvent* pE ) { //cout<<"contentsDragEnterEvent()"<ignore(); return; } mpOldCurrent = dynamic_cast( currentItem() ); CTreeElement* pElement = dynamic_cast(itemAt(contentsToViewport(pE->pos()))); if ( NULLPTR != pElement ) { mpDropElement = pElement; mAutoOpenTimer.start(miAutoOpenTime); } } void CTree::contentsDragMoveEvent( QDragMoveEvent* pE ) { //cout<<"contentsDragMoveEvent()"<ignore(); return; } QPoint vp = contentsToViewport( pE->pos() ); CTreeElement* pElement = dynamic_cast( itemAt(vp) ); if ( NULLPTR != pElement ){ setSelected(pElement, TRUE); pE->accept(); if ( pElement != mpDropElement ){ mAutoOpenTimer.stop(); mpDropElement = pElement; mAutoOpenTimer.start(miAutoOpenTime); } switch ( pE->action() ) { case QDropEvent::Copy: break; case QDropEvent::Move: pE->acceptAction(); emit showMessage("Move to '"+ (pElement->text(0))+"'", 1); break; case QDropEvent::Link: pE->acceptAction(); break; default: ; } }else{ pE->ignore(); mAutoOpenTimer.stop(); mpDropElement = NULLPTR; emit showMessage("", 1); } } void CTree::contentsDragLeaveEvent( QDragLeaveEvent* ) { //cout<<"contentsDragLeaveEvent()"<ignore(); return; } CTreeElement* pItem = dynamic_cast( itemAt(contentsToViewport(pE->pos())) ); if ( NULLPTR == pItem ) { pE->ignore(); return; } QString collectionString; QTextDrag::decode(pE, collectionString); switch (pE->action()) { case QDropEvent::Copy: break; case QDropEvent::Move: pE->acceptAction(); break; case QDropEvent::Link: pE->acceptAction(); break; default: ; } pE->accept(); //std::cout<<"CTree::contentsDropEvent; format="<format()<format()); if ( format.startsWith("text/plain") ) { QString data(pE->encodedData("text/plain")); pItem->getInformationElement()->appendInformation(data); return; } //std::cout<<"dropped format = "<getInformationElement()->addCollection(XMLPersister::createInformationCollection(collectionString)); CInformationCollection* pCollection = XMLPersister::createInformationCollection(collectionString); if ( NULLPTR != pCollection ) { CInformationElement* pRoot = pCollection->getRootElement(); if ( NULLPTR != pRoot ) { pItem->getInformationElement()->addChild( dynamic_cast(pRoot) ); } } //((CTreeInformationElement*)getCurrentActive())->setOpen(TRUE); //setSelected(x, TRUE); // remove this->deleteElement(mpOldCurrent); } /******************************************************************************/ CInformationElement* CTree::getCurrentActive( void ) { if ( NULLPTR == mpCollection ) return NULLPTR; return mpCollection->getActiveElement(); } /** * wrapper for 'clearTree()' */ void CTree::removeAll( void ) { clearTree(); setColumnText(""); } /** * removes all children from rootItem */ void CTree::clearTree( void ) { if ( NULL == childCount() ) return; CTreeElement* pRoot = dynamic_cast( firstChild() ); //selectionChanged(root); if ( NULLPTR == pRoot ) return; CTreeElement* pX = dynamic_cast(pRoot->firstChild()); CTreeElement* pNext = NULLPTR; for ( int i=1; i <= pRoot->childCount(); i++ ) { pNext = dynamic_cast( pX->nextSibling() ); DELETE( pX ); pX = pNext; } DELETE( pRoot ); } void CTree::setDefaultTreeContents( void ) { (void) new QListViewItem(this, "root"); } void CTree::createTreeFromCollection( CInformationCollection& collection ) { // create it //cout<<"CTree:: creating tree from collection"<firstChild(), (CTreeInformationElement*)pCollection->getRootElement()); removeAll(); CTreeInformationElement* pCollectionRootElement = dynamic_cast(collection.getRootElement()); if ( NULLPTR == pCollectionRootElement ) { std::cout<<"CTree::createTreeFromCollection(): NULLPTR == pCollectionRootElement !"< it(*pCollectionRootElement->getChildren()); CTreeInformationElement* pX = NULLPTR; while( (pX = dynamic_cast(it.current())) != NULLPTR ) { ++it; addInformationElementsToTreeItem( *pTreeElement, *pX ); } // add this tree as listener // TODO: disconnect from previous collection // TODO: delete old collection mpCollection = &collection; connect( mpCollection, SIGNAL(activeInformationElementChanged(CInformationElement*)), this, SLOT(activeInformationElementChanged(CInformationElement*)) ); } /** * transforms the informationelement 'element' in a qlistitem and adds * it to 'parent'; same function as above but recursively */ void CTree::addInformationElementsToTreeItem( CTreeElement& parent, CTreeInformationElement& element){ CTreeElement* pTreeElement = new CTreeElement(&parent, element); QPtrListIterator it( *(element.getChildren()) ); CTreeInformationElement* pX = NULLPTR; while( (pX = dynamic_cast(it.current())) != NULLPTR ) { ++it; addInformationElementsToTreeItem( *pTreeElement, *pX ); } } /** * through this slot, the tree will be notified, if the active element * within the structure has changed. */ void CTree::activeInformationElementChanged( CInformationElement* pElement ) { if ( NULLPTR == pElement ) return; Path path(pElement); CTreeElement* pX = getTreeElement(path); // do nothing if path not valid if ( NULLPTR == pX ) return; // do nothing if already active if ( getCurrentActiveTreeElement() == pX ) return; setSelected( pX, true ); ensureItemVisible( pX ); //Path p2(x->getInformationElement()); //std::cout<<"found "<text(0)<text(0) == name ) return dynamic_cast(pX); pX = pX->nextSibling(); } return NULLPTR; } // responde to "context-menu" ------------------------------------------- void CTree::addElement( void ) { mPropertyDialog.setUp( getCurrentActive(), CPropertyDialog::MODE_CREATE_NEW_ELEMENT ); } void CTree::changeActiveElementProperties( void ) { mPropertyDialog.setUp( getCurrentActive(), CPropertyDialog::MODE_CHANGE_PROPERTIES); } /** * This slot is called if an element should be deleted. * The corresponding datamodel is called to delete this element. */ void CTree::askForDeletion( void ) { if ( (NULLPTR == selectedItem()) || (NULLPTR == getCurrentActive()) ) { emit showMessage("Nothing selected.", 5); return; } if (selectedItem() == firstChild()) { QMessageBox::information( this, "Delete the active Entry", "The root entry cannot be deleted.", "Ok" ); return; } if (QMessageBox::warning( this, "Delete the active Entry", "Do you really want to delete '" +getCurrentActive()->getDescription()+"'?", "Yes", "No, sorry.")) { return; } deleteElement( dynamic_cast(selectedItem()) ); } /** * This slot is called if an element should be deleted. * The corresponding datamodel is called to delete this element. */ void CTree::deleteElement( CTreeElement* pElem ) { if ( NULLPTR == pElem ) return; if ( pElem == firstChild() ) return; // this does only work as long as only one view is present at one time setSelected( pElem->itemAbove(), true ); CInformationElement* pIE = pElem->getInformationElement(); if ( NULLPTR != pIE ) pIE->deleteSelf(); else std::cout<<"CTree::deleteElement(): pIE == NULLPTR"<( currentItem() ); Q_CHECK_PTR(retVal); return retVal; } /** * */ void CTree::search( void ) { if (mSearchDialog.setUp( dynamic_cast(firstChild()), getCurrentActiveTreeElement()) == QDialog::Rejected ) { return; } } ///** // * 'x' the CTreeElement to make visible // * 'line', 'pos', 'len' describe the exact place of the String found // * (i.o. to highlight it) // */ //void CTree::makeVisible(CTreeElement* x, int paragraph, int pos, int len){ // // // open all parents // CTreeElement* y=x; // while(y!=firstChild()){ // y=(CTreeElement*)(y->parent()); // setOpen(y, true); // } // setOpen(firstChild(), true); // // // make it visible // setSelected(x, true); // ensureItemVisible(x); // //// editor->setSelection(paragraph,pos, paragraph,pos+len, 0); //// editor->setCursorPosition(paragraph, pos+len); //// editor->ensureCursorVisible(); //} /** * links splitter with tree and resizes the listwidth automatically */ void CTree::resizeEvent( QResizeEvent* pE ) { if ( NULLPTR == pE ) return; setColumnWidth(0, pE->size().width()-22); // evtl. make vScrollBar auto-on triggerUpdate(); } void CTree::addEntryToBookmarks( void ) { emit addEntryToBookmarksSignal(); } // ------------------------------------------------------------------------------- void CTree::keyPressEvent( QKeyEvent* pK ) // ------------------------------------------------------------------------------- { if ( NULLPTR == pK ) return; // If // ALT + left cursor (history one back / previous entry) or // ALT + right cursor (history one forward / next entry) // is called, then ignore it. if( ( (pK->state() == AltButton) && (pK->key() == Key_Left) ) || ( (pK->state() == AltButton) && (pK->key() == Key_Right) ) ) { //std::cout<<" -> ignore"<ignore(); return; } switch( pK->key() ) { case Qt::Key_Insert : //std::cout<<"Within CTree: pressing 'Insert"<(pItem); if ( NULLPTR == pTreeElement ) return; CTreeInformationElement* pIE = pTreeElement->getInformationElement(); if ( NULLPTR == pIE ) return; pIE->setDescription( sText ); } // ------------------------------------------------------------------------------- void CTree::moveElementUp() // ------------------------------------------------------------------------------- { CInformationElement* pIE = getCurrentActive(); CTreeInformationElement* pTreeIE = dynamic_cast(pIE); if (pTreeIE) pTreeIE->moveOneUp(); } // ------------------------------------------------------------------------------- void CTree::moveElementDown() // ------------------------------------------------------------------------------- { CInformationElement* pIE = getCurrentActive(); CTreeInformationElement* pTreeIE = dynamic_cast(pIE); if (pTreeIE) pTreeIE->moveOneDown(); }