/*************************************************************************** tagattributetree.cpp --------------------- copyright : (C) 2003 by Andras Mantia ***************************************************************************/ /*************************************************************************** * * * 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; version 2 of the License. * * * ***************************************************************************/ //qt includes #include #include #include #include #include #include #include //kde includes #include #include #include #include #include #include #include #include #include #include #include //app includes #include "tagattributetree.h" #include "tagattributeitems.h" #include "qtag.h" #include "node.h" #include "parser.h" #include "quantacommon.h" #include "document.h" #include "quantaview.h" #include "tag.h" #include "wkafkapart.h" #include "kafkacommon.h" #include "undoredo.h" #include "viewmanager.h" EditableTree::EditableTree(TQWidget *parent, const char *name) : KListView(parent, name) { m_editable = true; } EditableTree::~EditableTree() { } void EditableTree::setCurrentItem( TQListViewItem *item) { if ( item && m_editable) { TQListViewItem *it = currentItem(); if ( dynamic_cast(it) ) static_cast(it)->hideEditor(); KListView::setCurrentItem(item); it = currentItem(); if ( dynamic_cast(it) ) static_cast(it)->showEditor(); } } void EditableTree::editorContentChanged() { } void EditableTree::focusInEvent(TQFocusEvent *) { /**TQListViewItem *it = currentItem(); if( dynamic_cast(it)) { static_cast(it)->showEditor(); static_cast(it)->lin->setFocus(); }*/ } void EditableTree::focusOutEvent(TQFocusEvent *) { /**TQListViewItem *it = currentItem(); if( dynamic_cast(it)) { static_cast(it)->hideEditor(); }*/ } DualEditableTree::DualEditableTree(TQWidget *parent, const char *name) : EditableTree(parent, name) { curCol = 0; setFocusPolicy(TQ_ClickFocus); this->installEventFilter(this); connect(this, TQT_SIGNAL(clicked(TQListViewItem *, const TQPoint &, int )), this, TQT_SLOT(itemClicked(TQListViewItem *, const TQPoint &, int ))); } DualEditableTree::~DualEditableTree() { } bool DualEditableTree::eventFilter(TQObject *object, TQEvent *event) { AttributeItem *it = dynamic_cast(currentItem()); AttributeItem *up = 0L, *down = 0L; if(!it) return KListView::eventFilter(object, event); if(currentItem()->itemAbove()) up = dynamic_cast(currentItem()->itemAbove()); if(currentItem()->itemBelow()) down = dynamic_cast(currentItem()->itemBelow()); if(event->type() == TQEvent::KeyPress && m_editable) { TQKeyEvent *keyevent = TQT_TQKEYEVENT(event); switch(keyevent->key()) { case Key_Left: if(curCol == 1 && it->lin->cursorPosition() == 0 ) { it->hideEditor(1); it->showEditor(0); it->lin2->setFocus(); curCol = 0; } break; case Key_Right: if(curCol == 0 && (unsigned)it->lin2->cursorPosition() == it->lin2->text().length()) { it->hideEditor(0); it->showEditor(1); it->lin->setFocus(); curCol = 1; } break; case Key_Up: if(up) { it->hideEditor(curCol); up->showEditor(curCol); } break; case Key_Down: if(down) { it->hideEditor(curCol); down->showEditor(curCol); } break; } } return KListView::eventFilter(object, event);; } void DualEditableTree::resizeEvent(TQResizeEvent *ev) { KListView::resizeEvent(ev); if(!currentItem()) return; AttributeItem *item = dynamic_cast(currentItem()); if(item) { item->hideEditor(curCol); item->showEditor(curCol); } } void DualEditableTree::setCurrentItem(TQListViewItem *item) { if ( item && m_editable) { TQListViewItem *it = currentItem(); if ( dynamic_cast(it) ) { static_cast(it)->hideEditor(0); static_cast(it)->hideEditor(1); } KListView::setCurrentItem(item); it = currentItem(); if ( dynamic_cast(it) ) static_cast(it)->showEditor(curCol); } } void DualEditableTree::editorContentChanged() { emit itemModified(dynamic_cast(currentItem())); } void DualEditableTree::itemClicked(TQListViewItem *item, const TQPoint &, int column) { if(item) { curCol = column; if(item == currentItem()) setCurrentItem(item); } } TagAttributeTree::TagAttributeTree(TQWidget *parent, const char *name) : EditableTree(parent, name) { setRootIsDecorated( true ); setSorting(-1); setFrameStyle( Panel | Sunken ); setLineWidth( 2 ); setFocusPolicy(TQ_ClickFocus); addColumn(i18n("Attribute Name")); addColumn(i18n("Value")); setResizeMode(TQListView::LastColumn); m_node = 0L; m_newNode = 0L; m_parentItem = 0L; rebuildEnabled = true; } TagAttributeTree::~TagAttributeTree() { } void TagAttributeTree::setCurrentNode(Node *node) { if (m_node == node) return; m_node = node; emit newNodeSelected(node); if (!rebuildEnabled) return; clear(); m_parentItem = 0L; //We don't want to be able to edit the text node but it's parent. if (node && node->tag->type == Tag::Text) m_node = node = node->parent; if (!node) return; #ifdef HEAVY_DEBUG kafkaCommon::coutTree(baseNode, 2); KafkaDocument::ref()->coutLinkTree(baseNode, 2); #endif AttributeItem *item = 0L; TopLevelItem *group = 0L; TQString attrName; TQTag *qTag = QuantaCommon::tagFromDTD(node); Node *n = node->parent; while (n) { if (n->tag->type == Tag::XmlTag) { if (!m_parentItem) { group = new TopLevelItem(this, 0L, i18n("Parent tags")); m_parentItem = new ParentItem(this, group); } m_parentItem->addNode(n); } n = n->parent; } if (m_parentItem) m_parentItem->showList(true); if (group) group->setOpen(true); // if (!node->tag->nameSpace.isEmpty()) if(node->tag->type == Tag::XmlTag || node->tag->type == Tag::XmlTagEnd) { TQString nameSpace = node->tag->nameSpace; if (node->tag->type == Tag::XmlTagEnd) nameSpace.remove('/'); group = new TopLevelItem(this, group, i18n("Namespace")); item = new AttributeNameSpaceItem(this, group, i18n("prefix"), nameSpace); group->setOpen(true); } if (qTag) { group = new TopLevelItem(this, group, i18n("Attributes")); TQStringList list; for (int i = 0; i < qTag->attributeCount(); i++) { list += qTag->attributeAt(i)->name; } list.sort(); TQStringList::Iterator it = list.end(); --it; while (it != list.end()) { Attribute *attr = qTag->attribute(*it); if (attr->type == "check") { item = new AttributeBoolItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } else if (attr->type == "url") { item = new AttributeUrlItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } else if (attr->type == "list") { item = new AttributeListItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } else if (attr->type == "color") { item = new AttributeColorItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } else { item = new AttributeItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } item->setRenameEnabled(1, true); if (it != list.begin()) --it; else break; } group->setOpen(true); for (uint i = 0; i < qTag->commonGroups.count(); i++) { group = new TopLevelItem(this, group, i18n(qTag->commonGroups[i].utf8())); AttributeList *groupAttrs = qTag->parentDTD->commonAttrs->find(qTag->commonGroups[i]); for (uint j = 0; j < groupAttrs->count(); j++) { Attribute *attr = groupAttrs->at(j); attrName = attr->name; if (attr->type == "check") { item = new AttributeBoolItem(this, group, attrName, node->tag->attributeValue(attrName)); } else if (attr->type == "url") { item = new AttributeUrlItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } else if (attr->type == "list") { item = new AttributeListItem(this, group, attr->name, node->tag->attributeValue(attr->name), attr); } else if (attr->type == "color") { item = new AttributeColorItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } else if (attr->type == "css-style") { item = new AttributeStyleItem(this, group, attr->name, node->tag->attributeValue(attr->name)); } else { item = new AttributeItem(this, group, attrName, node->tag->attributeValue(attrName)); } item->setRenameEnabled(1, true); } group->setOpen(true); } } connect(this, TQT_SIGNAL(collapsed(TQListViewItem*)), TQT_SLOT(slotCollapsed(TQListViewItem*))); connect(this, TQT_SIGNAL(expanded(TQListViewItem*)), TQT_SLOT(slotExpanded(TQListViewItem*))); } void TagAttributeTree::editorContentChanged() { AttributeItem *item = dynamic_cast(currentItem()); if (m_node && item ) { rebuildEnabled = false; if (dynamic_cast(item)) { TQString nameSpace = item->editorText(); m_node->tag->write()->changeTagNamespace(m_node->tag, nameSpace); } else { if(ViewManager::ref()->activeView()->hadLastFocus() == QuantaView::SourceFocus) { m_node->tag->write()->changeTagAttribute(m_node->tag, item->text(0), item->editorText()); } else { //edit the attribute NodeModifsSet *modifs = new NodeModifsSet(); kafkaCommon::editNodeAttribute(m_node, item->text(0), item->editorText(), modifs); ViewManager::ref()->activeDocument()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); #ifdef HEAVY_DEBUG kafkaCommon::coutTree(baseNode, 2); #endif } } rebuildEnabled = true; } } /**void TagAttributeTree::setCurrentItem( TQListViewItem *item ) { if ( item ) { TQListViewItem *it = currentItem(); if ( dynamic_cast(it) ) static_cast(it)->hideEditor(); KListView::setCurrentItem(item); it = currentItem(); if ( dynamic_cast(it) ) static_cast(it)->showEditor(); } }*/ void TagAttributeTree::slotParentSelected(int index) { if (m_parentItem) { m_newNode = m_parentItem->node(index); TQTimer::singleShot(0, this, TQT_SLOT(slotDelayedSetCurrentNode())); } } void TagAttributeTree::slotCollapsed(TQListViewItem *item) { if (m_parentItem && item == m_parentItem->parent()) m_parentItem->showList(false); } void TagAttributeTree::slotExpanded(TQListViewItem *item) { if (m_parentItem && item == m_parentItem->parent()) m_parentItem->showList(true); } void TagAttributeTree::slotDelayedSetCurrentNode() { setCurrentNode(m_newNode); if (ViewManager::ref()->activeDocument()) { if (ViewManager::ref()->activeView()->hadLastFocus() == QuantaView::SourceFocus) ViewManager::ref()->activeDocument()->view()->setFocus(); else KafkaDocument::ref()->getKafkaWidget()->view()->setFocus(); } } EnhancedTagAttributeTree::EnhancedTagAttributeTree(TQWidget *parent, const char *name) : TQWidget(parent, name) { widgetLayout = new TQGridLayout( this, 1, 1, 11, 6, "MainLayout"); attrTree = new TagAttributeTree(this, "TagAttributeTree"); attrTree->setSizePolicy(TQSizePolicy::Minimum, TQSizePolicy::MinimumExpanding); widgetLayout->addMultiCellWidget( attrTree, 1, 1, 0, 3 ); nodeName = new TQLabel(this, i18n( "Node Name" ).ascii()); nodeName->setSizePolicy( TQSizePolicy( TQSizePolicy::MinimumExpanding, TQSizePolicy::Fixed, 0, 0, nodeName->sizePolicy().hasHeightForWidth() ) ); widgetLayout->addWidget( nodeName, 0, 0 ); deleteTag = new KPushButton(this, i18n( "Delete Tag" ).ascii()); deleteTag->setPixmap(SmallIcon("editdelete")); deleteTag->setMaximumHeight(32); deleteTag->setMaximumWidth(32); TQToolTip::add(deleteTag, i18n("Delete the current tag only.")); deleteAll = new KPushButton(this, i18n( "Delete All" ).ascii()); deleteAll->setPixmap(SmallIcon("editdelete")); deleteAll->setMaximumHeight(32); deleteAll->setMaximumWidth(32); TQToolTip::add(deleteAll, i18n("Delete the current tag and all its tqchildren.")); widgetLayout->addWidget( deleteTag, 0, 2 ); widgetLayout->addWidget( deleteAll, 0, 3 ); clearWState( WState_Polished ); connect(attrTree, TQT_SIGNAL(newNodeSelected(Node *)), this, TQT_SLOT(NodeSelected(Node *))); connect(deleteTag, TQT_SIGNAL(clicked()), this, TQT_SLOT(deleteNode())); connect(deleteAll, TQT_SIGNAL(clicked()), this, TQT_SLOT(deleteSubTree())); } EnhancedTagAttributeTree::~EnhancedTagAttributeTree() { } void EnhancedTagAttributeTree::setCurrentNode(Node *node) { curNode = node; attrTree->setCurrentNode(node); showCaption(); } void EnhancedTagAttributeTree::NodeSelected(Node *node) { curNode = node; //We don't want to be able to edit the text node but it's parent. if (node && node->tag->type == Tag::Text) curNode = node = node->parent; showCaption(); emit newNodeSelected(node); } void EnhancedTagAttributeTree::showCaption() { if(curNode) { if(curNode->tag->type == Tag::XmlTag || curNode->tag->type == Tag::XmlTagEnd || curNode->tag->type == Tag::ScriptTag) { TQString s = i18n("Current tag: %1").tqarg(curNode->tag->name); nodeName->setText(KStringHandler::rPixelSqueeze(s, nodeName->fontMetrics(), attrTree->width()- 50)); } else if(curNode->tag->type == Tag::Text) nodeName->setText(i18n("Current tag: text")); else if(curNode->tag->type == Tag::Comment) nodeName->setText(i18n("Current tag: comment")); else nodeName->setText(i18n("Current tag:")); } } void EnhancedTagAttributeTree::deleteSubTree() { QuantaView *view = ViewManager::ref()->activeView(); if(!curNode || !view->document()) return; Node *oldCurNode; NodeModifsSet *modifs; int curLine, curCol; long offset; DOM::Node domNode; TQValueList loc; //Save the cursor position in kafka/quanta if(view->hadLastFocus() == QuantaView::SourceFocus) curNode->tag->beginPos(curLine, curCol); else { KafkaDocument::ref()->getKafkaWidget()->getCurrentNode(domNode, offset); if(!domNode.previousSibling().isNull()) domNode = domNode.previousSibling(); else if(!domNode.parentNode().isNull()) domNode = domNode.parentNode(); else domNode = KafkaDocument::ref()->getKafkaWidget()->document(); if(domNode.nodeType() == DOM::Node::TEXT_NODE) offset = domNode.nodeValue().length(); else offset = 0; loc = kafkaCommon::getLocation(domNode); } //Remove the Nodes oldCurNode = curNode; curNode = 0L; attrTree->setCurrentNode(curNode); modifs = new NodeModifsSet(); kafkaCommon::extractAndDeleteNode(oldCurNode, modifs); view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); //set the cursor position in kafka/quanta if(view->hadLastFocus() == QuantaView::SourceFocus) view->document()->viewCursorIf->setCursorPositionReal((uint)curLine, (uint)curCol); else { domNode = kafkaCommon::getNodeFromLocation(loc, KafkaDocument::ref()->getKafkaWidget()->document()); KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(domNode, offset); } } void EnhancedTagAttributeTree::deleteNode() { QuantaView *view = ViewManager::ref()->activeView(); if(!curNode || !view->document()) return; Node *oldCurNode, *oldCurNodeParent, *child; TQTag *oldCurNodeParentTQTag; int curLine, curCol; long offset; DOM::Node domNode; TQValueList loc; NodeModifsSet *modifs; //Save the cursor position in kafka/quanta if(view->hadLastFocus() == QuantaView::SourceFocus) curNode->tag->beginPos(curLine, curCol); else { KafkaDocument::ref()->getKafkaWidget()->getCurrentNode(domNode, offset); if(!domNode.previousSibling().isNull()) domNode = domNode.previousSibling(); else if(!domNode.parentNode().isNull()) domNode = domNode.parentNode(); else domNode = KafkaDocument::ref()->getKafkaWidget()->document(); if(domNode.nodeType() == DOM::Node::TEXT_NODE) offset = domNode.nodeValue().length(); else offset = 0; loc = kafkaCommon::getLocation(domNode); } //remove the Nodes oldCurNode = curNode; oldCurNodeParent = curNode->parent; curNode = 0L; attrTree->setCurrentNode(curNode); modifs = new NodeModifsSet(); kafkaCommon::extractAndDeleteNode(oldCurNode, modifs, false); //Then we see if the new parent - child relationships are valid, and if not, delete the child and restart if(oldCurNodeParent) { oldCurNodeParentTQTag = QuantaCommon::tagFromDTD(oldCurNodeParent); if(oldCurNodeParentTQTag) { child = oldCurNodeParent->child; while(child) { if(!oldCurNodeParentTQTag->isChild(child)) { kafkaCommon::extractAndDeleteNode(child, modifs, false); //too lazy to get the real next node ;-) child = oldCurNodeParent->child; } else child = child->next; } } } view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); //set the cursor position in kafka/quanta if(view->hadLastFocus() == QuantaView::SourceFocus) view->document()->viewCursorIf->setCursorPositionReal((uint)curLine, (uint)curCol); else { domNode = kafkaCommon::getNodeFromLocation(loc, KafkaDocument::ref()->getKafkaWidget()->document()); KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(domNode, offset); } } #include "tagattributetree.moc"