You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kxmleditor/part/kxmleditorpart.cpp

1926 lines
61 KiB

/***************************************************************************
kxmleditorpart.cpp - description
-------------------
begin : Wed Sep 19 2001
copyright : (C) 2001, 2002, 2003 by The KXMLEditor Team
email : OleBowle@gmx.de
***************************************************************************/
/***************************************************************************
* *
* 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 "kxmleditorpart.h"
#include "kxmleditorfactory.h"
#include "kxedocument.h"
#include "kxeconfiguration.h"
#include "kxenewfilesettings.h"
#include "kxearchiveextssettings.h"
#include "kxeprintsettings.h"
#include "kxetextviewsettings.h"
#include "commands_edit.h"
#include "commands_insert.h"
#include "kxe_viewelement.h"
#include "kxe_treeviewitem.h"
#include "kxesearchdialog.h"
#include "kxechoosestringdialog.h"
#include "kxeelementdialog.h"
#include "kxeattributedialog.h"
#include "kxeprocinstrdialog.h"
#include "kxespecprocinstrdialog.h"
#include "kxefilenewdialog.h"
#include "kxechardatadialog.h"
#include "kxeattachdialogbase.h"
#include "kxetexteditordialog.h"
#include "actions.h"
#include "qdom_add.h"
#include <kinstance.h>
#include <kdebug.h>
#include <klocale.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kpopupmenu.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kprinter.h>
#include <ktar.h>
#include <kzip.h>
#include <ktempfile.h>
#include <kconfig.h>
#include <kurlrequester.h>
#include <kcommand.h>
#include <ktoolbar.h>
#include <kfiledialog.h>
#include <qregexp.h>
#include <qtextcodec.h>
#include <qstringlist.h>
#include <qsplitter.h>
#include <qtabwidget.h>
#include <qtextedit.h>
#include <qcombobox.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qclipboard.h>
#include <qdragobject.h>
#include <qapplication.h>
#include <qbuffer.h>
#include <qlabel.h>
#include <qpainter.h>
#include <qpaintdevicemetrics.h>
#include <qevent.h>
#include "dcopiface_part_ro.h" // DCOP Iface
#define CONFIG_MAIN_SPLITTER_SIZES "Main splitter sizes"
KXMLEditorPart::KXMLEditorPart( bool fReadWrite, KXEDocument* pDocument, QWidget * pParent, const char * pszName )
: KParts::ReadWritePart(pParent,pszName),
m_pDlgSearch(0),
m_pDocument(0)
{
//////////////////////////////
// INIT PART
//////////////////////////////
setInstance(KXMLEditorFactory::instance());
if(fReadWrite)
m_pBrowserExt = 0L; // Create Browser extension only for read-only part
else
m_pBrowserExt = new KXMLEditorBrowserExtension( this, "KXMLEditorPart browser extension" );
m_pPrinter = 0L;
m_bAlreadyModified = false;
//////////////////////////////
// CREATE ACTIONS
//////////////////////////////
// file actions
if(fReadWrite)
{
KStdAction::save(this, SLOT(save()), actionCollection());
KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection());
}
// edit actions
m_pActEditFind = KStdAction::find( this, SLOT(slotEditFind()), actionCollection());
m_pActEditFindNext = KStdAction::findNext( this, SLOT(slotEditFindNext()), actionCollection());
m_pActEditDeselect = new KAction( i18n("D&eselect Node"), CTRL+Key_E, this,
SLOT(slotEditDeselect()), actionCollection(), "deselect" );
// view actions
m_pActViewNodeUp = new KAction( i18n("To &Parent Node"), "up", 0, this,
SLOT(slotViewNodeUp()), actionCollection(), "treeitem_up" );
m_pActViewExpNode = new KToolBarPopupAction( i18n("&Expand Node"), "expand_node", CTRL+Key_Plus, this,
SLOT(slotViewExpNode()), actionCollection(), "treeitem_expand" );
KPopupMenu * pMenuExpNode = m_pActViewExpNode->popupMenu();
connect( pMenuExpNode, SIGNAL(activated(int)), this, SLOT(slotViewExpNode(int)) );
for ( uint i = 1; i <= 8; i++ )
pMenuExpNode->insertItem( i18n("Expand To Level %1").arg(i), i-1 );
m_pActViewColNode = new KToolBarPopupAction( i18n("&Collapse Node"), "collapse_node", CTRL+Key_Minus, this,
SLOT(slotViewColNode()), actionCollection(), "treeitem_collapse" );
KPopupMenu * pMenuColNode = m_pActViewColNode->popupMenu();
connect( pMenuColNode, SIGNAL(activated(int)), this, SLOT(slotViewColNode(int)) );
for ( uint i = 0; i <= 7; i++ )
pMenuColNode->insertItem( i18n("Collapse To Level %1").arg(i), i );
// bookmark actions
m_pActBookmarksToggle = new KAction( i18n("&Toggle Bookmark"), "bookmark_add", CTRL+Key_B, this,
SLOT(slotBookmarksToggle()), actionCollection(), "bookmark_toggle" );
m_pActBookmarksPrev = new KAction( i18n("&Previous Bookmark"), "bookmark_prev", SHIFT+Key_F5, this,
SLOT(slotBookmarksPrev()), actionCollection(), "bookmark_prev" );
m_pActBookmarksNext = new KAction( i18n("&Next Bookmark"), "bookmark_next", Key_F5, this,
SLOT(slotBookmarksNext()), actionCollection(), "bookmark_next" );
// settings actions
new KAction( i18n("&Configure KXMLEditor..."), "configure", 0, this,
SLOT (slotConfigure()), actionCollection(), "configure" );
// path toolbar
m_pActPathCombo = new KXmlEditorComboAction( i18n("Path Bar"), 0, this,
SLOT(slotPathSelected(const QString &)), actionCollection(), "path_combo" );
new KAction( i18n("Clear Path Bar"), BarIcon("locationbar_erase", 16), 0, this,
SLOT(slotPathClear()), actionCollection(), "path_clear" );
QLabel *m_locationLabel = new ToolbarLabel( i18n("Path: ") );
new KWidgetAction( m_locationLabel, i18n("Path: "), 0, this, 0, actionCollection(), "path_label" );
m_locationLabel->setBuddy( m_pActPathCombo->comboBox());
if ( ! fReadWrite )
{
setXMLFile( "kxmleditorpartBrowseUI.rc", true );
KStdAction::cut( m_pBrowserExt, SLOT(slotEditCut()), actionCollection(), "cut" );
KStdAction::copy( m_pBrowserExt, SLOT(slotEditCopy()), actionCollection(), "copy" );
KStdAction::paste( m_pBrowserExt, SLOT(slotEditPaste()), actionCollection(), "paste");
m_pCmdHistory = 0L;
m_pActVersionEncoding = 0L;
m_pActAttachSchema = 0L;
m_pActDetachSchema = 0L;
m_pActAttachStylesheet = 0L;
m_pActDetachStylesheet = 0L;
}
else
{
// document specific actions here
m_pActVersionEncoding = new KAction( i18n("&Version && Encoding..."), 0, 0, this, SLOT(slotActVersionEncoding()), actionCollection(), "xml_ins_spec_procins" );
m_pActAttachSchema = new KAction(i18n("Attach Schema..."),0,0,this,SLOT(slotActAttachSchema()), actionCollection(), "xml_attach_schema");
m_pActDetachSchema = new KAction(i18n("Detach Schema"),0,0,this,SLOT(slotActDetachSchema()), actionCollection(), "xml_detach_schema");
m_pActAttachStylesheet = new KAction(i18n("Attach Stylesheet..."),0,0,this,SLOT(slotActAttachStylesheet()), actionCollection(), "xml_attach_stylesheet");
m_pActDetachStylesheet = new KAction(i18n("Detach Stylesheet"),0,0,this,SLOT(slotActDetachStylesheet()), actionCollection(), "xml_detach_stylesheet");
KStdAction::print( this, SLOT(slotActPrint()), actionCollection(), "print" );
m_pActAttachSchema->setEnabled(false);
m_pActDetachSchema->setEnabled(false);
m_pActDetachStylesheet->setEnabled(false);
// undo & redo
KStdAction::undo(this, SLOT(slotActUndo()), actionCollection());
KStdAction::redo(this, SLOT(slotActRedo()), actionCollection());
m_pCmdHistory = new KCommandHistory(actionCollection());
m_pActEditCut = KStdAction::cut( this, SLOT(slotEditCut()), actionCollection());
m_pActEditCopy = KStdAction::copy( this, SLOT(slotEditCopy()), actionCollection());
m_pActEditPaste = KStdAction::paste( this, SLOT(slotEditPaste()), actionCollection());
// Move node Up & Down
m_pActXmlMoveNodeUp = new KAction( i18n("&Move Up"), "xml_move_item_up", CTRL+Key_U, this, SLOT(slotXmlMoveNodeUp()), actionCollection(), "xml_move_item_up" );
m_pActXmlMoveNodeDown = new KAction( i18n("Move &Down"), "xml_move_item_down", CTRL+Key_D, this, SLOT(slotXmlMoveNodeDown()), actionCollection(), "xml_move_item_down" );
// Insert actions
m_pActXmlElementInsert = new KAction( i18n("&Element..."), "xml_insert_element", CTRL+SHIFT+Key_E, this, SLOT(slotXmlElementInsert()), actionCollection(), "xml_ins_element" );
m_pActXmlAttributesAdd = new KAction( i18n("&Attribute..."), "xml_insert_attribute", CTRL+SHIFT+Key_A, this, SLOT(slotXmlAttributesAdd()), actionCollection(), "xml_add_attribute" );
m_pActInsertText = new KAction( i18n("&Text..."), "xml_text", CTRL+SHIFT+Key_T, this, SLOT(slotActInsertText()), actionCollection(), "insert_text" );
m_pActInsertCDATA = new KAction( i18n("C&DATA..."), "xml_cdata", CTRL+SHIFT+Key_D, this, SLOT(slotActInsertCDATA()), actionCollection(), "insert_cdata" );
m_pActInsertComment = new KAction( i18n("&Comment..."), "xml_comment", CTRL+SHIFT+Key_C, this, SLOT(slotActInsertComment()), actionCollection(), "insert_comment" );
m_pActXmlProcInstrInsert = new KAction( i18n("&Processing Instruction..."), "xml_insert_procins", CTRL+SHIFT+Key_P, this, SLOT(slotXmlProcInstrInsert()), actionCollection(), "xml_ins_procins" );
// Edit node properties
m_pActProperties = new KAction(i18n("&Properties..."),"edit",0,this,SLOT(slotActProperties()),actionCollection(),"edit_properties");
m_pActEditRawXml = new KAction(i18n("Edit &raw XML..."), 0, 0, this, SLOT(slotActEditRawXml()),actionCollection(),"edit_as_raw_xml");
// delete actions
m_pActXmlAttributeDel = new KAction( i18n("&Delete"), "editdelete", 0, this, SLOT(slotXmlAttributeDel()), actionCollection(), "xml_del_attribute" );
m_pActXmlAttributesDel = new KAction( i18n("Delete all Attributes..."), 0, 0, this, SLOT(slotXmlAttributesDel()), actionCollection(), "xml_del_attributes" );
m_pActDelete = new KAction(i18n("&Delete"),"editdelete",0,this,SLOT(slotActDelete()),actionCollection(),"edit_delete");
setXMLFile( "kxmleditorpartEditUI.rc", true );
// we are not modified since we haven't done anything yet
setModified(false);
}
//////////////////////////////
// CREATE WIDGETS
//////////////////////////////
pSplitter = new QSplitter( pParent, "KXMLEditorPart main widget (Splitter)" );
pSplitter->setFocusPolicy( QWidget::NoFocus );
pSplitter->setOpaqueResize(true);
setWidget( pSplitter );
// create the tree view -------------------
m_pViewTree = new KXE_TreeView( this, pSplitter, "KXMLEditorPart treeview" );
connect( m_pViewTree, SIGNAL(sigSelectionCleared(bool)), this, SLOT(slotSelectionCleared(bool)) );
connect( m_pViewTree, SIGNAL(sigSelectionChanged(const QDomElement &)), this, SLOT(slotSelectionChanged(const QDomElement &)) );
connect( m_pViewTree, SIGNAL(sigSelectionChanged(const QDomCharacterData &)), this, SLOT(slotSelectionChanged(const QDomCharacterData &)) );
connect( m_pViewTree, SIGNAL(sigSelectionChanged(const QDomProcessingInstruction &)), this, SLOT(slotSelectionChanged(const QDomProcessingInstruction &)) );
connect( m_pViewTree, SIGNAL(sigContextMenuRequested(const QString&,const QPoint&)), this, SLOT(slotContextMenuRequested(const QString&,const QPoint&)) );
connect( m_pViewTree, SIGNAL(itemRenamed(QListViewItem *)), this, SLOT(slotItemRenamedInplace(QListViewItem *)) );
connect( m_pViewTree, SIGNAL(sigKeyPressed(QKeyEvent* )),this,SLOT(slotTreeViewKeyPressed(QKeyEvent*)));
// create tab widget ----------------------
m_pTabWidget = new QTabWidget( pSplitter, "KXMLEditorPart tabwidget");
m_pTabWidget->setFocusPolicy( QWidget::NoFocus );
// create element view
m_pViewElement = new KXE_ViewElement( m_pTabWidget, instance()->config(), "KXMLEditorPart element view" );
m_pTabWidget->addTab( m_pViewElement, g_iconElement, i18n("Element") );
connect( m_pViewElement, SIGNAL(sigContextMenuRequested(const QString&,const QPoint&)), this, SLOT(slotContextMenuRequested(const QString&,const QPoint&)) );
connect( m_pViewElement, SIGNAL(sigAttributeNameChangedInplace(const QDomAttr&, const QString)), this, SLOT(slotAttributeNameChangedInplace(const QDomAttr&, const QString)) );
connect( m_pViewElement, SIGNAL(sigAttributeValueChangedInplace(const QDomAttr&, const QString)), this, SLOT(slotAttributeValueChangedInplace(const QDomAttr&, const QString)) );
// create edit widget, that display XML character data contents
m_pViewContents = new QTextEdit( m_pTabWidget, "KXMLEditorPart contents view" );
m_pTabWidget->addTab( m_pViewContents, g_iconText, i18n("Contents") );
m_pViewContents->setReadOnly( true );
m_pViewContents->setWordWrap( QTextEdit::NoWrap );
m_pViewContents->setTextFormat(QTextEdit::PlainText);
// create proc.instr. view
m_pViewProcInstr = new QTextEdit( m_pTabWidget, "KXMLEditorPart proc.instr. view" );
m_pTabWidget->addTab( m_pViewProcInstr, g_iconProcessingInstruction, i18n("Proc.Instruction") );
m_pViewProcInstr->setReadOnly( true );
m_pViewProcInstr->setWordWrap( QTextEdit::NoWrap );
connect( this, SIGNAL(started(KIO::Job*)), this, SLOT(started()) );
connect( this, SIGNAL(completed()), this, SLOT(completed()) );
connect( this, SIGNAL(canceled(const QString &)), this, SLOT(canceled()) );
//////////////////////////////
// INIT BEGIN STATE
//////////////////////////////
// Disable actions
if(m_pBrowserExt)
m_pBrowserExt->emit enableAction("copy", false);
else
m_pActEditCopy->setEnabled(false);
m_pActEditFindNext->setEnabled(false);
m_pActEditDeselect->setEnabled(false);
m_pActViewNodeUp->setEnabled(false);
m_pActViewExpNode->setEnabled(false);
m_pActViewColNode->setEnabled(false);
m_pActBookmarksToggle->setEnabled(false);
m_pActBookmarksPrev->setEnabled(false);
m_pActBookmarksNext->setEnabled(false);
if ( fReadWrite )
{
m_pActEditCut->setEnabled(false);
m_pActEditPaste->setEnabled(true);
m_pActXmlElementInsert->setEnabled(true);
m_pActXmlAttributesAdd->setEnabled(false);
m_pActXmlAttributesDel->setEnabled(false);
m_pActXmlProcInstrInsert->setEnabled(true);
m_pActInsertText->setEnabled(false);
m_pActInsertCDATA->setEnabled(false);
m_pActInsertComment->setEnabled(false);
m_pActXmlMoveNodeUp->setEnabled(false);
m_pActXmlMoveNodeDown->setEnabled(false);
m_pActDelete->setEnabled(false);
m_pActProperties->setEnabled(false);
m_pActEditRawXml->setEnabled(false);
}
m_pTabWidget->setTabEnabled( m_pViewElement, false );
m_pTabWidget->setTabEnabled( m_pViewContents, false );
m_pTabWidget->setTabEnabled( m_pViewProcInstr, false );
setReadWrite(fReadWrite);
// configuring splitter sizes
QValueList<int> list = instance()->config()->readIntListEntry(CONFIG_MAIN_SPLITTER_SIZES);
if (!list.isEmpty())
pSplitter->setSizes(list);
//////////////////////////////
// INIT DCOP object (if any)
//////////////////////////////
//m_pDCOPIface = NULL;
//m_pDCOPIface = new KXMLEditorPartIfaceReadOnly(this);
m_pDCOPIface = new KXMLEditorPartIfaceReadWrite(this); // temporarly to test openUrl
setDocument(pDocument);
}
KXMLEditorPart::~KXMLEditorPart()
{
// saving splitter configuration
KConfig *pConfig = instance()->config();
pConfig->writeEntry( CONFIG_MAIN_SPLITTER_SIZES, pSplitter->sizes() );
if (m_pDCOPIface)
delete m_pDCOPIface;
if (m_pDlgSearch)
delete m_pDlgSearch;
if (m_pPrinter)
delete m_pPrinter;
if (document())
delete document();
delete m_pCmdHistory;
}
/////////////////////////////////////////////////////////////////////
// KPART FUNCTIONALITY
/////////////////////////////////////////////////////////////////////
bool KXMLEditorPart::openFile()
{
if( isModified() )
kdError() << "KXMLEditorPart::openFile the current document is modified." << endl;
document()->setURL(m_url);
bool bResult = document()->open(m_file);
updateActions();
return bResult;
}
bool KXMLEditorPart::saveFile()
{
emit setStatusBarText( i18n("Saving file...") );
if( url().isEmpty() )
{
return slotFileSaveAs();
}
// delegate this operation to underlying document object
document()->setURL(m_url);
bool bRetVal = document()->save(m_file);
emit setStatusBarText( i18n("Ready.") );
return bRetVal;
}
void KXMLEditorPart::setModified( bool bModified )
{
KParts::ReadWritePart::setModified( bModified ); // base functionality
if ( m_bAlreadyModified != bModified )
{
m_bAlreadyModified = bModified;
QString szNewCaption = m_url.prettyURL();
emit setWindowCaption( szNewCaption );
}
// get a handle on our Save action and make sure it is valid
KAction *pActFileSave = actionCollection()->action(KStdAction::stdName(KStdAction::Save));
if(!pActFileSave)
return;
// if so, we either enable or disable it based on the current state
pActFileSave->setEnabled(bModified);
// Update others actions
updateActions();
}
void KXMLEditorPart::setReadWrite( bool fReadWrite )
{
m_pViewTree->setReadWrite(fReadWrite);
m_pViewElement->setReadWrite(fReadWrite);
KParts::ReadWritePart::setReadWrite( fReadWrite ); // base functionality
}
void KXMLEditorPart::started()
{
kdDebug() << "KXMLEditorPart::started" << endl;
}
void KXMLEditorPart::completed()
{
kdDebug() << "KXMLEditorPart::completed" << endl;
}
void KXMLEditorPart::canceled()
{
kdDebug() << "KXMLEditorPart::canceled" << endl;
}
/////////////////////////////////////////////////////////////////////
// ACTION SLOTS
/////////////////////////////////////////////////////////////////////
void KXMLEditorPart::slotActPrint()
{
// this slot is called whenever the File->Print menu is selected,
// the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
// button is clicked
if (!m_pPrinter)
m_pPrinter = new KPrinter;
if (m_pPrinter->setup(widget()))
print(m_pPrinter);
}
void KXMLEditorPart::slotActProperties()
{
QDomNode* pNode = m_pViewTree->getSelectedNode();
if (pNode)
{
if (pNode->isElement())
slotXmlElementEdit();
else if (pNode->isCharacterData())
slotXmlCharDataEdit();
else if (pNode->isProcessingInstruction())
slotXmlProcInstrEdit();
else
kdError() << "Unknown node selected.";
}
}
void KXMLEditorPart::slotActDelete()
{
QDomNode* pNode = m_pViewTree->getSelectedNode();
if (!m_pViewElement->hasFocus())
{
// delete nodes selected there
if (pNode)
{
KCommand *pCmd = new KXEDeleteNodeCommand(document(), *pNode);
m_pCmdHistory->addCommand(pCmd);
}
}
else
{
// we can have also delete attribute selected on a element view
QDomAttr domAttr = m_pViewElement->getSelectedAttribute();
if (!domAttr.isNull())
{
QDomElement domElement = pNode->toElement();
QDomAttr domAttr = m_pViewElement->getSelectedAttribute();
KCommand *pCmd = new KXEDeleteAttrCommand(document(), domElement, domAttr);
m_pCmdHistory->addCommand(pCmd);
}
}
}
void KXMLEditorPart::slotEditCut()
{
kdDebug() << "KXMLEditor " << k_funcinfo << endl;
if(! isReadWrite())
{
kdError() << "KXMLEditorPart::slotEditCut called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if(pNode)
{ // copy to clipboard
slotEditCopy();
// and cut it
KCommand *pCmd = new KXECutCommand(document(), *pNode);
m_pCmdHistory->addCommand(pCmd);
}
}
void KXMLEditorPart::slotEditCopy()
{
kdDebug() << "KXMLEditor " << k_funcinfo << endl;
QDomNode * pNode = m_pViewTree->getSelectedNode();
if(pNode)
{
QTextDrag *pDrag = copyNode(m_pViewTree->getSelectedNode());
if(pDrag)
QApplication::clipboard()->setData(pDrag);
}
else
kdError() << "KXMLEditorPart::slotEditCopy no element selected." << endl;
}
void KXMLEditorPart::slotEditPaste()
{
kdDebug() << "KXMLEditor " << k_funcinfo << endl;
if(!isReadWrite())
{
kdError() << "KXMLEditorPart::slotEditPaste called in readonly mode." << endl;
return;
}
if (document()->documentElement().isNull())
{
pasteNode(0, QApplication::clipboard()->data());
}
else
{
pasteNode(m_pViewTree->getSelectedNode(), QApplication::clipboard()->data());
}
}
void KXMLEditorPart::slotEditFind()
{
emit setStatusBarText( i18n("Search in XML tree ...") );
if ( ! m_pDlgSearch )
{
m_pDlgSearch = new KXESearchDialog( widget(), "search dialog", true );
}
if ( m_pDlgSearch->exec() == KXESearchDialog::Accepted )
slotEditFindNext();
m_pActEditFindNext->setEnabled(true);
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotEditFindNext()
{
emit setStatusBarText( i18n("Search in XML tree ...") );
if ( ! m_pDlgSearch )
{
kdDebug() << "KXMLEditorPart::slotEditFindNext implementation error - no search dialog" << endl;
emit setStatusBarText( i18n("Ready.") );
return;
}
// get node to start with (either the next node of the item selected at the tree view or documents root node)
QDomNode node = ( (m_pViewTree->getSelectedNode()) && (! m_pViewTree->getSelectedNode()->isNull()) ) ? domTool_nextNode(* m_pViewTree->getSelectedNode()) : document()->documentElement();
// start testing til the last node
while( ! node.isNull() )
{
if ( domTool_match( node, m_pDlgSearch ) )
{
m_pViewTree->selectNode(node);
emit setStatusBarText( i18n("Ready.") );
return;
}
node = domTool_nextNode(node);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlElementInsert()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlElementInsert called in readonly mode." << endl;
return;
}
emit setStatusBarText( i18n("Inserting XML element into document...") );
KXEElementDialog dlg( widget(), "XML element dialog" );
if ( document()->documentElement().isNull() ) // the document doesn't
{ // have a root element yet
if ( dlg.exec( false, true, false ) == QDialog::Accepted )
{
KCommand *pCmd = new KXEElementCommand(document(), document(), dlg.nsURI(), dlg.prefix(), dlg.name());
m_pCmdHistory->addCommand(pCmd);
}
}
else // the document seems to
{ // have a root element
QDomNode * pParentNode = m_pViewTree->getSelectedNode();
if ( (pParentNode) && (pParentNode->isElement()) )
{
QDomElement domParentElement = pParentNode->toElement();
if ( dlg.exec( false, false, false ) == QDialog::Accepted )
{
KCommand *pCmd = new KXEElementCommand(document(), domParentElement, dlg.nsURI(), dlg.prefix(), dlg.name(), dlg.atTop());
m_pCmdHistory->addCommand(pCmd);
}
}
else
kdError() << "KXMLEditorPart::slotXmlElementInsert no element selected." << endl;
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlElementEdit()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlElementEdit called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotXmlElementEdit no node selected or selected node is no XML element." << endl;
return;
}
emit setStatusBarText( i18n("Editing XML element...") );
QDomElement domElement = pNode->toElement();
KXEElementDialog dlg( widget(), "XML element dialog" );
dlg.setPrefix(domElement.prefix());
dlg.setName(domElement.tagName());
if(!domElement.namespaceURI().isNull())
dlg.setNsURI(domElement.namespaceURI() );
if ( dlg.exec( true, false, domElement.namespaceURI().isNull() ) == QDialog::Accepted )
{
KCommand *pCmd = new KXEEditElementCommand(document(), domElement, dlg.prefix(), dlg.name());
m_pCmdHistory->addCommand(pCmd);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotActEditRawXml()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotActEditRawXml called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotActEditRawXml no node selected or selected node is no XML element." << endl;
return;
}
emit setStatusBarText( i18n("Editing raw XML...") );
QDomElement domElement = pNode->toElement();
QString strXML;
QTextStream streamXML(&strXML, IO_WriteOnly);
int iIndent = KXMLEditorFactory::configuration()->textview()->indentSteps();
pNode->save(streamXML, iIndent);
KXETextEditorDialog dlg(0, "Text dialog");
dlg.setEditorText(strXML);
if((dlg.exec() == QDialog::Accepted) && (strXML != dlg.editorText()))
{
QString strXML = "<root>" + dlg.editorText() + "</root>";
// create XML documemt from text
QString strErrorMsg;
int iErrorLine, iErrorColumn;
QDomDocument doc;
if(!doc.setContent(strXML, true, &strErrorMsg, &iErrorLine, &iErrorColumn) )
{
kdDebug() << "KXMLEditorPart::slotActEditRawXml: Failed parsing the file." << endl;
KMessageBox::error(m_pViewTree,
i18n("%1 in line %2, column %3").arg(strErrorMsg).arg(iErrorLine).arg(iErrorColumn),
i18n("Parsing error !"));
return;
}
// check if root item already exists
if(!doc.firstChild().firstChild().isElement())
{
KMessageBox::sorry(m_pViewTree, i18n("You are changed root element to another node type, while editing !"));
return;
}
QDomElement domNewElement = doc.firstChild().firstChild().toElement();
KCommand *pCmd = new KXEEditRawXmlCommand(document(), domElement, domNewElement);
m_pCmdHistory->addCommand(pCmd);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlAttributesAdd()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlAttributesAdd called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotXmlAttributesAdd no node selected or selected node is no XML element." << endl;
return;
}
emit setStatusBarText( i18n("Add attribute...") );
KXEAttributeDialog dlg( widget(), "attribute dialog" );
QDomElement domOwnerElement = pNode->toElement();
if ( dlg.exec( ) == QDialog::Accepted )
{
KCommand *pCmd = new KXEAttributeCommand(document(), domOwnerElement, dlg.attributeNamespace(), dlg.QName(), dlg.Value());
m_pCmdHistory->addCommand(pCmd);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlAttributesDel()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlAttributesDel called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotXmlAttributesDel no node selected or selected node is no XML element." << endl;
return;
}
if(KMessageBox::questionYesNo(0, i18n("Remove all attributes from selected node ?")) != KMessageBox::Yes)
return;
emit setStatusBarText( i18n("Delete all attributes...") );
QDomElement domOwnerElement = pNode->toElement();
KCommand *pCmd = new KXEDeleteAllAttribCommand(document(), domOwnerElement);
m_pCmdHistory->addCommand(pCmd);
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlAttributeDel()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlAttributeDel called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotXmlAttributeDel no node selected or selected node is no XML element." << endl;
return;
}
emit setStatusBarText( i18n("Delete attribute...") );
QDomElement domElement = pNode->toElement();
QDomAttr domAttr = m_pViewElement->getSelectedAttribute();
KCommand *pCmd = new KXEDeleteAttrCommand(document(), domElement, domAttr);
m_pCmdHistory->addCommand(pCmd);
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlProcInstrInsert()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlProcInstrInsert called in readonly mode." << endl;
return;
}
KXEProcInstrDialog dlg( widget(), "proc. instr. dialog" );
QDomNode * pParentNode = m_pViewTree->getSelectedNode();
if ( (pParentNode) && (!pParentNode->isElement()) )
{
kdError() << k_funcinfo << " The selected node is no XML element." << endl;
return;
}
else
{
if ( ! pParentNode ) // no node selected -> the new node should be a direct child of the document
{
if ( dlg.exec( false, true ) == QDialog::Accepted )
{
KCommand *pCmd = new KXEProcInstrCommand(document(), document(), dlg.atTop(), dlg.target(), dlg.data());
m_pCmdHistory->addCommand(pCmd);
}
}
else
{
if ( dlg.exec( false, false ) == QDialog::Accepted )
{
QDomElement domParentElement = pParentNode->toElement();
KCommand *pCmd = new KXEProcInstrCommand(document(), domParentElement, dlg.atTop(), dlg.target(), dlg.data());
m_pCmdHistory->addCommand(pCmd);
}
}
}
emit setStatusBarText( i18n("Inserting processing instruction into document...") );
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlProcInstrEdit()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlProcInstrEdit called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isProcessingInstruction()) )
{
kdError() << "KXMLEditorPart::slotXmlProcInstrEdit no node selected or selected node is no processing instruction." << endl;
return;
}
emit setStatusBarText( i18n("Editing processing instruction...") );
QDomProcessingInstruction domProcInstr = pNode->toProcessingInstruction();
// We have two different kinds of processing instructions:
// - a special one - defining the documents XML version and encoding
// - others
// and both cases require different dialogs.
if( domProcInstr.target() == "xml" ) // 1st case (special proc.instr.)
document()->actVersionEncoding();
else // 2nd case (others)
{
KXEProcInstrDialog dlg( widget(), "proc. instr. dialog" );
dlg.setTarget(domProcInstr.target());
dlg.setData(domProcInstr.data());
if ( dlg.exec( true, false ) == QDialog::Accepted )
{
KCommand *pCmd = new KXEEditProcInstrCommand(document(), domProcInstr, dlg.data());
m_pCmdHistory->addCommand(pCmd);
}
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotActInsertText()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotActInsertText called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotActInsertText no element selected." << endl;
return;
}
emit setStatusBarText( i18n("Inserting text into document...") );
KXECharDataDialog dlg( widget());
dlg.setCaption(i18n("Insert text"));
QDomElement domParentElement = pNode->toElement();
if ( dlg.exec( false ) == QDialog::Accepted )
{
KCommand *pCmd = new KXECharDataCommand(document(), domParentElement, dlg.atTop(), CharDataTextNode, dlg.contents());
m_pCmdHistory->addCommand(pCmd);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotActInsertCDATA()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotActInsertCDATA called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotActInsertCDATA no element selected." << endl;
return;
}
emit setStatusBarText( i18n("Inserting CDATA into document...") );
KXECharDataDialog dlg( widget());
dlg.setCaption(i18n("Insert CDATA"));
QDomElement domParentElement = pNode->toElement();
if ( dlg.exec( false ) == QDialog::Accepted )
{
KCommand *pCmd = new KXECharDataCommand(document(), domParentElement, dlg.atTop(), CharDataCDATASection, dlg.contents());
m_pCmdHistory->addCommand(pCmd);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotActInsertComment()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotActInsertComment called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isElement()) )
{
kdError() << "KXMLEditorPart::slotActInsertComment no element selected." << endl;
return;
}
emit setStatusBarText( i18n("Inserting comment into document...") );
KXECharDataDialog dlg( widget());
dlg.setCaption(i18n("Insert comment"));
QDomElement domParentElement = pNode->toElement();
if ( dlg.exec( false ) == QDialog::Accepted )
{
KCommand *pCmd = new KXECharDataCommand(document(), domParentElement, dlg.atTop(), CharDataComment, dlg.contents());
m_pCmdHistory->addCommand(pCmd);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlCharDataEdit()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlCharDataEdit called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( (!pNode) || (!pNode->isCharacterData()) )
{
kdError() << "KXMLEditorPart::slotXmlCharDataEdit no node selected or selected node is no character data." << endl;
return;
}
emit setStatusBarText( i18n("Editing character data...") );
QDomCharacterData domCharData = pNode->toCharacterData();
KXECharDataDialog dlg( widget() );
CharDataKind eCharDataKind;
if(domCharData.isText())
eCharDataKind = CharDataTextNode;
else
{
if(domCharData.isCDATASection())
eCharDataKind = CharDataCDATASection;
else
eCharDataKind = CharDataComment;
}
// dlg.setCharDataKind(eCharDataKind);
dlg.setContents(domCharData.data());
if ( dlg.exec( true ) == QDialog::Accepted )
{
KCommand *pCmd = new KXEEditCharDataCommand(document(), domCharData, dlg.contents());
m_pCmdHistory->addCommand(pCmd);
}
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlMoveNodeUp()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlMoveNodeUp called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( ! pNode )
{
kdError() << "KXMLEditorPart::slotXmlMoveNodeUp no node selected." << endl;
return;
}
emit setStatusBarText( i18n("Moving node up...") );
KCommand *pCmd = new KXEUpCommand(document(), * pNode);
m_pCmdHistory->addCommand(pCmd);
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotXmlMoveNodeDown()
{
if ( ! isReadWrite() )
{
kdError() << "KXMLEditorPart::slotXmlMoveNodeDown called in readonly mode." << endl;
return;
}
QDomNode * pNode = m_pViewTree->getSelectedNode();
if ( ! pNode )
{
kdError() << "KXMLEditorPart::slotXmlMoveNodeDown no node selected." << endl;
return;
}
emit setStatusBarText( i18n("Moving node down...") );
KCommand *pCmd = new KXEDownCommand(document(), * pNode);
m_pCmdHistory->addCommand(pCmd);
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotBookmarksToggle()
{
m_pViewTree->bookmarksToggle();
m_pActBookmarksPrev->setEnabled(m_pViewTree->containsBookmarkedItems());
m_pActBookmarksNext->setEnabled(m_pViewTree->containsBookmarkedItems());
}
void KXMLEditorPart::slotConfigure()
{
emit setStatusBarText( i18n("Configure KXML Editor ...") );
KXMLEditorFactory::configuration()->showDialog();
emit setStatusBarText( i18n("Ready.") );
}
void KXMLEditorPart::slotPathSelected( )
{
}
void KXMLEditorPart::slotPathSelected( const QString & strPath )
{
QDomNode node = domTool_matchingNode( document()->toDocument(), strPath );
if(node.isNull())
{ // node don't exists, remove item from combo
m_pActPathCombo->removeItem(strPath);
m_pActPathCombo->slotClearEdit();
return;
}
if(!m_pViewTree->selectNode(node))
{ // node not found, remove item from combo
m_pActPathCombo->removeItem(strPath);
m_pActPathCombo->slotClearEdit();
}
}
void KXMLEditorPart::slotPathClear()
{
slotEditDeselect();
m_pActPathCombo->slotFocusEdit();
}
void KXMLEditorPart::slotItemRenamedInplace( QListViewItem * pItem )
{
KXE_TreeViewItem * pXMLItem = static_cast <KXE_TreeViewItem*> (pItem);
if ( ! pXMLItem->xmlNode()->isElement() ) // check, if it really represents an XML element
{
kdFatal() << "KXMLEditorPart " << k_funcinfo << " the given item doesn't represent an XML element." << endl;
return;
}
QDomElement domElement = pXMLItem->xmlNode()->toElement();
if ( domElement.nodeName() != pItem->text(0) ) // if really something was changed
{
// else the element is "namespaced"
int nPosColon = pItem->text(0).find(':');
if ( nPosColon == -1 ) // if no namespace prefix was entered,
{
// check name
QString strMessage = KXEElementDialog::checkName(pItem->text(0));
if(strMessage.length() > 0)
{
// restore old name
m_pViewTree->updateNodeChanged(domElement);
KMessageBox::sorry(m_pViewTree, strMessage);
return;
}
// clear the elements namespace prefix
// and set the entered text as its tag name
KCommand *pCmd = new KXEEditElementCommand(document(), domElement, QString::null, pItem->text(0));
m_pCmdHistory->addCommand(pCmd);
}
else
{
// otherwise split up the entered text by the first colon and
QString strPrefix(pItem->text(0).left(nPosColon));
QString strName(pItem->text(0).right( pItem->text(0).length() - nPosColon - 1 ));
// check name
QString strMessage = KXEElementDialog::checkName(strName);
if(strMessage.length() > 0)
{
// restore old name
m_pViewTree->updateNodeChanged(domElement);
KMessageBox::sorry(m_pViewTree, strMessage);
return;
}
KCommand *pCmd = new KXEEditElementCommand(
document(),
domElement,
strPrefix,
strName
);
m_pCmdHistory->addCommand(pCmd);
}
if ( m_pViewTree->selectedItem() == pItem ) // and if the item is still selected
{
m_pActPathCombo->insertItem( domTool_getIconForNodeType(pXMLItem->xmlNode()->nodeType(), false),
domTool_getPath(*pXMLItem->xmlNode()) ); // the path combo
}
}
}
void KXMLEditorPart::slotAttributeNameChangedInplace( const QDomAttr & domAttr, const QString strNewName )
{
if ( *m_pViewTree->getSelectedNode() == domAttr.ownerElement() ) // if the corresponding element
{ // is still selected
KCommand *pCmd = new KXEEditAttrNameCommand(document(), domAttr, strNewName);
m_pCmdHistory->addCommand(pCmd);
}
}
void KXMLEditorPart::slotAttributeValueChangedInplace( const QDomAttr & domAttr, const QString strNewValue )
{
if ( *m_pViewTree->getSelectedNode() == domAttr.ownerElement() ) // if the corresponding element
{ // is still selected
KCommand *pCmd = new KXEEditAttrValueCommand(document(), domAttr, strNewValue);
m_pCmdHistory->addCommand(pCmd);
}
}
/////////////////////////////////////////////////////////////////////
// MISC FUNCTIONS
/////////////////////////////////////////////////////////////////////
/** Copy XML node into clipboard */
QTextDrag * KXMLEditorPart::copyNode(QDomNode * pNode)
{
QTextDrag *pDrag = 0;
QString strXML;
QTextStream streamXML(&strXML, IO_WriteOnly);
int iIndent = KXMLEditorFactory::configuration()->textview()->indentSteps();
pNode->save(streamXML, iIndent);
pDrag = new QTextDrag(strXML, m_pViewTree);
/*if(pNode->isElement())
pDrag->setSubtype(KXE_TreeViewItem::m_strSubtypeXML);
if(pNode->isProcessingInstruction())
pDrag->setSubtype(KXE_TreeViewItem::m_strSubtypeXML_procins);
if(pNode->isText())
pDrag->setSubtype(KXE_TreeViewItem::m_strSubtypeXML_text);
if(pNode->isCDATASection())
pDrag->setSubtype(KXE_TreeViewItem::m_strSubtypeXML_cdata);
if(pNode->isComment())
pDrag->setSubtype(KXE_TreeViewItem::m_strSubtypeXML_comment); */
return pDrag;
}
//-----------------------------------------------------------------------------
//
// Paste XML node from clipboard into document
//
// pTargetNode - target node
// data - data to pasted
//
//-----------------------------------------------------------------------------
bool KXMLEditorPart::pasteNode(QDomNode * pTargetNode, QMimeSource *data)
{
QString strText;
// Drop XML Processing Instruction
if(QTextDrag::decode(data, strText))
{ if(strText.find("<?xml ") == 0)
{
KMessageBox::sorry(0, i18n("This processing instruction cannot be pasted here !"));
return false;
}
//---
QString strXML = "<root>" + strText + "</root>";
// Paste clipboard contents as XML element
QString strErrorMsg;
int iErrorLine, iErrorColumn;
QDomDocument doc;
if(!doc.setContent(strXML, true, &strErrorMsg, &iErrorLine, &iErrorColumn) )
{ kdDebug() << "KXMLEditorPart::pasteNode: Failed parsing the file." << endl;
KMessageBox::error(m_pViewTree,
i18n("%1 in line %2, column %3").arg(strErrorMsg).arg(iErrorLine).arg(iErrorColumn),
i18n("Parsing error !"));
return false;
}
// Import parsed document to main document
if(doc.hasChildNodes())
{ if(pTargetNode == 0)
{ // check if root item already exists
if(!document()->documentElement().isNull() /*(this->documentElement().isElement())*/ && (doc.firstChild().firstChild().isElement()) )
{ KMessageBox::sorry(m_pViewTree, i18n("Root element already exists !"));
return false;
}
if(doc.documentElement().firstChild().isElement() == false)
{
KMessageBox::sorry(m_pViewTree, i18n("Node pasted to document must be element !"));
return false;
}
// Append it as root node
QDomElement newNode = doc.documentElement().firstChild().cloneNode(true).toElement();
KCommand *pCmd = new KXEPasteToDocumentCommand(document(), document(), newNode);
m_pCmdHistory->addCommand(pCmd);
}
else
{ QDomNode sourceNode = doc.firstChild().firstChild().cloneNode(true);
/*
L.V.
TESTING CODE FOR [ 925668 ] Attribute values in a copied element can't be changed.
if(sourceNode.isElement())
{
QDomElement domSourceElement = sourceNode.toElement();
QDomNamedNodeMap list = domSourceElement.attributes();
unsigned int iLength = list.length();
for ( unsigned int iRow = 0; iRow < iLength; iRow++ )
{
QDomAttr a = list.item(iRow).toAttr();
QDomElement domOwnerElement = a.ownerElement();
if(domOwnerElement.isNull())
KMessageBox::sorry(m_pViewTree, i18n("Cloned owner is null !"));
}*/
//---
if(pTargetNode->isElement())
{
QDomElement domTargetElement = pTargetNode->toElement();
KCommand *pCmd = new KXEPasteToElementCommand(document(), domTargetElement, sourceNode);
m_pCmdHistory->addCommand(pCmd);
return true;
}
if(pTargetNode->isProcessingInstruction() && sourceNode.isProcessingInstruction())
{ // Replace contents of selected node
QDomProcessingInstruction domTargetProcInstr = pTargetNode->toProcessingInstruction();
QDomProcessingInstruction domSourceProcInstr = sourceNode.toProcessingInstruction();
KCommand *pCmd = new KXEPasteToProcInstrCommand(document(), domTargetProcInstr, domSourceProcInstr);
m_pCmdHistory->addCommand(pCmd);
return true;
}
if(pTargetNode->isCharacterData() && sourceNode.isCharacterData())
{ // Replace contents of selected node
QDomCharacterData domTargetCharData = pTargetNode->toCharacterData();
QDomCharacterData domSourceCharData = sourceNode.toCharacterData();
KCommand *pCmd = new KXEPasteToCharDataCommand(document(), domTargetCharData, domSourceCharData);
m_pCmdHistory->addCommand(pCmd);
return true;
}
KMessageBox::sorry(m_pViewTree, i18n("Incompactible node types for drag&drop !"));
return false;
}
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
//
// Drag & Drop MOVE operation
//
// domTrgetElement - target element
// domSourceNode - source node
//
//-----------------------------------------------------------------------------
bool KXMLEditorPart::dropMoveNode(QDomElement & domTargetElement, QDomNode & domSourceNode)
{
KCommand *pCmd = new KXEDragDropMoveCommand(document(), domTargetElement, domSourceNode);
m_pCmdHistory->addCommand(pCmd);
return true;
}
/////////////////////////////////////////////////////////////////////
// PRINTING
/////////////////////////////////////////////////////////////////////
// these defines should rather stay fixed and not configurable by the user.
#define headerMargin 30;
#define footerMargin 50;
#define m_printLinespace 0.4 // percent of font size used to make line indent
int headerHeight, footerHeight; // used in few functions, nevertheless temporary...
void KXMLEditorPart::print(KPrinter* pPrinter)
{
// setup the printer. with Qt, you always "print" to a
// QPainter.. whether the output medium is a pixmap, a screen, or paper
QPainter p;
QPainter *painter = &p;
QFont font( KXMLEditorFactory::configuration()->print()->fontFamily(),
KXMLEditorFactory::configuration()->print()->fontSize() );
QPaintDeviceMetrics metrics((QPrinter*)pPrinter); // determining
int width = metrics.width(); // width and
int height = metrics.height(); // height of the page
footerHeight = font.pointSize()+footerMargin;
headerHeight = font.pointSize()+headerMargin;
int pageNumber = 0;
painter->begin(pPrinter); // start print job
painter->setFont(font); // set up fonts for printout
printHeader(painter,pageNumber,0,width); // draw header on a first page
while (printPage (painter,pageNumber,
headerHeight,width,
height-headerHeight-footerHeight)) // and start printing loop
{
printFooter(painter, pageNumber, height-footerHeight,width); // draw footer at the end of that page
pageNumber++;
pPrinter->newPage();
printHeader(painter,pageNumber,0,width); // draw header on new page
}
printFooter(painter,pageNumber,height-footerHeight,width); // draw footer on last page
painter->end(); // finish print job
}
void KXMLEditorPart::printHeader(QPainter* painter,int pageNumber, int ypos, int width)
{
pageNumber = pageNumber;
if ( KXMLEditorFactory::configuration()->print()->hasHeader() )
{
painter->drawText(0,ypos,m_url.prettyURL());
painter->drawLine(0,ypos,width,ypos);
}
}
bool KXMLEditorPart::printPage(QPainter* painter,int pageNumber, int top, int width, int height)
{
width = width;
if (pageNumber==0)
{
// initialization of working variables is done when
// first page is about to be printed
m_printLineNumber = 0;
m_printLines = QStringList::split( "\n", document()->toString(KXMLEditorFactory::configuration()->print()->indentSteps()) );
}
int lineHeight = (int)(painter->font().pointSize()*(1+m_printLinespace));
int y = top;
while ( y <= height )
{
painter->drawText(0,y,m_printLines[m_printLineNumber]);
if (m_printLineNumber++==m_printLines.size())
return false; // no more pages to print
y += lineHeight;
}
return true; // there are still some pages to print
}
void KXMLEditorPart::printFooter(QPainter* painter,int pageNumber, int ypos, int width)
{
if ( KXMLEditorFactory::configuration()->print()->hasFooter() )
{
int fh = painter->font().pointSize();
painter->drawText(0,ypos,i18n("Page %1").arg(pageNumber+1));
painter->drawLine(0,ypos-fh,width,ypos-fh);
}
}
/////////////////////////////////////////////////////////////////////
// OTHER SLOTS
/////////////////////////////////////////////////////////////////////
void KXMLEditorPart::slotTreeViewKeyPressed(QKeyEvent *e)
{
// few keypresses are recognized and proper actions
// are executed.
switch (e->key())
{
case Qt::Key_Delete : slotActDelete(); break;
case Qt::Key_Return :
case Qt::Key_Enter : slotActProperties(); break;
}
}
void KXMLEditorPart::slotSelectionCleared(bool bRootElementExists)
{
// Enable/Disable actions
if(m_pBrowserExt)
m_pBrowserExt->emit enableAction( "copy", false );
else
m_pActEditCopy->setEnabled(false);
m_pActEditDeselect->setEnabled(false);
m_pActViewNodeUp->setEnabled(false);
m_pActViewExpNode->setEnabled(false);
m_pActViewColNode->setEnabled(false);
m_pActBookmarksToggle->setEnabled(false);
if ( isReadWrite() )
{
m_pActEditCut->setEnabled(false );
m_pActEditPaste->setEnabled(true );
m_pActXmlElementInsert->setEnabled(!bRootElementExists);
m_pActXmlAttributesAdd->setEnabled(false);
m_pActXmlAttributesDel->setEnabled(false);
m_pActXmlProcInstrInsert->setEnabled(true);
m_pActInsertText->setEnabled(false);
m_pActInsertCDATA->setEnabled(false);
m_pActInsertComment->setEnabled(false);
m_pActXmlMoveNodeUp->setEnabled(false);
m_pActXmlMoveNodeDown->setEnabled(false);
m_pActDelete->setEnabled(false);
m_pActProperties->setEnabled(false);
m_pActEditRawXml->setEnabled(false);
}
m_pActPathCombo->slotClearEdit();
// change views
m_pViewContents->clear();
m_pTabWidget->setTabEnabled( m_pViewElement, false );
m_pTabWidget->setTabEnabled( m_pViewContents, false );
m_pTabWidget->setTabEnabled( m_pViewProcInstr, false );
m_pTabWidget->showPage( m_pViewContents );
// change path combo
m_pActPathCombo->slotClearEdit();
}
void KXMLEditorPart::slotSelectionChanged( const QDomElement & selectedNode)
{
// Enable/Disable actions
if(m_pBrowserExt)
m_pBrowserExt->emit enableAction( "copy", true );
else
m_pActEditCopy->setEnabled(true);
m_pActEditDeselect->setEnabled(true);
m_pActViewNodeUp->setEnabled( ! selectedNode.parentNode().isNull() ); // disable if it's a root item
m_pActViewExpNode->setEnabled( ! selectedNode.firstChild().isNull() ); // no childs -> disable
m_pActViewColNode->setEnabled( ! selectedNode.firstChild().isNull() ); // no childs -> disable
m_pActBookmarksToggle->setEnabled(true);
if ( isReadWrite() )
{
m_pActEditCut->setEnabled(true);
m_pActEditPaste->setEnabled(true);
m_pActXmlElementInsert->setEnabled(true);
m_pActXmlAttributesAdd->setEnabled(true);
m_pActXmlAttributesDel->setEnabled( (selectedNode.attributes().count() != 0) );
m_pActXmlProcInstrInsert->setEnabled(true);
// m_pActXmlCharDataInsert->setEnabled(true);
m_pActInsertText->setEnabled(true);
m_pActInsertCDATA->setEnabled(true);
m_pActInsertComment->setEnabled(true);
m_pActDelete->setEnabled(true);
m_pActProperties->setEnabled(true);
m_pActEditRawXml->setEnabled(true);
if ( selectedNode.parentNode().isDocument() )
{
m_pActXmlMoveNodeUp->setEnabled(false);
m_pActXmlMoveNodeDown->setEnabled(false);
}
else
{
m_pActXmlMoveNodeUp->setEnabled( ! selectedNode.previousSibling().isNull() );
m_pActXmlMoveNodeDown->setEnabled( ! selectedNode.nextSibling().isNull() );
}
}
// change views
m_pViewElement->slotChange(selectedNode);
m_pTabWidget->setTabEnabled( m_pViewElement, true );
m_pTabWidget->setTabEnabled( m_pViewContents, false );
m_pTabWidget->setTabEnabled( m_pViewProcInstr, false );
m_pTabWidget->showPage(m_pViewElement);
// change path combo
m_pActPathCombo->insertItem( domTool_getIconForNodeType(selectedNode.nodeType(), false), domTool_getPath(selectedNode) );
}
void KXMLEditorPart::slotSelectionChanged( const QDomCharacterData & selectedNode )
{
// Enable/Disable actions
if(m_pBrowserExt)
m_pBrowserExt->emit enableAction( "copy", true );
else
m_pActEditCopy->setEnabled(true);
m_pActEditDeselect->setEnabled(true);
m_pActViewNodeUp->setEnabled( ! selectedNode.parentNode().isNull() ); // disable if it's a root item
m_pActViewExpNode->setEnabled(false);
m_pActViewColNode->setEnabled(false);
m_pActBookmarksToggle->setEnabled(true);
if ( isReadWrite() )
{
m_pActEditCut->setEnabled(true);
m_pActEditPaste->setEnabled(true);
m_pActXmlElementInsert->setEnabled(false);
m_pActXmlAttributesAdd->setEnabled(false);
m_pActXmlAttributesDel->setEnabled(false);
m_pActXmlProcInstrInsert->setEnabled(false);
m_pActInsertText->setEnabled(false);
m_pActInsertCDATA->setEnabled(false);
m_pActInsertComment->setEnabled(false);
m_pActXmlMoveNodeUp->setEnabled( ! selectedNode.previousSibling().isNull() );
m_pActXmlMoveNodeDown->setEnabled( ! selectedNode.nextSibling().isNull() );
m_pActDelete->setEnabled(true);
m_pActProperties->setEnabled(true);
m_pActEditRawXml->setEnabled(false);
}
// change views
m_pViewContents->setText( selectedNode.data() );
m_pTabWidget->setTabEnabled( m_pViewElement, false );
m_pTabWidget->setTabEnabled( m_pViewContents, true );
m_pTabWidget->setTabEnabled( m_pViewProcInstr, false );
m_pTabWidget->showPage( m_pViewContents );
// change path combo
m_pActPathCombo->insertItem( domTool_getIconForNodeType(selectedNode.nodeType(), false), domTool_getPath(selectedNode) );
}
void KXMLEditorPart::slotSelectionChanged( const QDomProcessingInstruction & selectedNode )
{
// Enable/Disable actions
if(m_pBrowserExt)
m_pBrowserExt->emit enableAction( "copy", true );
else
m_pActEditCopy->setEnabled(true);
m_pActEditDeselect->setEnabled(true);
m_pActViewNodeUp->setEnabled( ! selectedNode.parentNode().isNull() ); // disable if it's a root item
m_pActViewExpNode->setEnabled(false);
m_pActViewColNode->setEnabled(false);
m_pActBookmarksToggle->setEnabled(true);
if ( isReadWrite() )
{
m_pActEditCut->setEnabled(true);
m_pActEditPaste->setEnabled(true);
m_pActXmlAttributesAdd->setEnabled(false);
m_pActXmlAttributesDel->setEnabled(false);
m_pActXmlProcInstrInsert->setEnabled(false);
m_pActInsertText->setEnabled(false);
m_pActInsertCDATA->setEnabled(false);
m_pActInsertComment->setEnabled(false);
m_pActDelete->setEnabled(true);
m_pActProperties->setEnabled(true);
m_pActEditRawXml->setEnabled(false);
m_pActXmlElementInsert->setEnabled(selectedNode.parentNode().isDocument() &&
document()->documentElement().isNull());
if ( selectedNode.parentNode().isDocument() )
{
m_pActXmlMoveNodeUp->setEnabled(false);
m_pActXmlMoveNodeDown->setEnabled(false);
}
else
{
m_pActXmlMoveNodeUp->setEnabled( ! selectedNode.previousSibling().isNull() );
m_pActXmlMoveNodeDown->setEnabled( ! selectedNode.nextSibling().isNull() );
}
}
// change views
m_pViewProcInstr->setText( selectedNode.data() );
m_pTabWidget->setTabEnabled( m_pViewElement, false );
m_pTabWidget->setTabEnabled( m_pViewContents, false );
m_pTabWidget->setTabEnabled( m_pViewProcInstr, true );
m_pTabWidget->showPage( m_pViewProcInstr );
// change path combo
m_pActPathCombo->insertItem( domTool_getIconForNodeType(selectedNode.nodeType(), false), domTool_getPath(selectedNode) );
}
void KXMLEditorPart::slotContextMenuRequested( const QString & szMenuName, const QPoint & pos )
{
QWidget * pContainer = hostContainer(szMenuName);
if ( ! pContainer )
{
kdError() << "KXMLEditor " << k_funcinfo << " Couldn't get a container widget for the given menu name (" << szMenuName << ")" << endl;
return;
}
if ( ! pContainer->inherits("KPopupMenu") )
{
kdError() << "KXMLEditor " << k_funcinfo << " Wrong container widget" << endl;
return;
}
KPopupMenu * pMenu = static_cast <KPopupMenu*> (pContainer);
pMenu->popup( pos );
}
/////////////////////////////////////////////////////////////////////
// FUNCTIONS CALLED FROM KXECommand CHILD CLASSES
/////////////////////////////////////////////////////////////////////
void KXMLEditorPart::updateNodeCreated(const QDomNode & node)
{
m_pViewTree->updateNodeCreated(node);
}
void KXMLEditorPart::updateNodeDeleted( const QDomNode & node )
{
m_pViewTree->updateNodeDeleted(node);
// if root element deleted, enable Insert Element
if(node.isElement() && (m_pViewTree->firstChild() == 0) && (isReadWrite()))
m_pActXmlElementInsert->setEnabled(true);
}
void KXMLEditorPart::updateNodeChanged( const QDomElement & domElement )
{
m_pViewTree->updateNodeChanged(domElement);
m_pViewElement->slotChange(domElement);
}
void KXMLEditorPart::updateNodeChanged( const QDomCharacterData & domCharData )
{
m_pViewTree->updateNodeChanged(domCharData);
m_pViewContents->setText( domCharData.data() );
}
void KXMLEditorPart::updateNodeChanged( const QDomProcessingInstruction &domProcInstr )
{
m_pViewTree->updateNodeChanged(domProcInstr);
m_pViewProcInstr->setText( domProcInstr.data() );
}
void KXMLEditorPart::updateNodeMoved( const QDomNode & domNode )
{
m_pViewTree->updateNodeMoved(domNode);
}
bool KXMLEditorPart::slotFileSaveAs()
{
emit setStatusBarText( i18n("Saving file with a new filename...") );
KFileDialog dlg( QDir::currentDirPath(), // start dir.
i18n(FILE_DIALOG_FILTER), // filter
widget(), // parent
"file dialog for saving", // name
true ); // modal
dlg.setCaption( i18n("Save as...") );
dlg.setOperationMode( KFileDialog::Saving );
dlg.exec();
KURL url = dlg.selectedURL();
bool bRetVal = false;
if(!url.isEmpty())
{
// append filetype if necessary
if(dlg.currentFilter() != "*.*")
{ QString strExtension = dlg.currentFilter();
strExtension.remove('*');
if(strExtension != url.fileName().right(strExtension.length()))
url.setFileName(url.fileName() + strExtension );
}
if((bRetVal = saveAs(url))) // something may go wrong
{
emit sigAddRecentURL(url);
setModified(false);
}
}
emit setStatusBarText( i18n("Ready.") );
return bRetVal;
}
void KXMLEditorPart::slotDocOpened()
{
// I temporary introduced code to measure the loading time using
// the different tree view item initialization modes.
// Simply open a document, remember the measured time difference,
// change the mode (in the configuration dialog), load the
// same document again and compare the measurements.
// Olaf
//
// TODO: the three lines operating with the QTime objects
// can be removed later
// update the view
m_pViewTree->updateClear();
int i = document()->childNodes().length();
//QTime t1 = QTime::currentTime(); //TODO: remove this line later (Olaf)
while ( i > 0 )
{
i--;
m_pViewTree->updateNodeCreated( document()->childNodes().item(i) );
}
//QTime t2 = QTime::currentTime(); //TODO: remove this and the next line later (Olaf)
//kdDebug() << "KXMLEditorPart::slotDocOpened() time difference: " << t1.msecsTo(t2) << " msecs" << endl;
m_pActPathCombo->slotClear();
}
void KXMLEditorPart::setDocument(KXEDocument *pDocument)
{
// detach previously used document
if (m_pDocument)
{
disconnect (m_pDocument,0,this,0);
}
m_pDocument = pDocument;
if (pDocument)
{
// open document notification
connect(pDocument,SIGNAL(sigOpened()),this,SLOT(slotDocOpened()));
// document modification is also dispatched
connect(pDocument,SIGNAL(sigModified(bool)),this,SLOT(setModified(bool)));
// update notifications
connect(pDocument,SIGNAL(sigNodeChanged(const QDomElement&)),this,SLOT(updateNodeChanged(const QDomElement&)));
connect(pDocument,SIGNAL(sigNodeChanged(const QDomProcessingInstruction&)),this,SLOT(updateNodeChanged(const QDomProcessingInstruction&)));
connect(pDocument,SIGNAL(sigNodeChanged(const QDomCharacterData&)),this,SLOT(updateNodeChanged(const QDomCharacterData&)));
connect(pDocument,SIGNAL(sigNodeCreated(const QDomNode&)),this,SLOT(updateNodeCreated(const QDomNode&)));
connect(pDocument,SIGNAL(sigNodeDeleted(const QDomNode&)),this,SLOT(updateNodeDeleted(const QDomNode&)));
connect(pDocument,SIGNAL(sigNodeMoved(const QDomNode&)),this,SLOT(updateNodeMoved(const QDomNode&)));
// merging document action collection
insertChildClient(pDocument);
}
}
void KXMLEditorPart::slotActRedo()
{
m_pCmdHistory->redo();
}
void KXMLEditorPart::slotActUndo()
{
m_pCmdHistory->undo();
}
void KXMLEditorPart::slotActDetachStylesheet()
{
KCommand *pCmd = m_pDocument->actDetachStylesheet();
if(pCmd) m_pCmdHistory->addCommand(pCmd);
}
void KXMLEditorPart::slotActAttachStylesheet()
{
KCommand *pCmd = m_pDocument->actAttachStylesheet();
if(pCmd) m_pCmdHistory->addCommand(pCmd);
}
void KXMLEditorPart::slotActDetachSchema()
{
KCommand *pCmd = m_pDocument->actDetachSchema();
if(pCmd) m_pCmdHistory->addCommand(pCmd);
}
void KXMLEditorPart::slotActAttachSchema()
{
KCommand *pCmd = m_pDocument->actAttachSchema();
if(pCmd) m_pCmdHistory->addCommand(pCmd);
}
// Instert or edit special processing instruction <?xml ... ?>
void KXMLEditorPart::slotActVersionEncoding()
{
KCommand *pCmd = m_pDocument->actVersionEncoding();
if(pCmd) m_pCmdHistory->addCommand(pCmd);
}
void KXMLEditorPart::updateActions()
{
if(!m_pDocument) return;
if(!m_pActAttachSchema) return; // not in read-write mode
// Schema
bool bSchemaExists = !m_pDocument->documentElement().isNull() &&
// that's a question why it works with negated condition ??????
!m_pDocument->documentElement().hasAttributeNS(SCHEMA_NAMESPACE,SCHEMA_ATTRIBUTE);
m_pActAttachSchema->setEnabled(!m_pDocument->documentElement().isNull() && !bSchemaExists);
m_pActDetachSchema->setEnabled(bSchemaExists);
// Stylesheet
m_pActDetachStylesheet->setEnabled(!m_pDocument->getSpecProcInstr("xml-stylesheet").isNull());
}
#include "kxmleditorpart.moc"