diff options
author | Slávek Banko <[email protected]> | 2016-03-26 13:50:43 +0100 |
---|---|---|
committer | Slávek Banko <[email protected]> | 2016-03-26 13:50:43 +0100 |
commit | d62c8c002c51fb7c36487839eeeb4ac89f044dee (patch) | |
tree | bb4d1f5c631ab1f22a3018ba39e6a806035f80fd /part/kxedocument.cpp | |
download | kxmleditor-d62c8c002c51fb7c36487839eeeb4ac89f044dee.tar.gz kxmleditor-d62c8c002c51fb7c36487839eeeb4ac89f044dee.zip |
Initial import of kxmleditor 1.1.4
Diffstat (limited to 'part/kxedocument.cpp')
-rw-r--r-- | part/kxedocument.cpp | 631 |
1 files changed, 631 insertions, 0 deletions
diff --git a/part/kxedocument.cpp b/part/kxedocument.cpp new file mode 100644 index 0000000..c3775c5 --- /dev/null +++ b/part/kxedocument.cpp @@ -0,0 +1,631 @@ +// +// C++ Implementation: kxedocument +// +// Description: +// +// +// Author: Adam Charytoniuk <[email protected]>, (C) 2004 +// +// Copyright: See COPYING file that comes with this distribution +// +// +#include "kxedocument.h" + +#include "kxmleditorfactory.h" +#include "kxeconfiguration.h" +#include "kxenewfilesettings.h" +#include "kxearchiveextssettings.h" +#include "kxeprintsettings.h" +#include "kxetextviewsettings.h" +#include "kxechoosestringdialog.h" +#include "kxeattachdialogbase.h" +#include "kxespecprocinstrdialog.h" +#include "kxefilenewdialog.h" +#include "commands_file.h" + + +#include <kfile.h> +#include <ktar.h> +#include <kzip.h> +#include <kfilterdev.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kcommand.h> +#include <kaction.h> +#include <kurl.h> +#include <kurlrequester.h> + +#include <qcombobox.h> +#include <qbuffer.h> +#include <qregexp.h> +#include <qtextcodec.h> +#include <qlabel.h> +#include <qcheckbox.h> + +KXEDocument::KXEDocument(QObject *parent, const char *name) + :QObject (parent,name), + QDomDocument(), + KXMLGUIClient() +{ + m_bDocIsCompressed = false; + m_bIsModified = false; + m_strCompressedTarEntryName = ""; + m_url = ""; + + //setXMLFile("kxedocument.rc"); +} + + +KXEDocument::~KXEDocument() +{ +} + + +bool KXEDocument::save(const QString &strFileName) +{ + if (this->documentElement().isNull() && + KMessageBox::warningContinueCancel(0, + i18n("Your file doesn't have root element defined. \n\ + Continue saving?"))==KMessageBox::Cancel ) + { + return false; + } + + QString strXML; + + QTextStream streamXML(&strXML, IO_WriteOnly); + int iIndent = KXMLEditorFactory::configuration()->textview()->indentSteps(); + ((QDomDocument*)this)->save(streamXML, iIndent); + + QString strEncoding; + QTextCodec *pTextCodec; + + // find encoding info + if(strXML.left(5) == "<?xml") + { int iStart, iEnd; + if((iStart = strXML.find("encoding", 0)) > 0) + { + // info about encoding found; + iStart += 8; // skip encoding + + // search " or ' after encoding + if((iStart = strXML.find(QRegExp("[\"']"), iStart)) > 0) + { + QChar ch = strXML[iStart]; + iStart++; // skip ch + if((iEnd = strXML.find(ch, iStart)) > 0) + { + strEncoding = strXML.mid(iStart, iEnd - iStart); + } + } + } + } + + if(strEncoding.length() <= 0) + pTextCodec = QTextCodec::codecForLocale(); // default + else + pTextCodec = QTextCodec::codecForName(strEncoding); + + if(pTextCodec == 0) + { if(KMessageBox::questionYesNo(0, i18n("Codec for encoding %1 not found ! Continue saving ?").arg(strEncoding)) != KMessageBox::Yes) + return false; + } + + QCString strDecoded; + if(pTextCodec) + { strDecoded = pTextCodec->fromUnicode(strXML); + } + + // save string to file + if(!m_bDocIsCompressed) + { QFile file(strFileName); + if(file.open(IO_WriteOnly) == true) + { file.writeBlock(strDecoded, strDecoded.length()); + file.flush(); + file.close(); + } + else + { KMessageBox::error(0, + i18n("Can't create file %1").arg(strFileName), + i18n("Write error !")); + } + } + else + { // obtain file extension ----------------------------------------- + QString strExtension; + + int iPos = strFileName.findRev('.'); + + if(iPos > 0) + { strExtension = strFileName.mid(iPos + 1); + } + + if(strExtension == "svgz") + { + KMessageBox::sorry(0, + "Saving *.svgz not implemented yet", + "sory"); + return false; + } + else + { + KZip tarGzFile(strFileName); // New KOffice use KZip instead of KTarGz for storing files + if(tarGzFile.open(IO_WriteOnly)) + { tarGzFile.writeFile(m_strCompressedTarEntryName, "user", "group", strDecoded.length(), strDecoded); + tarGzFile.close(); + } + else + { KMessageBox::error(0, + i18n("Can't create archive %1").arg(strFileName), + i18n("Write error !")); + } + } + } + + return true; +} + +bool KXEDocument::open(const QString &strFileName) +{ + QString strCompressedTarEntryName; + + kdDebug() << "KXEDocument::open: opening file " << strFileName << endl; + + // obtain file extension ----------------------------------------- + QString strExtension; + + int iPos = strFileName.findRev('.'); + + if(iPos > 0) + { strExtension = strFileName.mid(iPos + 1); + } + + QString strTmpfileName; + + if ( KXMLEditorFactory::configuration()->archexts()->extensions().contains(strExtension) ) + { + + KTempFile tmp; + if (tmp.status() != 0) + { + kdError() << "Couldn't open temp file" << endl; + KMessageBox::sorry(0, i18n("Couldn't open temp file !")); + return false; + } + + tmp.setAutoDelete(false); + QFile &fileTemporary = *(tmp.file()); + + + if(strExtension == "svgz") + { + //----------------------- It is gzip compressed file ----------------------- + + m_strCompressedTarEntryName = strFileName.left(strFileName.length() - 5); // For SVG compressed icons strip extension, e.g. "kate.svgz" has entry "kate" etc + + iPos = m_strCompressedTarEntryName.findRev('/'); + + if(iPos > 0) + { m_strCompressedTarEntryName = m_strCompressedTarEntryName.mid(iPos + 1); + } + + QIODevice *pIODevice = KFilterDev::deviceForFile(strFileName, "application/x-gzip"); + + if(pIODevice->open( IO_ReadOnly )) + { + QTextStream stream(pIODevice); + QString line; + //int i = 1; + while ( !stream.atEnd() ) + { + line = stream.readLine(); // line of text excluding '\n' + //printf( "%3d: %s\n", i++, line.latin1() ); + fileTemporary.writeBlock(line, line.length()); + } + pIODevice->close(); + } + } + else + { + //----------------------- It is zip archive file --------------------------- + + KZip tarGzFile(strFileName); // new KOffice use KZip instead of KTarGz for storing files + + tarGzFile.open(IO_ReadOnly); + fileTemporary.open(IO_WriteOnly); + + const KTarDirectory *root = tarGzFile.directory(); + if(!root) + { + return false; + } + + // For KOffice files let user to choose maindoc or documentinfo + if(strCompressedTarEntryName.length() == 0) + { KXEChooseStringDialog dlgChooseString(0, 0, i18n("Choose file"), i18n("File:")); + dlgChooseString.m_pComboBox->insertItem("maindoc.xml"); + dlgChooseString.m_pComboBox->insertItem("documentinfo.xml"); + + if(dlgChooseString.exec() != KXEChooseStringDialog::Accepted) + { return false; + } + m_strCompressedTarEntryName = dlgChooseString.m_strChoosedText; + } + else + { + m_strCompressedTarEntryName = strCompressedTarEntryName; + } + + const KArchiveEntry *entry = root->entry(m_strCompressedTarEntryName); + + if(entry && entry->isFile()) + { const KArchiveFile *pTarFile = static_cast <const KArchiveFile *> (entry); + + QBuffer buffer(pTarFile->data()); + buffer.open(IO_ReadOnly); + + fileTemporary.writeBlock(buffer.buffer(), buffer.size()); + } + else + m_strCompressedTarEntryName.truncate(0); + + tarGzFile.close(); + } + + strTmpfileName = fileTemporary.name(); + fileTemporary.close(); + + m_bDocIsCompressed = true; + } + else + m_bDocIsCompressed = false; + + + // ( 1.) parse the file and fill our document + QFile file(m_bDocIsCompressed ? strTmpfileName : strFileName); + if(! file.open(IO_ReadOnly)) + { + kdDebug() << "KXEDocument::openFile: Can't open file." << endl; + return false; + } + + // auxiliary file for obtaining encoding info + QFile fileAux(m_bDocIsCompressed ? strTmpfileName : strFileName); + if(! fileAux.open(IO_ReadOnly)) + { + kdDebug() << "KXEDocument::openFile: Can't open file." << endl; + return false; + } + + QTextStream txtStreamLocal( & file ); + + // Lookup at XML document encoding ----------------------------------------------- + QTextStream txtStreamAux( & fileAux ); + QString strFirstLine = txtStreamAux.readLine(); + fileAux.close(); + int iStart, iEnd; + if((iStart = strFirstLine.find("encoding", 0)) > 0) + { + QString strEncoding; + // info about encoding found; + iStart += 8; // skip encoding + + // search " or ' after encoding + if((iStart = strFirstLine.find(QRegExp("[\"']"), iStart)) > 0) + { + QChar ch = strFirstLine[iStart]; + iStart++; // skip ch + if((iEnd = strFirstLine.find(ch, iStart)) > 0) + { + strEncoding = strFirstLine.mid(iStart, iEnd - iStart); + + QTextCodec *pTextCodec = QTextCodec::codecForName(strEncoding); + if(pTextCodec) + txtStreamLocal.setCodec(pTextCodec); + else + { + KMessageBox::sorry(0, i18n("Codec for encoding %1 not found ! Using locale encoding for load.").arg(strEncoding)); + txtStreamLocal.setEncoding(QTextStream::Locale); + } + } + } + } + else + { + // XML documment dont have info about encoding, set default UTF-8 + txtStreamLocal.setCodec(QTextCodec::codecForName("UTF-8")); + } + + + //-------------------------------------------------------------------------------- + QString strFileContents = txtStreamLocal.read(); + file.close(); + + if(m_bDocIsCompressed) + { + QDir dir; + dir.remove(strTmpfileName); + } + + //-- Set string with XML to QDomDocument ------------------------------------------ + QString strErrorMsg; + int iErrorLine, iErrorColumn; + QDomDocument * pNewDoc = new QDomDocument; // first try with a new document + + if( ! pNewDoc->setContent(strFileContents, true, &strErrorMsg, &iErrorLine, &iErrorColumn) ) + { kdDebug() << "KXEDocument::openFile: Failed parsing the file." << endl; + + KMessageBox::error(0, + i18n("%1 in line %2, column %3").arg(strErrorMsg).arg(iErrorLine).arg(iErrorColumn), + i18n("Parsing error !")); + + delete pNewDoc; // remove the new document, because it's useless + return false; + } + +// The following commented code is performance wise buggy, because the string +// gets parsed a second time. I replaced it with this code. + // copy the content of the parsed document to this one + QDomNode e = pNewDoc->removeChild( pNewDoc->documentElement() ); + QDomDocument::operator=( *pNewDoc ); + appendChild( e ); +// Here comes the "buggy" code. + //this->setContent(pNewDoc->toString(),true,0,0); // and take the new one + //delete pNewDoc; // remove the former document +// To test/see the difference in loading time, you can switch the commented +// codeblocks above and compare the loading-time-differences measured in +// KXMLEditorPart::openFile. +// Olaf +// TODO: remove the comments above later + + emit sigOpened(); + + return true; +} + +void KXEDocument::setModified(bool value) +{ + m_bIsModified = value; + emit sigModified(value); +} + +void KXEDocument::setURL(KURL url) +{ + m_url = url; + emit sigURLChanged(url); +} + +void KXEDocument::updateNodeCreated(const QDomNode & node) +{ + emit sigNodeCreated(node); + setModified(); +} + +void KXEDocument::updateNodeDeleted(const QDomNode & node) +{ + emit sigNodeDeleted(node); + setModified(); +} + +void KXEDocument::updateNodeChanged( const QDomElement & domElement ) +{ + emit sigNodeChanged(domElement); + setModified(); +} + +void KXEDocument::updateNodeChanged( const QDomCharacterData & node ) +{ + emit sigNodeChanged(node); + setModified(); +} + +void KXEDocument::updateNodeChanged( const QDomProcessingInstruction &domProcInstr ) +{ + emit sigNodeChanged(domProcInstr); + setModified(); +} + +void KXEDocument::updateNodeMoved( const QDomNode & node ) +{ + emit sigNodeMoved(node); + setModified(); +} + +void KXEDocument::attachStylesheet(const KURL& stylesheet) +{ + setSpecProcInstr("xml-stylesheet",QString("type = 'text/xsl' href = '")+stylesheet.url()+"' "); +} + +void KXEDocument::detachStylesheet() +{ + removeSpecProcInstr("xml-stylesheet"); +} + +void KXEDocument::attachSchema(const KURL& schema) +{ + QDomElement domElement = documentElement(); + if (!domElement.isNull()) + { + domElement.setAttributeNS(SCHEMA_NAMESPACE, + SCHEMA_ATTRIBUTE_XSI, + schema.url()); + // refresh views + updateNodeChanged(domElement); + setModified(); + } +} + +void KXEDocument::detachSchema() +{ + QDomElement domElement = this->documentElement(); + if (!domElement.isNull()) + { + domElement.removeAttributeNS(SCHEMA_NAMESPACE,SCHEMA_ATTRIBUTE); + // refresh views + updateNodeChanged(domElement); + setModified(); + } +} + +void KXEDocument::setSpecProcInstr(const QString& target, const QString& data) +{ + // removing old one + removeSpecProcInstr(target); + // create new one + if (!data.isEmpty()) + { + QDomProcessingInstruction domProcInstr = this->createProcessingInstruction(target,data); + + QDomNode node = getSpecProcInstr("xml"); + if (!node.isNull()) + // if there is already xml instruction, then put that one below it + this->insertAfter(domProcInstr,node); + else + // otherwise put it always on the top + this->insertBefore(domProcInstr,this->firstChild()); + + updateNodeCreated(domProcInstr); + } + setModified(); +} + +void KXEDocument::removeSpecProcInstr(const QString &target) +{ + QDomNode domNode = getSpecProcInstr(target); + if (!domNode.isNull()) + { + updateNodeDeleted(domNode); + ((QDomDocument*)this)->removeChild(domNode); + setModified(); + } +} + +QDomNode KXEDocument::getSpecProcInstr(const QString& target) +{ + QDomNode result; + QDomNodeList domNodeList = this->childNodes(); + for (uint i=0;i<domNodeList.count();i++) + if (domNodeList.item(i).isProcessingInstruction()) + { + QDomProcessingInstruction domProcInstr = domNodeList.item(i).toProcessingInstruction(); + if (domProcInstr.target()==target) + return domNodeList.item(i); + } + return result; +} + +void KXEDocument::newFile() +{ + switch ( KXMLEditorFactory::configuration()->newfile()->newFileCreaBehav() ) + { + case KXENewFileSettings::CreateEmptyFile: + break; // nothing to do in this case + + case KXENewFileSettings::CreateWithAssistance: + { + + KXEFileNewDialog dlg( 0L); + dlg.fillDialog( KXMLEditorFactory::configuration()->newfile()->dfltVersion(), + KXMLEditorFactory::configuration()->newfile()->dfltEncoding() ); + if( dlg.exec() ) + { // if the dialog has been accepted (OK pressed) + setSpecProcInstr( "xml", dlg.getData() ); + + // if the dialog shouldn't be shown anymore, the settings have to be changed + if ( dlg.m_pDontShowAgain->isChecked() ) + KXMLEditorFactory::configuration()->newfile()->setNewFileCreaBehav( KXENewFileSettings::UseDefaults, instance()->config() ); + } + + break; + } + + case KXENewFileSettings::UseDefaults: + setSpecProcInstr( "xml", QString( "version='%1' encoding='%2'" ).arg(KXMLEditorFactory::configuration()->newfile()->dfltVersion()).arg(KXMLEditorFactory::configuration()->newfile()->dfltEncoding()) ); + break; + } + emit sigOpened(); + setModified(); +} + +//------------- SLOTS, called from Part -------------------------------- + +KCommand * KXEDocument::actDetachStylesheet() +{ + QDomNode domNode = getSpecProcInstr("xml-stylesheet"); + if (!domNode.isNull()) + { + KCommand *pCmd = new KXEStylesheetDetachCommand(this,domNode.toProcessingInstruction().data()); + return pCmd; + } + return 0L; +} + +KCommand * KXEDocument::actAttachStylesheet() +{ + KXEAttachDialogBase dlg; + dlg.Label->setText(i18n("Stylesheet URL:")); + if (dlg.exec()) + { + QDomNode domNode = getSpecProcInstr("xml-stylesheet"); + QString data = ""; + if (!domNode.isNull()) + data = domNode.toProcessingInstruction().data(); + KCommand *pCmd = new KXEStylesheetAttachCommand(this,data,dlg.attachURI->url()); + return pCmd; + } + return 0L; +} + +KCommand * KXEDocument::actDetachSchema() +{ + if (!documentElement().isNull()) // just for sure... + { + KCommand *pCmd = new KXESchemaDetachCommand(this, + documentElement().attributeNS(SCHEMA_NAMESPACE, + SCHEMA_ATTRIBUTE,"") + ); + return pCmd; + } + return 0L; +} + +KCommand * KXEDocument::actAttachSchema() +{ + KXEAttachDialogBase dlg; + dlg.Label->setText(i18n("Schema URL:")); + if (dlg.exec()) + { + if (!documentElement().isNull()) // just for sure... + { + KCommand *pCmd = new KXESchemaAttachCommand(this,dlg.attachURI->url(), + documentElement().attributeNS(SCHEMA_NAMESPACE,SCHEMA_ATTRIBUTE,"")); + return pCmd; + } + } + return 0L; +} + +// Instert or edit special processing instruction <?xml ... ?> +KCommand * KXEDocument::actVersionEncoding() +{ + QDomNode node = getSpecProcInstr("xml"); + KXESpecProcInstrDialog dlg; + + if(!node.isNull()) + dlg.fillDialog(node.toProcessingInstruction().data()); + else + dlg.fillDialog( KXMLEditorFactory::configuration()->newfile()->dfltVersion(), + KXMLEditorFactory::configuration()->newfile()->dfltEncoding() ); + + if(dlg.exec()) + { + QString strOldData = ""; + if (!node.isNull()) + strOldData = node.toProcessingInstruction().data(); + KCommand *pCmd = new KXEVersionEncodingCommand(this,strOldData,dlg.getData()); + return pCmd; + } + return 0L; +} |