/*************************************************************************** htmldocumentproperties.cpp ------------------- copyright : (C) 2003, 2004 - Nicolas Deschildre email : ndeschildre@tdewebdev.org ***************************************************************************/ /*************************************************************************** * * * 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 #include #include #include #include #include #include #include #include #include "node.h" #include "tag.h" #include "qtag.h" #include "resource.h" #include "quanta.h" #include "quantacommon.h" #include "quantaview.h" #include "document.h" #include "tagattributetree.h" #include "qextfileinfo.h" #include "kafkacommon.h" #include "wkafkapart.h" #include "undoredo.h" #include "cursors.h" #include "htmldocumentproperties.h" #include "viewmanager.h" htmlDocumentProperties::htmlDocumentProperties( TQWidget* parent, bool forceInsertionOfBasicNodes, const char* name, bool modal, WFlags fl) : htmlDocumentPropertiesui(parent, name, modal, fl), titleNode( 0L ), htmlNode( 0L ), headNode( 0L ), linkNode( 0L ), bodyNode( 0L), doctypeNode( 0L ), CSSNode ( 0L ), xmlNode( 0L ), titleDirty(false), linkDirty(false) { Node *node; TQString text, nodeName; bool b; int index; KURL url, baseURL; m_forceInsertionOfBasicNodes = forceInsertionOfBasicNodes; //set the "autodefault" property metaItemsAdd->setAutoDefault(false); metaItemsDelete->setAutoDefault(false); cssRulesAdd->setAutoDefault(false); cssRulesEdit->setAutoDefault(false); cssRulesDelete->setAutoDefault(false); cssStylesheet->button()->setAutoDefault(false); cancel->setAutoDefault(false); ok->setAutoDefault(true); //set the taborder and disable focus for some widgets. currentDTD->setFocusPolicy(TQ_NoFocus); TQWidget::setTabOrder(title, metaItems); TQWidget::setTabOrder(metaItems, metaItemsAdd); TQWidget::setTabOrder(metaItemsAdd, metaItemsDelete); TQWidget::setTabOrder(metaItemsDelete, cssRules); TQWidget::setTabOrder(cssRules, cssRulesAdd); TQWidget::setTabOrder(cssRulesAdd, cssRulesEdit); TQWidget::setTabOrder(cssRulesEdit, cssRulesDelete); TQWidget::setTabOrder(cssRulesDelete, cssStylesheet); TQWidget::setTabOrder(cssStylesheet, ok); TQWidget::setTabOrder(ok, cancel); //set the current DTD name currentDTD->setText(ViewManager::ref()->activeDocument()->defaultDTD()->nickName); //set the metaItems DualEditableTree metaItems->addColumn(i18n("Name")); metaItems->addColumn(i18n("Content")); metaItems->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); metaItems->setLineWidth( 2 ); metaItems->setSorting(0, true); //set the cssRules TDEListView //cssRules->setEditable(false); cssRules->addColumn(i18n("Selector")); cssRules->addColumn(i18n("Rule")); cssRules->setFrameStyle( TQFrame::Panel | TQFrame::Sunken ); cssRules->setLineWidth( 2 ); //cssRules->setFocusPolicy(TQ_ClickFocus); cssRules->setSorting(-1); //search for the head, html, title Node if(baseNode) { node = baseNode; while(node) { nodeName = node->tag->name.lower(); if(nodeName == "?xml" || nodeName.contains("xml pi block")) xmlNode = node; if(nodeName == "html") htmlNode = node; if(nodeName == "head") headNode = node; if(nodeName == "body") bodyNode = node; if(nodeName == "!doctype" || nodeName.contains("dtd block")) doctypeNode = node; if(nodeName == "title") titleNode = node; if(nodeName == "link") linkNode = node; if(nodeName == "meta") loadMetaNode(node); if(nodeName == "style") loadCSS(node); node = node->next; } //support for old Node organization if(doctypeNode) { node = doctypeNode->child; while(node) { nodeName = node->tag->name.lower(); if(nodeName == "html") htmlNode = node; if(nodeName == "head") headNode = node; if(nodeName == "body") bodyNode = node; if(nodeName == "title") titleNode = node; if(nodeName == "link") linkNode = node; if(nodeName == "meta") loadMetaNode(node); if(nodeName == "style") loadCSS(node); node = node->next; } } if(htmlNode) { node = htmlNode->child; while(node) { nodeName = node->tag->name.lower(); if(nodeName == "head") headNode = node; if(nodeName == "body") bodyNode = node; if(nodeName == "title") titleNode = node; if(nodeName == "link") linkNode = node; if(nodeName == "meta") loadMetaNode(node); if(nodeName == "style") loadCSS(node); node = node->next; } } if(headNode) { node = headNode->child; while(node) { nodeName = node->tag->name.lower(); if(nodeName == "title") titleNode = node; if(nodeName == "link") linkNode = node; if(nodeName == "meta") loadMetaNode(node); if(nodeName == "style") loadCSS(node); node = node->next; } } } //set the current title if(titleNode) { node = titleNode->child; b = false; while(node) { text += node->tag->tagStr(); node = kafkaCommon::getNextNode(node, b, titleNode); } title->setText(KafkaDocument::ref()->getDecodedText(text)); } //set the link if(linkNode) { index = linkNode->tag->attributeIndex("rel"); if(index != -1) { if(linkNode->tag->attributeValue(index).lower() == "stylesheet") { index = linkNode->tag->attributeIndex("href"); if(index != -1) { cssStylesheet->setMode(KFile::File | KFile::ExistingOnly ); baseURL.setPath(ViewManager::ref()->activeDocument()->url().directory()); QuantaCommon::setUrl(url, linkNode->tag->attributeValue(index)); url = QExtFileInfo::toAbsolute(url, baseURL); cssStylesheet->setURL(url.url()); } } } } ok->setIconSet(SmallIconSet("button_ok")); cancel->setIconSet(SmallIconSet("button_cancel")); //connect buttons connect(ok, TQT_SIGNAL(clicked()), this, TQT_SLOT(accept())); connect(cancel, TQT_SIGNAL(clicked()), this, TQT_SLOT(reject())); connect(cssRulesAdd, TQT_SIGNAL(clicked()), this, TQT_SLOT(newCSSRule())); connect(cssRulesEdit, TQT_SIGNAL(clicked()), this, TQT_SLOT(editCSSRule())); connect (cssRulesDelete, TQT_SIGNAL(clicked()), this, TQT_SLOT(deleteCurrentCSSRule())); connect(metaItemsAdd, TQT_SIGNAL(clicked()), this, TQT_SLOT(newMetaItem())); connect(metaItemsDelete, TQT_SIGNAL(clicked()), this, TQT_SLOT(deleteCurrentMetaItem())); connect(title, TQT_SIGNAL(textChanged(const TQString &)), this, TQT_SLOT(titleChanged(const TQString &))); connect(metaItems, TQT_SIGNAL(itemModified( TQListViewItem * )), this, TQT_SLOT(metaChanged(TQListViewItem * ))); connect(cssRules, TQT_SIGNAL(itemModified( TQListViewItem * )), this, TQT_SLOT(CSSChanged(TQListViewItem * ))); connect(cssStylesheet, TQT_SIGNAL(textChanged(const TQString &)), this, TQT_SLOT(linkChanged( const TQString& ))); } htmlDocumentProperties::~htmlDocumentProperties() { } void htmlDocumentProperties::loadMetaNode(Node *node) { int index; TQString name, content; NodeLinkedViewItem *item; index = node->tag->attributeIndex("name"); if(index != -1) name = node->tag->attributeValue(index); index = node->tag->attributeIndex("http-equiv"); if(index != -1) name = node->tag->attributeValue(index); index = node->tag->attributeIndex("content"); if(index != -1) content = node->tag->attributeValue(index); item = new NodeLinkedViewItem(metaItems, name, content); item->node = node; metaList.append(item); metaItems->sort(); } void htmlDocumentProperties::loadCSS(Node *node) { NodeLinkedViewItem *item; TQString selector; CSSNode = node; node = node->child; while(node) { if(node->tag->type == Tag::ScriptStructureBegin) { selector = node->tag->tagStr(); selector = selector.left((uint)selector.find("{")).stripWhiteSpace(); if(node->child) item = new NodeLinkedViewItem(cssRules, selector, node->child->tag->tagStr().replace('\n'," ")); else item = new NodeLinkedViewItem(cssRules, selector, ""); item->node = node; item->moveItem(cssRules->lastChild()); CSSList.append(item); } node = node->next; } } void htmlDocumentProperties::newMetaItem() { NodeLinkedViewItem *item; item = new NodeLinkedViewItem(metaItems, "", ""); item->node = 0L; metaList.append(item); if(metaItems->lastItem()) item->moveItem(metaItems->lastItem()); } void htmlDocumentProperties::deleteCurrentMetaItem() { if(metaItems->currentItem()) { TQListViewItem *item = metaItems->currentItem(); (static_cast(item))->deleted = true; (static_cast(item))->dirty = true; (static_cast(item))->hideEditor(0); (static_cast(item))->hideEditor(1); metaItems->takeItem(metaItems->currentItem()); } } void htmlDocumentProperties::newCSSRule() { NodeLinkedViewItem *item; item = new NodeLinkedViewItem(cssRules, "", ""); item->node = 0L; CSSList.append(item); if(cssRules->lastItem()) item->moveItem(cssRules->lastItem()); } void htmlDocumentProperties::editCSSRule() { //Make this using the big CSS dialog, need parsing!! KMessageBox::information(this, i18n("Sorry, VPL does not support this functionality yet.")); } void htmlDocumentProperties::deleteCurrentCSSRule() { if(cssRules->currentItem()) { TQListViewItem *item = cssRules->currentItem(); (static_cast(item))->deleted = true; (static_cast(item))->dirty = true; (static_cast(item))->hideEditor(0); (static_cast(item))->hideEditor(1); cssRules->takeItem(cssRules->currentItem()); } } void htmlDocumentProperties::titleChanged(const TQString &) { titleDirty = true; } void htmlDocumentProperties::metaChanged(TQListViewItem * item) { if(item) (static_cast(item))->dirty = true; } void htmlDocumentProperties::CSSChanged(TQListViewItem * item) { if(item) (static_cast(item))->dirty = true; } void htmlDocumentProperties::linkChanged( const TQString& ) { linkDirty = true; } void htmlDocumentProperties::accept() { Node *node, *nodeNext; NodeLinkedViewItem *item; TagAttr attr; NodeModifsSet *modifs = new NodeModifsSet(); KURL url, baseURL; TQString finalURL; NodeSelection *cursorPos; bool goUp; //TODO:see for !doctype QuantaView *view = ViewManager::ref()->activeView(); //set the TITLE if necessary. if(titleDirty) { if(!titleNode) { addBasicNodes(modifs); //create title titleNode = kafkaCommon::createAndInsertNode("title", "", Tag::XmlTag, view->document(), headNode, 0L, 0L, modifs); } node = titleNode->child; if(node && (node->next || node->tag->type != Tag::Text)) { while(node) { nodeNext = node->next; kafkaCommon::extractAndDeleteNode(node, modifs, true, false); node = nodeNext; } } if(!titleNode->child) { //create text! node = kafkaCommon::createAndInsertNode("", title->text(),Tag::Text, view->document(), titleNode, 0L, 0L, modifs); } else titleNode->child->tag->setStr(KafkaDocument::ref()->getEncodedText(title->text())); } //set the METAs if necessary if(metaItems->currentItem()) (static_cast(metaItems->currentItem()))->dirty = true; item = metaList.first(); while(item) { if((static_cast(item))->dirty) { if((static_cast(item))->deleted) { if((static_cast(item))->node) { //delete the meta kafkaCommon::extractAndDeleteNode( (static_cast(item))->node, modifs); } } else { if(!(static_cast(item))->node) { if(!(static_cast(item))->editorText(0).isEmpty() || !(static_cast(item))->editorText(1).isEmpty()) { addBasicNodes(modifs); //create the meta!! node = kafkaCommon::createAndInsertNode("meta", "",Tag::XmlTag, view->document(), headNode, 0L, 0L, modifs); } else node = 0L; } else node = (static_cast(item))->node; if(node) { if(node->tag->hasAttribute("name")) node->tag->editAttribute("name", (static_cast(item))->editorText(0)); else node->tag->editAttribute("http-equiv", (static_cast(item))->editorText(0)); node->tag->editAttribute("content", (static_cast(item))->editorText(1)); node->tag->setCleanStrBuilt(false); } } } item = metaList.next(); } //set the CSSs rules if necessary if(cssRules->currentItem()) (static_cast(cssRules->currentItem()))->dirty = true; item = CSSList.first(); while(item) { if((static_cast(item))->dirty) { if((static_cast(item))->deleted) { if((static_cast(item))->node) { //Delete the CSS Node node = (static_cast(item))->node; if(node->next && node->next->tag->type == Tag::ScriptStructureEnd) kafkaCommon::extractAndDeleteNode(node->next, modifs); kafkaCommon::extractAndDeleteNode(node, modifs); } } else { if(!(static_cast(item))->node) { if(!(static_cast(item))->editorText(0).isEmpty() || !(static_cast(item))->editorText(1).isEmpty()) { addBasicNodes(modifs); addBasicCssNodes(modifs); //create the CSS Nodes! node = kafkaCommon::createAndInsertNode( (static_cast(item))->editorText(0), (static_cast(item))->editorText(0) + "{", Tag::ScriptStructureBegin, view->document(), CSSNode, 0L, 0L, modifs); (void)kafkaCommon::createAndInsertNode("#text", "",Tag::Text, view->document(), node, 0L, 0L, modifs); nodeNext = kafkaCommon::createAndInsertNode("", "}",Tag::ScriptStructureEnd, view->document(), CSSNode, 0L, 0L, modifs); } else node = 0L; } else node = (static_cast(item))->node; if(node && node->child) { node->tag->name = (static_cast(item))->editorText(0); node->tag->setStr((static_cast(item))->editorText(0) + "{"); node->child->tag->setStr((static_cast(item))->editorText(1)); } } } item = CSSList.next(); } //set the LINK, if necessary if(linkDirty) { if(!linkNode) { //create LINK addBasicNodes(modifs); linkNode = kafkaCommon::createAndInsertNode("link", "",Tag::XmlTag, view->document(), headNode, 0L, 0L, modifs); } //modify it! QuantaCommon::setUrl(url, cssStylesheet->url()); baseURL = view->document()->url(); baseURL.setPath(baseURL.directory()); url = QExtFileInfo::toRelative(url, baseURL); finalURL = url.url(); if (url.protocol() == view->document()->url().protocol()) finalURL.remove(0, url.protocol().length() + 1); if(linkNode->tag->attributeValue("rel").lower() != "stylesheet") linkNode->tag->editAttribute("rel", "stylesheet"); linkNode->tag->editAttribute("href", finalURL); linkNode->tag->setCleanStrBuilt(false); } if(m_forceInsertionOfBasicNodes) addBasicNodes(modifs); //Set the cursor at the beginning of the document. goUp = false; node = kafkaCommon::getNextNode(bodyNode, goUp, bodyNode); while(node && node->tag->type != Tag::Text) node = kafkaCommon::getNextNode(node, goUp, bodyNode); cursorPos = new NodeSelection(); cursorPos->setCursorNode(node?node:bodyNode); cursorPos->setCursorOffset(0); view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif, cursorPos); delete cursorPos; //view->reloadBothViews(); done(0); } void htmlDocumentProperties::reject() { NodeModifsSet *modifs = new NodeModifsSet(); if(m_forceInsertionOfBasicNodes) addBasicNodes(modifs); ViewManager::ref()->activeDocument()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); done(0); } void htmlDocumentProperties::addBasicCssNodes(NodeModifsSet *modifs) { if(CSSNode || !htmlNode || !headNode) return; //TODO:quick hack, modify createAndInsertNode CSSNode = kafkaCommon::createAndInsertNode("style", "", Tag::XmlTag, ViewManager::ref()->activeDocument(), headNode, 0L, 0L, modifs); } void htmlDocumentProperties::addBasicNodes(NodeModifsSet *modifs) { Node *allTheNodes, *lastHeadChild, *lastBodyChild, *lastHtmlChild; Node *n, *nextNode; bool htmlNodeCreated = false, bodyNodeCreated = false; TQTag *qHead, *qBody; TQString tagName; if(headNode) return; QuantaView *view = ViewManager::ref()->activeView(); if(!xmlNode && view->document()->defaultDTD()->name.contains("XHTML", false)) { //if the xml node is not present and the current DTD is a xhtml like, create it. allTheNodes = baseNode; baseNode = 0L; xmlNode = kafkaCommon::createXmlDeclarationNode(view->document(), quantaApp->defaultEncoding()); nextNode = xmlNode->next; xmlNode = kafkaCommon::insertNode(xmlNode, 0L, 0L, modifs); kafkaCommon::insertNode(nextNode, 0L, 0L, modifs); xmlNode->next->next = allTheNodes; } if(!doctypeNode) { //if the !doctype node is not present, create it if(!view->document()->defaultDTD()->name.contains("XHTML", false)) { allTheNodes = baseNode; baseNode = 0L; } else { allTheNodes = xmlNode->next->next; xmlNode->next->next = 0L; } doctypeNode = kafkaCommon::createDoctypeNode(view->document()); nextNode = doctypeNode->next; doctypeNode = kafkaCommon::insertNode(doctypeNode, 0L, 0L, modifs); kafkaCommon::insertNode(nextNode, 0L, 0L, modifs); doctypeNode->next->next = allTheNodes; } if(!htmlNode && !headNode) { //if the HTML node is not present, create it allTheNodes = doctypeNode->next->next; doctypeNode->next->next = 0L; htmlNode = kafkaCommon::createAndInsertNode("html", "", Tag::XmlTag, view->document(), 0L, 0L, 0L, modifs); //TODO: hardcoded //If it is XML, it add the namespace. if(view->document()->defaultDTD()->name.contains("XHTML", false)) htmlNode->tag->editAttribute("xmlns", "http://www.w3.org/1999/xhtml"); htmlNode->child = allTheNodes; while(allTheNodes) { allTheNodes->parent = htmlNode; allTheNodes = allTheNodes->next; } htmlNodeCreated = true; } //Create the HEAD Node. allTheNodes = htmlNode->child; htmlNode->child = 0L; headNode = kafkaCommon::createAndInsertNode("head", "", Tag::XmlTag, view->document(), htmlNode, 0L, 0L, modifs); if(!bodyNode && htmlNodeCreated) { //let's create BODY to take all the Nodes which can't be in the newly created HTML bodyNode = kafkaCommon::createAndInsertNode("body", "", Tag::XmlTag, view->document(), htmlNode, 0L, 0L, modifs); bodyNodeCreated = true; } //we now move the necessary Nodes to HEAD (and to BODY if htmlNodeCreated) qHead = QuantaCommon::tagFromDTD(view->document()->defaultDTD(), "head"); qBody = QuantaCommon::tagFromDTD(view->document()->defaultDTD(), "body"); lastHeadChild = 0L; lastBodyChild = 0L; lastHtmlChild = htmlNode->child; while(lastHtmlChild && lastHtmlChild->next) lastHtmlChild = lastHtmlChild->next; while(allTheNodes) { n = allTheNodes->next; if(qHead->isChild(allTheNodes)) { /*//TODO:LOG this into the modif!! allTheNodes->parent = headNode; if(lastHeadChild) { lastHeadChild->next = allTheNodes; allTheNodes->prev = lastHeadChild; } else { headNode->child = allTheNodes; } lastHeadChild = allTheNodes;*/ kafkaCommon::moveNode(allTheNodes, headNode, 0L, modifs); } else if(bodyNodeCreated && htmlNodeCreated && qBody->isChild(allTheNodes)) { //TODO:log!! /**allTheNodes->parent = bodyNode; if(lastBodyChild) { lastBodyChild->next = allTheNodes; allTheNodes->prev = lastBodyChild; } else { bodyNode->child = allTheNodes; } lastBodyChild = allTheNodes;*/ kafkaCommon::moveNode(allTheNodes, bodyNode, 0L, modifs); } else { //TODO:log? no. /**allTheNodes->parent = htmlNode; lastHtmlChild->next = allTheNodes; allTheNodes->prev = lastHtmlChild; lastHtmlChild = allTheNodes;*/ kafkaCommon::moveNode(allTheNodes, htmlNode, 0L, modifs); } /**n = allTheNodes->next; if(allTheNodes->next) allTheNodes->next->prev = 0L; allTheNodes->next = 0L; allTheNodes = n;*/ allTheNodes = n; } } NodeLinkedViewItem::NodeLinkedViewItem(EditableTree *listView, const TQString& title, const TQString& title2) : AttributeItem(listView, title, title2, 0L) { node = 0L; dirty = false; deleted = false; } NodeLinkedViewItem::~NodeLinkedViewItem() { } #include "htmldocumentproperties.moc"