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.
tdewebdev/quanta/src/quantaview.cpp

1186 lines
37 KiB

/***************************************************************************
quantaview.cpp - description
-------------------
begin : <20><><EFBFBD><EFBFBD> 9 13:29:57 EEST 2000
copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com>
(C) 2001-2005 Andras Mantia <amantia@kde.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 files for TQt
#include <tqprinter.h>
#include <tqpainter.h>
#include <tqtabbar.h>
#include <tqtabwidget.h>
#include <tqtimer.h>
#include <tqlayout.h>
#include <tqwidgetstack.h>
#include <tqdom.h>
#include <tqfile.h>
#include <tqevent.h>
#include <tqwidget.h>
#include <tqsplitter.h>
#include <tqpoint.h>
#include <tqscrollview.h>
// include files for KDE
#include <tdeaction.h>
#include <kdebug.h>
#include <kdirwatch.h>
#include <tdehtmlview.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kmenubar.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kurldrag.h>
#include <tdeversion.h>
#include <tdeparts/partmanager.h>
#include <kstatusbar.h>
#include "undoredo.h"
#include "kafkacommon.h"
#include "wkafkapart.h"
#include <tdetexteditor/document.h>
#include <tdetexteditor/selectioninterface.h>
#include <tdetexteditor/selectioninterfaceext.h>
#include <tdetexteditor/view.h>
#include <tdetexteditor/viewcursorinterface.h>
// application specific includes
#include "document.h"
#include "resource.h"
#include "quantaview.h"
#include "quanta.h"
#include "quantacommon.h"
#include "qextfileinfo.h"
#include "viewmanager.h"
#include "tagaction.h"
#include "toolbartabwidget.h"
#include "quantaplugin.h"
#include "project.h"
#include "structtreeview.h"
#include "tagdialog.h"
extern int NN;
extern TQValueList<Node*> nodes;
QuantaView::QuantaView(TQWidget *parent, const char *name, const TQString &caption )
: KMdiChildView(parent, name)
, m_document(0L)
, m_plugin(0L)
, m_customWidget(0L)
, m_kafkaDocument(0L)
, m_currentFocus(SourceFocus)
{
setMDICaption(caption);
//Connect the VPL update timers
connect(&m_sourceUpdateTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(sourceUpdateTimerTimeout()));
connect(&m_VPLUpdateTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(VPLUpdateTimerTimeout()));
//create the source and VPL holding widgets
m_documentArea = new TQWidget(this);
//get the reference to the user toolbar holding widget
ToolbarTabWidget *m_toolbarTab = ToolbarTabWidget::ref();
m_toolbarTab->reparent(this, 0, TQPoint(), true);
m_toolbarTab ->setFocusPolicy( TQ_NoFocus );
//create a splitter to separate the VPL and document area
m_splitter = new TQSplitter(Qt::Vertical, this);
//place the widgets in a grid
m_viewLayout = new TQGridLayout(this, 2, 0);
m_viewLayout->setRowStretch(0, 0);
m_viewLayout->setRowStretch(1,1);
m_viewLayout->addWidget( m_toolbarTab, 0, 0);
m_viewLayout->addWidget( m_documentArea, 1, 0);
m_documentArea->show();
setAcceptDrops(true); // [MB02] Accept drops on the view
}
QuantaView::~QuantaView()
{
// quantaApp is undefined if the destructor of QuantaApp is active
if (quantaApp)
quantaApp->slotFileClosed(m_document);
if (m_document)
{
m_document->view()->reparent(0L, 0, TQPoint(), false);
if (quantaApp)
emit documentClosed(m_document->url());
}
delete m_document;
m_document = 0L;
}
bool QuantaView::mayRemove()
{
emit hidePreview();
if (m_plugin)
{
m_plugin->unload(false);
} else
{
bool unmodifiedUntitled = false;
if (m_document && m_document->isUntitled() && !m_document->isModified())
unmodifiedUntitled = true;
if (m_customWidget)
m_customWidget->reparent(0L, 0, TQPoint(), false);
if (!saveModified())
return false;
slotSetSourceLayout();
if (static_cast<QuantaView *>(quantaApp->activeWindow()) == this)
{
parser->setSAParserEnabled(false);
kdDebug(24000) << "Node objects before delete = " << NN << " ; list count = " << nodes.count() << endl;
Node::deleteNode(baseNode);
baseNode = 0L;
kdDebug(24000) << "Node objects after delete = " << NN << " ; list count = " << nodes.count() << endl;
TQValueList<Node*> nList = nodes;
/* for (TQValueList<Node*>::ConstIterator it = nList.constBegin(); it != nList.constEnd(); ++it)
Node::deleteNode(*it);
kdDebug(24000) << "Node objects after cleanup = " << NN << " ; list count = " << nodes.count() << endl;*/
}
if (m_document)
{
KURL url = m_document->url();
Project::ref()->saveBookmarks(url, dynamic_cast<KTextEditor::MarkInterface*>(m_document->doc()));
if (!unmodifiedUntitled)
emit eventHappened("before_close", url.url(), TQString());
m_currentViewsLayout = -1;
// m_document->closeTempFile();
if (!m_document->isUntitled() && url.isLocalFile())
{
fileWatcher->removeFile(url.path());
// kdDebug(24000) << "removeFile[mayRemove]: " << url.path() << endl;
}
Project::ref()->saveCursorPosition(url, dynamic_cast<KTextEditor::ViewCursorInterface*>(m_document->view()));
quantaApp->menuBar()->activateItemAt(-1);
quantaApp->guiFactory()->removeClient(m_document->view());
if (!unmodifiedUntitled)
emit eventHappened("after_close", url.url(), TQString());
}
/* kdDebug(24000) << "Calling reparse from close " << endl;
parser->setSAParserEnabled(true);
quantaApp->reparse(true);*/
}
return true;
}
void QuantaView::addDocument(Document *document)
{
if (!document)
return;
m_document = document;
connect(m_document, TQT_SIGNAL(editorGotFocus()), this, TQT_SLOT(slotSourceGetFocus()));
connect(m_document->view(), TQT_SIGNAL(cursorPositionChanged()), this, TQT_SIGNAL(cursorPositionChanged()));
m_kafkaDocument = KafkaDocument::ref();
connect(m_kafkaDocument->getKafkaWidget(), TQT_SIGNAL(hasFocus(bool)),
this, TQT_SLOT(slotVPLGetFocus(bool)));
connect(m_kafkaDocument, TQT_SIGNAL(newCursorPosition(int,int)),
this, TQT_SLOT(slotSetCursorPositionInSource(int, int)));
connect(m_kafkaDocument, TQT_SIGNAL(loadingError(Node *)),
this, TQT_SLOT(slotVPLLoadingError(Node *)));
m_kafkaReloadingEnabled = true;
m_quantaReloadingEnabled = true;
m_curCol = m_curLine = m_curOffset = 0;
//init the VPL part
m_currentViewsLayout = SourceOnly;//to correctly reload the timers.
reloadUpdateTimers();
m_currentViewsLayout = -1; //force loading of this layout
slotSetSourceLayout();
}
void QuantaView::addPlugin(QuantaPlugin *plugin)
{
ToolbarTabWidget *m_toolbarTab = ToolbarTabWidget::ref();
m_toolbarTab->reparent(0, 0, TQPoint(), false);
m_plugin = plugin;
m_splitter->hide();
TQWidget *w = m_plugin->widget();
if (w)
{
w->reparent(m_documentArea, 0, TQPoint(), true);
w->resize(m_documentArea->size());
}
m_documentArea->reparent(this, 0, TQPoint(), true);
m_viewLayout->addWidget(m_documentArea, 1, 0);
activated();
updateTab();
}
void QuantaView::addCustomWidget(TQWidget *widget, const TQString &label)
{
if (widget)
{
ToolbarTabWidget::ref()->reparent(0, 0, TQPoint(), false);
m_customWidget = widget;
m_splitter->hide();
widget->reparent(m_documentArea, 0, TQPoint(), true);
widget->resize(m_documentArea->size());
if (!label.isEmpty())
{
widget->setCaption(label);
updateTab();
}
m_viewLayout->addWidget(m_documentArea, 1, 0);
m_documentArea->show();
} else
if (m_customWidget)
{
ToolbarTabWidget::ref()->reparent(this, 0, TQPoint(), qConfig.enableDTDToolbar);
m_viewLayout->addWidget(ToolbarTabWidget::ref(), 0 , 0);
m_customWidget = 0L; //avoid infinite recursion
reloadLayout();
}
if (m_documentArea->height() + ToolbarTabWidget::ref()->height() > height() && ToolbarTabWidget::ref()->isVisible())
resize(m_documentArea->width(), m_documentArea->height() - ToolbarTabWidget::ref()->height());
else if (ToolbarTabWidget::ref()->isHidden())
resize(width(), height());
}
void QuantaView::reloadLayout()
{
int currentViewsLayout = m_currentViewsLayout;
m_currentViewsLayout = -1; //force loading of this layout
switch (currentViewsLayout)
{
case SourceOnly:
slotSetSourceLayout();
break;
case SourceAndVPL:
slotSetSourceAndVPLLayout();
break;
case VPLOnly:
slotSetVPLOnlyLayout();
break;
}
}
void QuantaView::updateTab()
{
if (qConfig.showCloseButtons == "ShowAlways")
{
setIcon(SmallIcon("fileclose"));
}
if (m_document)
{
// try to set the icon from mimetype
TQIconSet mimeIcon (KMimeType::pixmapForURL(m_document->url(), 0, KIcon::Small));
if (mimeIcon.isNull())
mimeIcon = TQIconSet(SmallIcon("document"));
TQString urlStr = QExtFileInfo::shortName(m_document->url().path());
if (m_document->isModified())
{
if (qConfig.showCloseButtons == "ShowAlways")
{
setMDICaption(urlStr + " " + i18n("[modified]"));
} else
{
setIcon(SmallIcon("filesave"));
setMDICaption(urlStr);
}
m_szCaption = urlStr + " " + i18n("[modified]");
} else
{
if (qConfig.showCloseButtons != "ShowAlways")
{
setIcon(mimeIcon.pixmap());
}
setMDICaption(urlStr);
quantaApp->setTabToolTip(this, m_document->url().prettyURL(0, KURL::StripFileProtocol));
}
} else
if (m_plugin)
{
if (qConfig.showCloseButtons != "ShowAlways")
{
setIcon(SmallIcon(m_plugin->icon()));
}
setMDICaption(m_plugin->name());
} else
if (m_customWidget)
{
if (qConfig.showCloseButtons != "ShowAlways")
{
setIcon(*(m_customWidget->icon()));
}
setMDICaption(m_customWidget->caption());
}
}
TQString QuantaView::tabName()
{
if (m_document)
{
return m_document->url().fileName();
} else
if (m_plugin)
{
return m_plugin->name();
} else
if (m_customWidget)
{
return m_customWidget->caption();
} else
return "";
}
void QuantaView::slotSetSourceLayout()
{
emit hidePreview();
if (m_currentViewsLayout == SourceOnly || !m_document)
return;
if(m_currentViewsLayout == SourceAndVPL)
m_splitterSizes = m_splitter->sizes();
TDEToggleAction *ta = (TDEToggleAction *) quantaApp->actionCollection()->action( "show_quanta_editor" );
if (ta)
ta->setChecked(true);
//hide the VPL widget, reload the source if necessary
if ((m_currentViewsLayout == SourceAndVPL && m_kafkaDocument->getKafkaWidget()->view()->hasFocus()) ||
m_currentViewsLayout == VPLOnly)
{
reloadSourceView();
}
if (m_kafkaDocument->isLoaded())
m_kafkaDocument->unloadDocument();
//show the document if full size
m_splitter->hide();
m_kafkaDocument->getKafkaWidget()->view()->reparent(0, 0, TQPoint(), false);
m_document->view()->reparent(m_documentArea, 0, TQPoint(), true);
m_document->view()->resize(m_documentArea->size());
m_viewLayout->addWidget(m_documentArea, 1, 0);
m_document->view()->setFocus();
m_currentViewsLayout = SourceOnly;
//update timers are not needed in source only mode
m_sourceUpdateTimer.stop();
m_VPLUpdateTimer.stop();
}
void QuantaView::slotSetSourceAndVPLLayout()
{
emit hidePreview();
if (m_currentViewsLayout == SourceAndVPL || !m_document)
return;
TDEToggleAction *ta = (TDEToggleAction *) quantaApp->actionCollection()->action( "show_kafka_and_quanta" );
if (m_document->defaultDTD()->name.contains("HTML", false) == 0)
{
KMessageBox::information(this, i18n("The VPL Mode does not support the current DTD, at the moment: %1").arg(m_document->defaultDTD()->nickName));
TDEToggleAction *ta2 = (TDEToggleAction *) quantaApp->actionCollection()->action( "show_quanta_editor" );
if (ta2)
ta2->setChecked(true);
return;
}
if (ta)
ta->setChecked(true);
if (!m_kafkaDocument->isLoaded())
m_kafkaDocument->loadDocument(m_document);
if (m_currentViewsLayout == VPLOnly)
{
reloadSourceView();
}
m_kafkaDocument->getKafkaWidget()->view()->reparent(m_splitter, 0, TQPoint(), true);
m_splitter->moveToFirst(m_kafkaDocument->getKafkaWidget()->view());
m_document->view()->reparent(m_splitter, 0, TQPoint(), true);
m_viewLayout->addWidget(m_splitter, 1, 0);
m_splitter->setSizes(m_splitterSizes);
m_splitter->show();
if ( m_currentViewsLayout == SourceOnly &&
(!baseNode || (baseNode->tag->type == Tag::Empty &&
!baseNode->next && !baseNode->child)))
{
quantaApp->documentProperties(true);
}
m_currentViewsLayout = SourceAndVPL;
reloadUpdateTimers();
}
void QuantaView::slotSetVPLOnlyLayout()
{
emit hidePreview();
if (m_currentViewsLayout == VPLOnly || !m_document)
return;
if(m_currentViewsLayout == SourceAndVPL)
m_splitterSizes = m_splitter->sizes();
TDEToggleAction *ta = (TDEToggleAction *) quantaApp->actionCollection()->action( "show_kafka_view" );
if (m_document->defaultDTD()->name.contains("HTML", false) == 0)
{
KMessageBox::information(this, i18n("The VPL Mode does not support the current DTD, at the moment: %1").arg(m_document->defaultDTD()->nickName));
TDEToggleAction *ta2 = (TDEToggleAction *) quantaApp->actionCollection()->action( "show_quanta_editor" );
if (ta2)
ta2->setChecked(true);
return;
}
if (ta)
ta->setChecked(true);
m_splitter->hide();
if (!m_kafkaDocument->isLoaded())
m_kafkaDocument->loadDocument(m_document);
m_kafkaDocument->getKafkaWidget()->view()->reparent(m_documentArea, 0, TQPoint(), true);
m_kafkaDocument->getKafkaWidget()->view()->resize(m_documentArea->size());
m_viewLayout->addWidget(m_documentArea, 1, 0);
m_kafkaDocument->getKafkaWidget()->view()->setFocus();
if ( m_currentViewsLayout == SourceOnly &&
(!baseNode || (baseNode->tag->type == Tag::Empty &&
!baseNode->next && !baseNode->child)))
{
quantaApp->documentProperties(true);
}
m_currentViewsLayout = VPLOnly;
//update timers are not needed in VPL only mode
m_sourceUpdateTimer.stop();
m_VPLUpdateTimer.stop();
}
void QuantaView::reloadUpdateTimers()
{
QuantaView* view=ViewManager::ref()->activeView();
m_sourceUpdateTimer.stop();
m_VPLUpdateTimer.stop();
if (m_kafkaDocument->isLoaded() && m_currentViewsLayout == SourceAndVPL && view && view == this)
{
if (m_currentFocus == VPLFocus && !qConfig.quantaRefreshOnFocus)
m_sourceUpdateTimer.start(qConfig.quantaRefreshDelay);
if (m_currentFocus == SourceFocus && !qConfig.kafkaRefreshOnFocus)
m_VPLUpdateTimer.start(qConfig.kafkaRefreshDelay);
}
}
void QuantaView::slotVPLGetFocus(bool focus)
{
// is Quanta exiting?
if (!quantaApp) return;
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "slotVPLGetFocus(" << focus << ")" << endl;
#endif
int contentsX, contentsY;
TDEAction *action;
if(focus)
{
//We reload the kafka part from the Node Tree
if (m_currentViewsLayout == SourceAndVPL && m_currentFocus == SourceFocus)
{
contentsX = m_kafkaDocument->getKafkaWidget()->view()->contentsX();
contentsY = m_kafkaDocument->getKafkaWidget()->view()->contentsY();
//Reload the kafka Editor only if Quanta was modified or if something has happened (e.g. a reparse)
//and NEED a kafka reload.
if (parser->parsingNeeded())
baseNode = parser->rebuild(m_document);
reloadVPLView();
//doesn't work!
m_kafkaDocument->getKafkaWidget()->view()->setContentsPos(contentsX, contentsY);
}
//We disable some actions which doesn't work on kafka for the moment
action = quantaApp->actionCollection()->action("tag_edit_table");
if(action)
action->setEnabled(false);
action = 0L;
action = quantaApp->actionCollection()->action("tag_quick_list");
if(action)
action->setEnabled(false);
action = 0L;
action = quantaApp->actionCollection()->action("tag_color");
if(action)
action->setEnabled(false);
action = 0L;
action = quantaApp->actionCollection()->action("tag_mail");
if(action)
action->setEnabled(false);
action = 0L;
action = quantaApp->actionCollection()->action("tag_misc");
if(action)
action->setEnabled(false);
action = 0L;
action = quantaApp->actionCollection()->action("tag_frame_wizard");
if(action)
action->setEnabled(false);
action = 0L;
action = quantaApp->actionCollection()->action("insert_css");
if(action)
action->setEnabled(false);
action = 0L;
action = quantaApp->actionCollection()->action("insert_char");
if(action)
action->setEnabled(false);
//TEMPORARY: Enable VPL undo/redo logging
m_document->docUndoRedo->turnOn(true);
m_currentFocus = VPLFocus;
reloadUpdateTimers();
}
}
void QuantaView::slotSourceGetFocus()
{
// is Quanta exiting?
if (!quantaApp) return;
#ifdef LIGHT_DEBUG
kdDebug(25001)<< "slotSourceGetFocus(true)" << endl;
#endif
TDEAction *action;
quantaApp->partManager()->setActivePart(m_document->doc(), m_document->view());
//We reload the quanta view from the Node Tree.
if (m_currentViewsLayout == SourceAndVPL && m_currentFocus == VPLFocus)
{
reloadSourceView();
//FIXME: the tree (and the output)is right, the pos aren't.
//This will reparse the whole Node tree and reload kafka.
baseNode = parser->parse(m_document);
}
m_currentFocus = SourceFocus;
reloadUpdateTimers();
//We enable some actions which doesn't work on kafka for the moment
action = quantaApp->actionCollection()->action("tag_edit_table");
if(action)
action->setEnabled(true);
action = 0L;
action = quantaApp->actionCollection()->action("tag_quick_list");
if(action)
action->setEnabled(true);
action = 0L;
action = quantaApp->actionCollection()->action("tag_color");
if(action)
action->setEnabled(true);
action = 0L;
action = quantaApp->actionCollection()->action("tag_mail");
if(action)
action->setEnabled(true);
action = 0L;
action = quantaApp->actionCollection()->action("tag_misc");
if(action)
action->setEnabled(true);
action = 0L;
action = quantaApp->actionCollection()->action("tag_frame_wizard");
if(action)
action->setEnabled(true);
action = 0L;
action = quantaApp->actionCollection()->action("insert_css");
if(action)
action->setEnabled(true);
action = 0L;
action = quantaApp->actionCollection()->action("insert_char");
if(action)
action->setEnabled(true);
//TEMPORARY: Disable VPL undo/redo logging
m_document->docUndoRedo->turnOn(false);
}
/** Reloads both views ONLY when changes have been made to the Node tree ONLY. */
void QuantaView::reloadBothViews(bool force)
{
reloadSourceView(force);
reloadVPLView(force);
}
/** reload the Kafka view from the Node Tree. Set force to true if you want to reload even if not necessary. */
void QuantaView::reloadVPLView(bool force)
{
if (m_document && (m_kafkaReloadingEnabled || force))
m_document->docUndoRedo->reloadKafkaEditor(force);
}
/** reload the Quanta view from the Node Tree. Set force to true if you want to reload even if not necessary. */
void QuantaView::reloadSourceView(bool force)
{
if (m_quantaReloadingEnabled || force)
m_document->docUndoRedo->reloadQuantaEditor(force);
}
void QuantaView::VPLUpdateTimerTimeout()
{
if(quantaApp && m_currentFocus == SourceFocus)
reloadVPLView();
}
void QuantaView::sourceUpdateTimerTimeout()
{
if(quantaApp && m_currentFocus == VPLFocus)
reloadSourceView();
}
void QuantaView::slotVPLLoadingError(Node *)
{
emit showProblemsView();
}
void QuantaView::slotSetCursorPositionInSource(int col, int line)
{
m_curCol = col;
m_curLine = line;
if (m_currentViewsLayout == SourceAndVPL || m_currentViewsLayout == SourceOnly)
m_document->viewCursorIf->setCursorPositionReal(line, col);
}
void QuantaView::dragEnterEvent(TQDragEnterEvent *e)
{
e->accept(KURLDrag::canDecode(e));
}
void QuantaView::dropEvent(TQDropEvent *e)
{
emit dragInsert(e);
}
void QuantaView::resizeEvent(TQResizeEvent *e)
{
TQWidget::resizeEvent(e);
resize(m_documentArea->width(), m_documentArea->height());
}
void QuantaView::resize(int width, int height)
{
if (m_plugin && m_plugin->widget())
{
m_plugin->widget()->resize(width, height);
return;
} else
if (m_customWidget)
{
m_customWidget->resize(width, height);
return;
} else
if (!m_document)
return;
if (m_currentViewsLayout == SourceOnly)
m_document->view()->resize(width, height);
else
if (m_currentViewsLayout == VPLOnly)
m_kafkaDocument->getKafkaWidget()->view()->resize(width,height);
else
if (m_currentViewsLayout == SourceAndVPL)
{
m_splitter->resize(width, height);
m_splitterSizes = m_splitter->sizes();
}
}
void QuantaView::insertTag(const char *tag)
{
if (!m_document )
return;
TQString tagStr = QuantaCommon::tagCase(tag);
const DTDStruct *dtd = m_document->currentDTD(true);
bool single = QuantaCommon::isSingleTag(dtd->name, tagStr);
bool optional = QuantaCommon::isOptionalTag(dtd->name, tagStr);
TQString startTag = tagStr;
startTag.prepend("<");
if ( dtd->singleTagStyle == "xml" &&
( single || (optional && !qConfig.closeOptionalTags))
)
{
startTag.append(" /");
}
startTag.append(">");
if ( (qConfig.closeTags && !single && !optional) ||
(qConfig.closeOptionalTags && optional) )
{
m_document->insertTag( startTag, TQString("</")+tagStr+">");
}
else
{
m_document->insertTag(startTag);
}
}
//FIXME: Move out from here??
/** Insert a new tag by bringing up the TagDialog. */
void QuantaView::insertNewTag(const TQString &tag, const TQString &attr, bool insertInLine)
{
if (m_document)
{
if (m_currentFocus == QuantaView::VPLFocus ||
(m_currentFocus == QuantaView::SourceFocus && qConfig.smartTagInsertion))
insertOutputInTheNodeTree("", "", quantaApp->showTagDialogAndReturnNode(tag, attr));
else
{
TQString selection;
if (m_document->selectionIf)
selection = m_document->selectionIf->selection();
TagDialog *dlg = new TagDialog(QuantaCommon::tagFromDTD(m_document->getDTDIdentifier(), tag), selection, attr, baseURL());
if (dlg->exec())
{
dlg->insertTag(m_document, insertInLine);
}
delete dlg;
}
}
}
void QuantaView::insertOutputInTheNodeTree(const TQString &str1, const TQString &str2, Node *node)
{
if (!m_document)
return;
#ifdef LIGHT_DEBUG
if (node)
kdDebug(25001)<< "QuantaView::insertOutputInTheNodeTree() - node : " << node->tag->name <<
" - type : " << node->tag->type << endl;
else
kdDebug(25001)<< "QuantaView::insertOutputInTheNodeTree() - str1 : " << str1 <<
" - str2 : " << str2 << endl;
#endif
KafkaWidget *kafkaPart = m_kafkaDocument->getKafkaWidget();
NodeModifsSet *modifs;
DOM::Node domNode, domStartContainer, domEndContainer;
TQString tagName;
TQTag *nodeTQTag, *qTag, *nodeParentTQTag;
Node *nodeCursor, *startContainer, *endContainer, *nodeParent, *dummy;
TQPtrList<TQTag> qTagList;
int startCol, startLine, endCol, endLine;
bool specialTagInsertion = false;
long nodeOffset, startOffset, endOffset, domNodeOffset;
TQValueList<int> loc;
uint line, col;
bool smartTagInsertion, hasSelection, nodeTreeModified;
if (!node && str1.isEmpty() || node && !str1.isEmpty())
return;
//Three cases :
//- Tag insertion in VPL
//- Normal tag insertion in kate
//- Smart tag insertion in kate
smartTagInsertion = (m_currentFocus == QuantaView::SourceFocus && qConfig.smartTagInsertion);
if (m_currentFocus == QuantaView::VPLFocus || smartTagInsertion)
{
modifs = new NodeModifsSet();
if (!node && !str1.isEmpty())
{
//We build the node from the str1
node = kafkaCommon::createNode("", "", Tag::XmlTag, m_document);
node->tag->parse(str1, m_document);
node->tag->name = QuantaCommon::tagCase(node->tag->name);
node->tag->single = QuantaCommon::isSingleTag(m_document->defaultDTD()->name,
node->tag->name);
}
if (m_currentFocus == QuantaView::VPLFocus)
{
kafkaPart->getCurrentNode(domNode, domNodeOffset);
nodeCursor = m_kafkaDocument->getNode(domNode);
}
else
{
m_document->viewCursorIf->cursorPositionReal(&line, &col);
nodeCursor = parser->nodeAt(line, col, false);
}
if (!nodeCursor)
return;
nodeParent = nodeCursor;
if (nodeParent->tag->type == Tag::Text)
nodeParent = nodeParent->parent;
//Checking if at least one parent of node can have a Text Node as child, otherwise
//it is impossible for the
//user to add this node. In that case, try to insert the Node in the closest parent accepting it.
//e.g. TR : a normal insertion would require to have the caret in the TABLE Node, but it is
//impossible
nodeTQTag = QuantaCommon::tagFromDTD(m_document->defaultDTD(),
node->tag->name);
if (!nodeTQTag)
return;
qTagList = nodeTQTag->parents();
#ifdef HEAVY_DEBUG
kdDebug(25001)<< "nodeTQTag name : " << nodeTQTag->name() << endl;
/**kdDebug(25001)<< nodeTQTag->isChild("#text", false) << endl;
kdDebug(25001)<< nodeTQTag->isChild("#text", true) << endl;*/
#endif
for (qTag = qTagList.first(); qTag; qTag = qTagList.next())
{
if (qTag->isChild("#text", false))
break;
if (qTag == qTagList.getLast())
specialTagInsertion = true;
}
if (m_currentFocus == QuantaView::VPLFocus)
{
m_kafkaDocument->translateKafkaIntoNodeCursorPosition(domNode, domNodeOffset, &dummy, nodeOffset);
kafkaPart->selection(domStartContainer, startOffset, domEndContainer, endOffset);
m_kafkaDocument->translateKafkaIntoNodeCursorPosition(domStartContainer, startOffset,
&startContainer, startOffset);
m_kafkaDocument->translateKafkaIntoNodeCursorPosition(domEndContainer, endOffset,
&endContainer,endOffset);
hasSelection = kafkaPart->hasSelection();
}
else
if (m_document->selectionIfExt)
{
m_kafkaDocument->translateQuantaIntoNodeCursorPosition(line, col, &dummy, nodeOffset);
startCol = m_document->selectionIfExt->selStartCol();
startLine = m_document->selectionIfExt->selStartLine();
endCol = m_document->selectionIfExt->selEndCol();
endLine = m_document->selectionIfExt->selEndLine();
m_kafkaDocument->translateQuantaIntoNodeCursorPosition((unsigned)startLine, (unsigned)startCol,
&startContainer, startOffset);
m_kafkaDocument->translateQuantaIntoNodeCursorPosition((unsigned)endLine, (unsigned)endCol,
&endContainer, endOffset);
hasSelection = m_document->selectionIf->hasSelection();
if (startContainer == endContainer && startContainer->tag->type == Tag::Empty)
{
hasSelection = false;
}
if (endContainer && endContainer->tag->type == Tag::XmlTag && endOffset < (signed)endContainer->tag->tagStr().length())
{
endContainer = endContainer->previousSibling();
endOffset = (endContainer)?endContainer->tag->tagStr().length():0;
}
/**else
{
if (startContainer && startContainer->tag->type == Tag::Empty)
startContainer = startContainer->nextNE();
if (endContainer && endContainer->tag->type == Tag::Empty)
endContainer = endContainer->prevNE();
}*/
}
nodeTreeModified = false;
if (specialTagInsertion)
{
//let's try to insert this node in the closest parent accepting it.
while (nodeParent)
{
nodeParentTQTag =
QuantaCommon::tagFromDTD(m_document->defaultDTD(),
nodeParent->tag->name);
if (nodeParentTQTag && nodeParentTQTag->isChild(node))
{
nodeCursor = kafkaCommon::createMandatoryNodeSubtree(node,
m_document);
nodeOffset = 0;
kafkaCommon::insertNodeSubtree(node, nodeParent, 0L, 0L, modifs);
nodeTreeModified = true;
break;
}
nodeParent = nodeParent->parent;
}
}
else if (hasSelection && !nodeTQTag->isSingle())
{
//If some text is selected in kafka, surround the selection with the new Node.
if(!startContainer || !endContainer)
return;
nodeTreeModified = kafkaCommon::DTDinsertRemoveNode(node, startContainer, (int)startOffset,
endContainer, (int)endOffset, m_document, &nodeCursor,
nodeOffset, modifs);
}
else
{
//Nothing is selected, simply inserting the Node if it is not an inline.
/* if(!kafkaCommon::isInline(node->tag->name) || nodeTQTag->isSingle())
{*/
nodeTreeModified = kafkaCommon::DTDinsertRemoveNode(node, nodeCursor, (int)nodeOffset, nodeCursor,
(int)nodeOffset, m_document, &nodeCursor, nodeOffset, modifs);
// }
}
m_document->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif);
if (m_currentFocus == QuantaView::VPLFocus)
{
//view->reloadVPLView();
//Now update the VPL cursor position
m_kafkaDocument->translateNodeIntoKafkaCursorPosition(nodeCursor, nodeOffset, domNode,
domNodeOffset);
if (!domNode.isNull() && domNode.nodeType() != DOM::Node::TEXT_NODE &&
!domNode.firstChild().isNull() && domNode.firstChild().nodeType() ==
DOM::Node::TEXT_NODE)
domNode = domNode.firstChild();
if (!domNode.isNull())
kafkaPart->setCurrentNode(domNode, domNodeOffset);
}
else
{
//view->reloadSourceView();
//Now update the source cursor position
m_kafkaDocument->translateNodeIntoQuantaCursorPosition(nodeCursor, nodeOffset, line, col);
m_document->viewCursorIf->setCursorPositionReal(line, col);
}
if (!nodeTreeModified)
quantaApp->slotStatusMsg(i18n("Cannot insert the tag: invalid location."));
}
else
{
m_document->insertTag(str1, str2);
}
}
/** Returns the baseURL of the document. */
KURL QuantaView::baseURL()
{
KURL base;
if (m_document && !m_document->isUntitled() )
{
base = QuantaCommon::convertToPath(m_document->url());
} else
{
base = Project::ref()->projectBaseURL();
}
return base;
}
void QuantaView::refreshWindow()
{
if (!m_document)
{
if (m_plugin)
quantaApp->partManager()->setActivePart(m_plugin->part(), m_plugin->widget());
resize(width(), height());
} else
{
/*
kdDebug(24000) << "m_documentArea->height(): " << m_documentArea->height() << endl;
kdDebug(24000) << "ToolbarTabWidget::ref()->height(): " << ToolbarTabWidget::ref()->height() << " hidden: " << ToolbarTabWidget::ref()->isHidden() << " visible: " << ToolbarTabWidget::ref()->isVisible() << endl;
kdDebug(24000) <<"sum: " << m_documentArea->height() + ToolbarTabWidget::ref()->height() << endl;
kdDebug(24000) << "height(): " << height() << endl;
*/
if (m_documentArea->height() + ToolbarTabWidget::ref()->height() - 1 > height() && !ToolbarTabWidget::ref()->isHidden()) //don't use isVisible alone instead of isHidden!
resize(m_documentArea->width(), m_documentArea->height() - ToolbarTabWidget::ref()->height());
else if (ToolbarTabWidget::ref()->isHidden())
resize(width(), height());
}
}
void QuantaView::activated()
{
if (!m_document)
{
parser->setSAParserEnabled(false);
quantaApp->slotReloadStructTreeView();
refreshWindow();
return;
}
ToolbarTabWidget::ref()->reparent(this, 0, TQPoint(), qConfig.enableDTDToolbar);
m_viewLayout->addWidget(ToolbarTabWidget::ref(), 0 , 0);
quantaApp->partManager()->setActivePart(m_document->doc(), m_document->view());
m_document->checkDirtyStatus();
StructTreeView::ref()->useOpenLevelSetting = true;
quantaApp->slotLoadToolbarForDTD(m_document->getDTDIdentifier());
//TEMP : If the activated document is not a (X)HTML document, disable smartTagInsertion
//Will be removed when VPL will support every DTD
TDEAction *action = quantaApp->actionCollection()->action("smart_tag_insertion");
if(action && m_document->defaultDTD()->name.contains("HTML", false) == 0)
{
qConfig.smartTagInsertion = false;
(static_cast<TDEToggleAction* >(action))->setChecked(false);
}
reloadLayout();
refreshWindow();
}
void QuantaView::deactivated()
{
if (m_plugin)
{
quantaApp->statusBar()->changeItem("", IDS_STATUS);
}
m_sourceUpdateTimer.stop();
m_VPLUpdateTimer.stop();
}
bool QuantaView::saveModified(bool ask)
{
if (!m_document)
return true;
bool completed=true;
TQString fileName = m_document->url().fileName();
if (m_document->isModified() )
{
if (m_currentFocus == VPLFocus)
reloadSourceView();
int want_save;
if (ask)
want_save = KMessageBox::warningYesNoCancel(this,
i18n("The file \"%1\" has been modified.\nDo you want to save it?").arg(fileName),
i18n("Warning"), KStdGuiItem::save(), KStdGuiItem::discard());
else
want_save = KMessageBox::Yes;
switch (want_save)
{
case KMessageBox::Yes :
if (m_document->isUntitled())
{
completed = quantaApp->slotFileSaveAs(this);
}
else
{
completed = saveDocument(m_document->url());
};
break;
case KMessageBox::No :
{
m_document->removeBackup(quantaApp->config());
completed=true;
}
break;
case KMessageBox::Cancel :
completed=false;
break;
default:
completed=false;
break;
}
} else
m_document->removeBackup(quantaApp->config());
return completed;
}
bool QuantaView::saveDocument(const KURL& url)
{
if (url.isEmpty())
return false;
emit eventHappened("before_save", url.url(), TQString());
m_saveResult = true;
KURL oldURL = m_document->url();
if (!m_document->isUntitled() && oldURL.isLocalFile())
{
fileWatcher->removeFile(oldURL.path());
// kdDebug(24000) << "removeFile[saveDocument]: " << oldURL.path() << endl;
}
if (url.isLocalFile())
{
if (!m_document->saveAs(url))
{
fileWatcher->addFile(oldURL.path());
// kdDebug(24000) << "addFile[saveDocument]: " << oldURL.path() << endl;
return false; //saving to a local file failed
} else //successful saving to a local file
{
m_document->setDirtyStatus(false);
m_document->removeBackup(quantaApp->config());
fileWatcher->addFile(m_document->url().path());
// kdDebug(24000) << "addFile[saveDocument, 2]: " << m_document->url().path() << endl;
}
} else //saving to a remote file
{
KTextEditor::Document *doc = m_document->doc();
m_eventLoopStarted = false;
connect(doc, TQT_SIGNAL(canceled(const TQString &)), this, TQT_SLOT(slotSavingFailed(const TQString &)));
connect(doc, TQT_SIGNAL(completed()), this, TQT_SLOT(slotSavingCompleted()));
m_saveResult = m_document->saveAs(url);
if (m_saveResult)
{
//start an event loop and wait until the saving finished
QExtFileInfo internalFileInfo;
m_eventLoopStarted = true;
internalFileInfo.enter_loop();
}
disconnect(doc, TQT_SIGNAL(canceled(const TQString &)), this, TQT_SLOT(slotSavingFailed(const TQString &)));
disconnect(doc, TQT_SIGNAL(completed()), this, TQT_SLOT(slotSavingCompleted()));
if (!m_saveResult) //there was an error while saving
{
if (oldURL.isLocalFile())
{
fileWatcher->addFile(oldURL.path());
// kdDebug(24000) << "addFile[saveDocument, 3]: " << oldURL.path() << endl;
}
return false;
}
}
// everything went fine
if (oldURL != m_document->url())
{
setCaption(m_document->url().fileName());
}
emit eventHappened("after_save", m_document->url().url(), TQString());
return true;
}
void QuantaView::slotSavingFailed(const TQString &error)
{
Q_UNUSED(error);
m_saveResult = false;
if (m_eventLoopStarted)
tqApp->exit_loop();
}
void QuantaView::slotSavingCompleted()
{
m_saveResult = true;
m_document->setDirtyStatus(false);
m_document->removeBackup(quantaApp->config());
if (m_eventLoopStarted)
tqApp->exit_loop();
}
#include "quantaview.moc"