diff options
Diffstat (limited to 'quanta/treeviews')
38 files changed, 10021 insertions, 0 deletions
diff --git a/quanta/treeviews/Makefile.am b/quanta/treeviews/Makefile.am new file mode 100644 index 00000000..c32c617d --- /dev/null +++ b/quanta/treeviews/Makefile.am @@ -0,0 +1,24 @@ +noinst_LTLIBRARIES = libtreeviews.la + +METASOURCES = AUTO + +libtreeviews_la_SOURCES = uploadtreeview.cpp uploadtreefolder.cpp uploadtreefile.cpp fileinfodlg.ui quantapropertiespage.ui newtemplatedirdlg.cpp templatedirform.ui templatestreeview.cpp projecttreeview.cpp structtreeview.cpp doctreeview.cpp docitem.cpp docfolder.cpp structtreetag.cpp filestreeview.cpp tagattributetree.cpp tagattributeitems.cpp scripttreeview.cpp basetreeview.cpp servertreeview.cpp + +if include_cvsservice +CVSSERVICE_INCLUDE = -I$(top_srcdir)/quanta/components/cvsservice +endif + +AM_CPPFLAGS = -I$(top_srcdir)/quanta/utility \ + -I$(top_srcdir)/quanta/parsers \ + -I$(top_srcdir)/quanta/src \ + -I$(top_srcdir)/quanta/project \ + -I$(top_srcdir)/quanta/dialogs/tagdialogs \ + -I$(top_srcdir)/quanta/dialogs \ + -I$(top_srcdir)/quanta/messages \ + -I$(top_srcdir)/quanta/parts/kafka \ + -I$(top_srcdir)/quanta/components/csseditor \ + -I$(top_srcdir)/lib \ + -I$(top_builddir)/quanta/dialogs/tagdialogs \ + -I$(top_builddir)/quanta/components/csseditor \ + -I$(top_srcdir)/quanta/plugins \ + $(KMDI_INCLUDES) $(CVSSERVICE_INCLUDE) $(LIBXML_CFLAGS) $(LIBXSLT_CFLAGS) $(all_includes) diff --git a/quanta/treeviews/basetreeview.cpp b/quanta/treeviews/basetreeview.cpp new file mode 100644 index 00000000..8d8fad11 --- /dev/null +++ b/quanta/treeviews/basetreeview.cpp @@ -0,0 +1,1233 @@ +/*************************************************************************** + basetreeview.cpp - description + ------------------- + begin : Thu Jun 1 2000 + copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com> + (C) 2001-2004 Andras Mantia <amantoa@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. * + * * + ***************************************************************************/ + +// QT includes +#include <qeventloop.h> +#include <qlayout.h> +#include <qfileinfo.h> +#include <qlabel.h> +#include <qimage.h> +#include <qregexp.h> +#include <qclipboard.h> +#include <qpoint.h> +#include <qregexp.h> +#include <qlineedit.h> +#include <qfont.h> +#include <qpainter.h> +#include <qtooltip.h> +#include <qptrstack.h> + +// KDE includes +#include <kaction.h> +#include <kdebug.h> +#include <krun.h> +#include <kinputdialog.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kopenwith.h> +#include <kmessagebox.h> +#include <kpropertiesdialog.h> +#include <kfiledialog.h> +#include <kprogress.h> +#include <kstandarddirs.h> +#include <kurldrag.h> +#include <kurl.h> +#include <ktar.h> +#include <ktempfile.h> +#include <ktrader.h> +#include <kapplication.h> +#include <kcursor.h> +#include <kprotocolinfo.h> + +// app includes +#include "basetreeview.h" +#include "fileinfodlg.h" +#include "project.h" +#include "resource.h" +#include "quanta.h" +#include "qextfileinfo.h" +#include "viewmanager.h" +#include "quantanetaccess.h" +#include "quantaplugininterface.h" +#include "quantaplugin.h" + +#include <X11/Xlib.h> + +class BaseTreeViewToolTip : public QToolTip +{ +public: + BaseTreeViewToolTip( QWidget *parent, BaseTreeView *lv ); + + void maybeTip( const QPoint &pos ); + +private: + BaseTreeView *m_view; + +}; + +BaseTreeViewToolTip::BaseTreeViewToolTip( QWidget *parent, BaseTreeView *lv ) + : QToolTip( parent ), m_view( lv ) +{ +} + +void BaseTreeViewToolTip::maybeTip( const QPoint &pos ) +{ + if ( !parentWidget() || !m_view || !m_view->showToolTips() ) + return; + + QListViewItem *item = m_view->itemAt(pos); + if (!item) + return; + QString text; + KFileTreeViewItem * kftvi = dynamic_cast<BaseTreeViewItem *> (item); + if (kftvi) { + QString desc = kftvi->text(1); + text = kftvi->fileItem()->getToolTipText(); + if ( !desc.isEmpty() ) + text.prepend(" <i>" + desc + "</i><br>"); + } else + { // show something for the branchroot + text = item->text(0); + if ( ! item->text(1).isEmpty() ) + text.append( "<br>" + item->text(1)); + } + if ( !text.isEmpty() ) + tip(m_view->itemRect(item), text); +} + + +//BaseTreeViewItem implementation +BaseTreeViewItem::BaseTreeViewItem( KFileTreeViewItem *parent, KFileItem* item, KFileTreeBranch *brnch ) +: KFileTreeViewItem( parent, item, brnch) +{ +} + +QString BaseTreeViewItem::key(int column, bool ascending) const +{ + if (ascending) + if (isDir()) + return text(column).prepend(" "); + else + return text(column); + else + if (isDir()) + return text(column); + else + return text(column).prepend(" "); +} + +int BaseTreeViewItem::compare(QListViewItem *i, int col, + bool ascending) const +{ + return key(col, ascending).compare(i->key(col, ascending)); +} + +void BaseTreeViewItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int align) +{ + QColorGroup _cg( cg ); + if (column == 0) + { + QFont f = p->font(); + if (quantaApp) + f.setBold(ViewManager::ref()->isOpened(url())); + p->setFont(f); + } else + { + int h, s, v; + p->pen().color().getHsv(&h, &s, &v); + v = (v < 155 ? v + 100 : 255); + _cg.setColor(QColorGroup::Text, QColor(h, s, v, QColor::Hsv)); + }; + KFileTreeViewItem::paintCell( p, _cg, column, width, align ); +} + +void BaseTreeViewItem::refreshIcon() +{ + fileItem()->refreshMimeType(); +} + + +//BaseTreeBranch implementation +BaseTreeBranch::BaseTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden , + KFileTreeViewItem *branchRoot) + : KFileTreeBranch(parent, url, name, pix, showHidden, branchRoot) +{ + bool localFile = url.isLocalFile(); + setAutoUpdate(localFile); + setChildRecurse(false); + +} + +bool BaseTreeBranch::matchesFilter(const KFileItem *item) const +{ + if (!excludeFilterRx.isEmpty()) + if (excludeFilterRx.exactMatch(item->url().path())) + return false; + + return KFileTreeBranch::matchesFilter(item); +} + +KFileTreeViewItem* BaseTreeBranch::createTreeViewItem(KFileTreeViewItem *parent, + KFileItem *fileItem) +{ + BaseTreeViewItem *tvi = 0; + if( parent && fileItem) + { + tvi = new BaseTreeViewItem(parent, fileItem, this); + // we assume there are childs + if (tvi) + { + tvi->setExpandable(tvi->isDir()); + } + } + else + kdDebug(24000) << "createTreeViewItem: Have no parent" << endl; + return tvi; +} + + +void BaseTreeBranch::addOpenFolder(QStringList* openFolder) +{ + if (! openFolder) // just in case + return; + KFileTreeViewItem *newItem; + KFileTreeViewItem *item = root(); + while (item) { + if (item->isDir() && item->isOpen()) { + openFolder->append( item->url().url() ); + // dive into the tree first + newItem = dynamic_cast<KFileTreeViewItem *>(item->firstChild()); + if (newItem) { + // found child go ahead + item = newItem; + continue; + }; + }; + // move up in the tree + while (item && item != root()) + { + if (item->nextSibling()) + { + item = dynamic_cast<KFileTreeViewItem *>(item->nextSibling()); + break; + } + else + { + item = dynamic_cast<KFileTreeViewItem *>(item->parent()); + } + } + if (item == root()) + break; + }; +} + + +void BaseTreeBranch::reopenFolder() +{ + if (folderToOpen.isEmpty()) + return; + KFileTreeViewItem *item; + for (QStringList::Iterator it = folderToOpen.begin(); it != folderToOpen.end(); ++it) { + KURL url( (*it) ); + item = findTVIByURL(url); + if (item) { + // erase the url in the list + (*it) = ""; + // open the folder + item->setExpandable(true); + item->setOpen(true); + } + } +} + + +void BaseTreeBranch::updateOpenFolder() +{ + KFileTreeViewItem *newItem; + KFileTreeViewItem *item = root(); + while (item) { + if (item->isDir() && item->isOpen()) { + updateDirectory( item->url() ); + kapp->processEvents(QEventLoop::ExcludeUserInput | QEventLoop::ExcludeSocketNotifiers); + // dive into the tree first + newItem = dynamic_cast<KFileTreeViewItem *>(item->firstChild()); + if (newItem) { + // found child go ahead + item = newItem; + continue; + }; + }; + // go up if no sibling available + if (! item->nextSibling()) + item = dynamic_cast<KFileTreeViewItem *>(item->parent()); + if (item == root()) + break; + if (item) + item = dynamic_cast<KFileTreeViewItem *>(item->nextSibling()); + }; +} + + +//////////////////////////////////////////////////////////////////////////////////// +// +// BaseTreeView implementation +// +//////////////////////////////////////////////////////////////////////////////////// + +BaseTreeView::BaseTreeView(QWidget *parent, const char *name) +: KFileTreeView(parent, name), fileInfoDlg(0), m_saveOpenFolder(false), m_openWithMenu(0L), m_openWithMenuId(-1) +{ + m_parent = parent; + QToolTip::remove(viewport()); // remove the tooltip from QListView + m_tooltip = new BaseTreeViewToolTip(viewport(), this); + setFrameStyle( Panel | Sunken ); + setRootIsDecorated(true); + setSorting(0); + setLineWidth(2); + setFullWidth(true); + setShowSortIndicator(true); + setFocusPolicy(QWidget::ClickFocus); + setShowFolderOpenPixmap(false); + + connect(this, SIGNAL(returnPressed(QListViewItem *)), + this, SLOT(slotReturnPressed(QListViewItem *))); + + connect(this, SIGNAL(dropped(QWidget *, QDropEvent *, KURL::List&, KURL&)), + this, SLOT(slotDropped(QWidget *, QDropEvent *, KURL::List&, KURL&))); + + connect(this, SIGNAL(itemRenamed(QListViewItem*, const QString &, int )), + this, SLOT(slotRenameItem(QListViewItem*, const QString &, int ))); + + connect(this, SIGNAL(executed(QListViewItem *)), + this, SLOT(slotSelectFile(QListViewItem *))); + + connect(this, SIGNAL(openFile(const KURL &)), + quantaApp, SLOT(slotFileOpen(const KURL &))); + + connect(this, SIGNAL(openImage(const KURL &)), + quantaApp, SLOT(slotImageOpen(const KURL &))); + + connect(this, SIGNAL(closeFile(const KURL &)), + quantaApp, SLOT(slotFileClose(const KURL &))); + + connect(this, SIGNAL(insertTag(const KURL &, DirInfo)), + quantaApp, SLOT(slotInsertTag(const KURL &, DirInfo))); +} + + +BaseTreeView::~BaseTreeView() +{ + QToolTip::remove(viewport()); + delete m_tooltip; +} + + +void BaseTreeView::itemRenamed(const KURL& oldURL, const KURL& newURL) +{ + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if (! curItem) return; + + if (curItem->isDir()) + { + KURL n = newURL; + n.adjustPath(1); + KURL o = oldURL; + o.adjustPath(1); + emit renamed(o, n); + } + else + { + emit renamed(oldURL, newURL); + } +} + + +/** Called for: double click, return, Open */ +void BaseTreeView::slotSelectFile(QListViewItem *item) +{ + KFileTreeViewItem* kftvi = currentKFileTreeViewItem(); + if (!kftvi || kftvi->isDir()) return; + + KURL urlToOpen = kftvi->url(); + if (!urlToOpen.isEmpty()) + { + if ( QuantaCommon::checkMimeGroup(urlToOpen,"text") ) + { + emit openFile(urlToOpen); + item->repaint(); + } + else if ( QuantaCommon::checkMimeGroup(urlToOpen, "image") ) //it may be an image + { + emit openImage( urlToOpen); + } + else if ( expandArchiv(kftvi)) //it may be an archiv + { + } + else //it is an unknown type, maybe binary + { + if (QuantaCommon::denyBinaryInsert(this) == KMessageBox::Yes) + { + emit openFile(urlToOpen); + item->repaint(); + } + } + } +} + + +/** expands an archiv, if possible */ +bool BaseTreeView::expandArchiv (KFileTreeViewItem *item) +{ + if (!item) return false; + KURL urlToOpen = item->url(); + + if ( ! urlToOpen.isLocalFile()) return false; + + QString mimeType = KMimeType::findByURL(urlToOpen)->name(); + + if ( mimeType == "application/x-tgz" || + mimeType == "application/x-tbz" || + mimeType == "application/x-tar" ) //it is an archiv + urlToOpen.setProtocol("tar"); + else + if ( mimeType == "application/x-zip" ) //it is an archiv + urlToOpen.setProtocol("zip"); + else + return false; + + // change status if there is already a sub branch + if (item->isExpandable()) { + item->setOpen( ! item->isOpen()); + return true; + }; + + KFileTreeBranch *kftb = new BaseTreeBranch(this, urlToOpen, item->text(0), *(item->pixmap(0)), true, item); + addBranch(kftb); // connecting some signals + kftb->populate(urlToOpen, item); + item->setExpandable(true); + item->setOpen(true); + return true; +} + + +/** Properties dialog addon*/ +FileInfoDlg* BaseTreeView::addFileInfoPage(KPropertiesDialog* propDlg) +{ + //If the item is a file, add the Quanta file info page + FileInfoDlg *quantaFileProperties = 0L; + if ( !currentKFileTreeViewItem()->isDir() ) + { + + QFrame *quantaFilePage = propDlg->addPage(i18n("Quanta File Info")); + QVBoxLayout *topLayout = new QVBoxLayout( quantaFilePage); + quantaFileProperties = new FileInfoDlg( quantaFilePage, i18n("Quanta") ); + + int fsize,fimgsize=0; + int ct=0,imgct=0,position=0; + KURL u = currentURL(); + if (u.isLocalFile()) //get the file info only for local file. TODO: for non-local ones + { + QString nameForInfo = u.path(); + QString path =u.directory(0,0); //extract path for images + QString sourcename=u.fileName(0); + + QFile qfile(nameForInfo); + fsize=qfile.size(); //html file size + + QString mimetype = KMimeType::findByFileContent(nameForInfo)->name(); + if (mimetype.contains("text")) + { + qfile.open(IO_ReadOnly); + QString imgname,imgpath; + QTextStream stream(&qfile); + stream.setEncoding(QTextStream::UnicodeUTF8); + while (!stream.atEnd()) //open & parse file + { + imgname = stream.readLine(); + ct++; + position=imgname.find("<img",0,false); //check for images + if (position!=-1) + { + imgname.remove(0,position+4); + position=imgname.find("src=",0,false); //extract images names + imgname.remove(0,position+4); + if (imgname.startsWith("\"")) imgname.remove(0,1); + if (imgname.startsWith("'")) imgname.remove(0,1); + position=imgname.find(" ",0,false); + if (position!=-1) imgname=imgname.left(position); + position=imgname.find(">",0,false); + if (position!=-1) imgname=imgname.left(position); + position=imgname.find("\"",0,false); + if (position!=-1) imgname=imgname.left(position); + position=imgname.find("'",0,false); + if (position!=-1) imgname=imgname.left(position); + if (!quantaFileProperties->imageList->findItem(imgname,Qt::ExactMatch)) //check if image was already counted + { + KURL v(KURL::fromPathOrURL( path ),imgname); + imgpath=v.path(); + QFile qimage(imgpath); + if (qimage.exists() && v.isLocalFile()) + { + fimgsize+=qimage.size(); + quantaFileProperties->imageList->insertItem(imgname); + imgct++; + } + } + } + } + qfile.close(); + + quantaFileProperties->lineNum->setText(i18n("Number of lines: %1").arg(ct)); + quantaFileProperties->imageNum->setText(i18n("Number of images included: %1").arg(imgct)); + quantaFileProperties->imageSize->setText(i18n("Size of the included images: %1 bytes").arg(fimgsize)); + quantaFileProperties->totalSize->setText(i18n("Total size with images: %1 bytes").arg(fsize+fimgsize)); + } + else if (mimetype.contains("image")) + { // assume it's an image file + QImage imagefile=QImage(nameForInfo); + quantaFileProperties->lineNum->setText(i18n("Image size: %1 x %2").arg(imagefile.width()).arg(imagefile.height())); + quantaFileProperties->imageNum->hide(); + quantaFileProperties->imageSize->hide(); + quantaFileProperties->totalSize->hide(); + quantaFileProperties->includedLabel->hide(); + quantaFileProperties->imageList->hide(); + } + quantaFileProperties->fileDescLbl->setText(i18n("Description:")); + quantaFileProperties->fileDesc->setText(currentKFileTreeViewItem()->text(1)); + // disable per default + quantaFileProperties->fileDescLbl->hide(); + quantaFileProperties->fileDesc->hide(); + topLayout->addWidget(quantaFileProperties); + } //if localfile + } + return quantaFileProperties; +} + + +void BaseTreeView::slotClose() +{ + if (currentItem()) + { + emit closeFile(currentURL()); + } +} + + +void BaseTreeView::slotOpen() +{ + QListViewItem *item = currentItem(); + if (item) + { + emit open(item); + item->repaint(); + } +} + + +void BaseTreeView::slotOpenWith() +{ + if (currentItem()) + { + KURL::List list; + KURL urlToOpen = currentURL(); + list.append( urlToOpen ); + KRun::displayOpenWithDialog( list ); + } +} + +void BaseTreeView::slotOpenWithApplication() +{ + KService::Ptr ptr = KService::serviceByDesktopPath(sender()->name()); + if (ptr) + { + KURL::List list; + list << currentURL(); + KRun::run(*ptr, list); + } +} + +void BaseTreeView::slotOpenWithActivated(int id) +{ + if (m_pluginIds.contains(id)) + { + QuantaPlugin *plugin = m_pluginIds[id]; + plugin->unload(true); + if (plugin->load()) + { + int input = plugin->input(); + plugin->setInput(-1); //disable input + plugin->run(); + if (plugin->part()) + plugin->part()->openURL(currentURL()); + plugin->setInput(input); + } + } +} + +void BaseTreeView::insertOpenWithMenu(KPopupMenu *menu, int position) +{ + if (m_openWithMenuId != -1) + menu->removeItem(m_openWithMenuId); + for (uint i = 0; i < m_openWithActions.count(); i++) + { + KAction *action = m_openWithActions[i]; + delete action; + } + m_openWithActions.clear(); + KURL urlToOpen = currentURL(); + QString mimeType = KMimeType::findByURL(urlToOpen, 0, true, true)->name(); + KTrader::OfferList offers = KTrader::self()->query(mimeType, "Type == 'Application'"); + QDict<QuantaPlugin> plugins = QuantaPluginInterface::ref()->plugins(); + m_pluginIds.clear(); + + if (offers.count() > 0 || plugins.count() > 0) + { + m_openWithMenu = new KPopupMenu(this); + if (offers.count() > 0) + { + KTrader::OfferList::Iterator it; + for (it = offers.begin(); it != offers.end(); ++it) + { + KAction *action = new KAction((*it)->name(), (*it)->icon(), 0, 0, QFile::encodeName((*it)->desktopEntryPath()).data()); + connect(action, SIGNAL(activated()), this, SLOT(slotOpenWithApplication())); + action->plug(m_openWithMenu); + m_openWithActions.append(action); + } + m_openWithMenu->insertSeparator(); + } + if (plugins.count() > 0) + { + m_openWithMenu->insertTitle(i18n("Plugins")); + QDictIterator<QuantaPlugin> it2(plugins); + for(;it2.current();++it2) + { + int id = m_openWithMenu->insertItem(KGlobal::iconLoader()->loadIconSet(it2.current()->icon(),KIcon::Small), it2.current()->name()); + m_pluginIds[id] = it2.current(); + } + connect(m_openWithMenu, SIGNAL(activated(int)), SLOT(slotOpenWithActivated(int))); + m_openWithMenu->insertSeparator(); + } + m_openWithMenu->insertItem(i18n("&Other..."), this, SLOT(slotOpenWith())); + m_openWithMenuId = menu->insertItem(i18n("Open &With"), m_openWithMenu, -1, position); + } else + m_openWithMenuId = menu->insertItem(i18n("Open &With..."), this, SLOT(slotOpenWith()), 0, -1, position); +} + +void BaseTreeView::slotInsertTag() +{ + if (currentItem() ) + { + DirInfo dirInfo; + + dirInfo.mimeType = ""; + dirInfo.preText = ""; + dirInfo.postText = ""; + emit insertTag( currentURL(), dirInfo ); + } +} + + +void BaseTreeView::slotCopy() +{ + if (currentItem()) + { + QClipboard *cb = QApplication::clipboard(); + cb->setText( currentURL().prettyURL() ); + } +} + + +void BaseTreeView::slotPaste() +{ + if (currentItem()) + { + QClipboard *cb = QApplication::clipboard(); + KURL::List list( QStringList::split( QChar('\n'), cb->text() ) ); + + KURL url = currentURL(); + if ( ! currentKFileTreeViewItem()->isDir() ) + url.setFileName(""); // don't paste on files but in dirs + QuantaNetAccess::dircopy(list, url, m_parent, true); + } +} + + +void BaseTreeView::slotPercent(KIO::Job *job, unsigned long value) +{ + Q_UNUSED(job); + progressBar->setProgress(value); +} + + +void BaseTreeView::slotDelete() +{ + if (!currentKFileTreeViewItem()) return; + KURL url = currentURL(); + if (currentKFileTreeViewItem()->isDir()) + url.adjustPath(+1); + QuantaNetAccess::del(url, m_parent, true); +} + + +void BaseTreeView::slotPopulateFinished(KFileTreeViewItem *item) +{ + progressBar->setTotalSteps(1); + progressBar->setProgress(-1); + progressBar->setTextEnabled(false); + + if ( !item ) return; + + if( item->isDir() ) + stopAnimation( item ); + + if (item->childCount() == 0) { + item->setOpen(false); + item->setExpandable(false); + } else { + QString url = item->url().url(); + BaseTreeBranch *btb = dynamic_cast<BaseTreeBranch *>(item->branch()); + if (btb && ! btb->folderToOpen.empty()) { + btb->reopenFolder(); + } + } +} + + +void BaseTreeView::slotInsertInProject() +{ + if (currentItem() ) + { + emit insertFileInProject( currentURL()); + } +} + + +void BaseTreeView::slotInsertDirInProject() +{ + if ( currentItem() ) + { + emit insertDirInProject( currentURL() ); + } +} + + +/** Bring up the properites dialog, and extend it for files */ +void BaseTreeView::slotProperties() +{ + if (! currentKFileTreeViewItem()) + return; + + propDlg = new KPropertiesDialog(currentKFileTreeViewItem()->fileItem(), this, 0L, false, false); //autodeletes itself + fileInfoDlg = 0L; + if (!currentKFileTreeViewItem()->isDir()) + { + fileInfoDlg = addFileInfoPage(propDlg); + } + connect(propDlg, SIGNAL( applied() ), this, SLOT( slotPropertiesApplied()) ); + propDlg->exec(); +} + + +void BaseTreeView::slotPropertiesApplied() +{ + if (! propDlg) return; + // check if renamed + KURL url = currentURL(); + if (url != propDlg->kurl()) + { + itemRenamed(url, propDlg->kurl()); + } + KFileTreeViewItem *kftvi = currentKFileTreeViewItem(); + if (fileInfoDlg && kftvi) + { + // has description changed? + QString newDesc = fileInfoDlg->fileDesc->text(); + if (kftvi->text(1) != newDesc) + itemDescChanged(kftvi, newDesc); + } + BaseTreeViewItem * btvi = dynamic_cast<BaseTreeViewItem *> (kftvi); + if (btvi) + { + btvi->refreshIcon(); + } +/* not working as expected + if (kftvi && kftvi->url().isLocalFile()) { + slotReloadAllTrees(); // refresh the icons for local url's, they might have changed + }*/ +} + + +void BaseTreeView::slotReloadAllTrees() +{ + QPtrStack<BaseTreeBranch> stack; + BaseTreeBranch *btb; + KFileTreeBranchIterator it( branches() ); + for ( ; it.current(); ++it) + { + btb = dynamic_cast<BaseTreeBranch *>( (*it) ); + if (btb && btb->rootUrl().isLocalFile()) { + stack.push(btb); + } + } + while (! stack.isEmpty()) + { + reload(stack.pop()); + } +} + + +void BaseTreeView::slotReload() +{ + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if (curItem) + reload(dynamic_cast<BaseTreeBranch *>(curItem->branch())); +} + + +void BaseTreeView::reload(BaseTreeBranch *btb) +{ + // remember the old status + QStringList folderToOpen; + btb->addOpenFolder(&folderToOpen); + KURL url = btb->rootUrl(); + // remove and open again + removeBranch(btb); + btb = dynamic_cast<BaseTreeBranch *>(newBranch(url)); + if (btb) { + btb->folderToOpen = folderToOpen; + btb->reopenFolder(); + btb->updateOpenFolder(); + } +} + + +void BaseTreeView::slotJobFinished(KIO::Job *job) +{ + if ( job->error() ) + job->showErrorDialog(this); + + progressBar->setTotalSteps(1); + progressBar->setProgress(-1); + progressBar->setTextEnabled(false); +} + + +void BaseTreeView::slotReturnPressed(QListViewItem *item) +{ + emit executed(item); +} + + +bool BaseTreeView::acceptDrag(QDropEvent* e ) const +{ + QPoint p (contentsToViewport(e->pos())); + QListViewItem *atpos = itemAt(p); + KFileTreeViewItem *kftvi = dynamic_cast <KFileTreeViewItem *> (atpos); + if (kftvi) + return (KFileTreeView::acceptDrag(e) && kftvi->isDir()); // accept only on folders + else + return (KFileTreeView::acceptDrag(e)); +} + + +void BaseTreeView::slotDropped (QWidget *, QDropEvent * /*e*/, KURL::List& fileList, KURL& dest) +{ + if(fileList.empty()) + return; + + // Check what the destination can do + if (!KProtocolInfo::supportsWriting(dest)) + return; + bool sLinking = KProtocolInfo::supportsLinking(dest); + + // Check what the source can do + KURL url = fileList.first(); // we'll assume it's the same for all URLs (hack) + bool sReading = KProtocolInfo::supportsReading(url); + bool sDeleting = KProtocolInfo::supportsDeleting(url); + bool sMoving = KProtocolInfo::supportsMoving(url); + + // Check the state of the modifiers key at the time of the drop + Window root; + Window child; + int root_x, root_y, win_x, win_y; + uint keybstate; + XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, + &root_x, &root_y, &win_x, &win_y, &keybstate ); + + int result; + if (keybstate & ControlMask) { + result = 1; // copy + } else { + if (keybstate & ShiftMask) { + result = 2; // move + } else { + + // create the popup menu + QPopupMenu popup; + if (sMoving || (sReading && sDeleting)) + popup.insertItem(SmallIconSet("goto"), i18n("&Move Here"), 2 ); + if (sReading) + popup.insertItem(SmallIconSet("editcopy"), i18n("&Copy Here"), 1 ); + if (sLinking) + popup.insertItem(SmallIconSet("www"), i18n("&Link Here"), 3 ); + popup.insertSeparator(); + popup.insertItem(SmallIconSet("cancel"), i18n("C&ancel"), 5); + + result = popup.exec( QCursor::pos() ); + } + } + bool tooltip = showToolTips(); + KIO::Job *job; + switch ( result ) { + case 1 : setShowToolTips(false); + setDragEnabled(false); + QuantaNetAccess::dircopy(fileList, dest, m_parent, true); + setDragEnabled(true); + setShowToolTips(tooltip); + return; + case 2 : setShowToolTips(false); + setDragEnabled(false); + QuantaNetAccess::move(fileList, dest, m_parent, true); + setDragEnabled(true); + setShowToolTips(tooltip); + return; + case 3 : job = KIO::link(fileList, dest); + break; + default : return ; + } + if (!job) + return; + + connect(job, SIGNAL( result(KIO::Job *) ), + this, SLOT( slotJobFinished(KIO::Job *) ) ); + progressBar->setTotalSteps(100); + connect(job, SIGNAL(percent( KIO::Job *, unsigned long)), + this, SLOT(slotPercent( KIO::Job *, unsigned long))); +} + + +void BaseTreeView::findDrop(const QPoint &pos, QListViewItem *&parent, QListViewItem *&after) +{ + QPoint p (contentsToViewport(pos)); + QListViewItem *atpos = itemAt(p); +// if (atpos && atpos->parent()) { +// after = atpos; +// parent = atpos->parent(); +// } else { + after = atpos; + parent = atpos; +// } +} + + +void BaseTreeView::slotNewProjectLoaded(const QString &name, const KURL &baseURL, const KURL &) +{ + m_projectName = name; + m_projectBaseURL = baseURL; +} + + +bool BaseTreeView::isFileOpen(const KURL &url) +{ + return ViewManager::ref()->isOpened(url); +} + + +bool BaseTreeView::isPathInClipboard() +{ + QClipboard *cb = QApplication::clipboard(); + KURL::List list( QStringList::split( QChar('\n'), cb->text() ) ); + for ( KURL::List::Iterator it = list.begin(); it != list.end(); ++it ) + { + if ( !(*it).isValid() ) + return false; + } + return true; +} + + +void BaseTreeView::slotDocumentClosed(const KURL& url) +{ + KFileTreeViewItem * item; + KFileTreeBranchIterator it( branches() ); + for ( ; it.current(); ++it) + { + item = (*it)->findTVIByURL(url); + if (item) + { + item->repaint(); + } + } +/* QListViewItemIterator iter(this); + for ( ; iter.current(); ++iter ) + { + iter.current()->repaint(); + }*/ +} + + +void BaseTreeView::slotStartRename() +{ + KFileTreeViewItem * item = currentKFileTreeViewItem(); + if (item) { + setRenameable(0, true); + rename(item, 0); + }; +} + + +void BaseTreeView::cancelRename(int col) +{ + // reset the inline rename option for file/folder name + if (col == 0) { + setRenameable(0, false); + } +} + + +void BaseTreeView::slotRenameItem(QListViewItem* item, const QString & newText, int col) +{ + if (!item) + return; + + // reset the inline rename option for file/folder name + if (col == 0) { + setRenameable(0, false); + KFileTreeViewItem * kvtvi = dynamic_cast<KFileTreeViewItem *>(item); + if (kvtvi) + doRename(kvtvi, newText); + } +} + + +void BaseTreeView::doRename(KFileTreeViewItem* kftvi, const QString & newName) +{ + if (! kftvi) + return; + + KURL oldURL = kftvi->url(); + KURL newURL = oldURL; + + if (kftvi->isDir()) + { + newURL.setPath(QFileInfo(oldURL.path(-1)).dirPath() + '/' + newName + '/'); + oldURL.adjustPath(1); + } else + { + newURL.setFileName(newName); + } + if ( oldURL != newURL ) + { + bool proceed = true; + if (QExtFileInfo::exists(newURL, false, this)) + { + proceed = KMessageBox::warningContinueCancel(this, i18n("<qt>The file <b>%1</b> already exists.<br>Do you want to overwrite it?</qt>").arg(newURL.prettyURL(0, KURL::StripFileProtocol)),i18n("Overwrite"), i18n("Overwrite")) == KMessageBox::Continue; + } + if (proceed) + { + //start the rename job + oldURL.adjustPath(-1); + newURL.adjustPath(-1); + if (!QuantaNetAccess::file_move(oldURL, newURL, -1, true, false, m_parent, true)) + { + kftvi->setText(0, kftvi->fileItem()->text()); // reset the text + } + } else + { + kftvi->setText(0, kftvi->fileItem()->text()); // reset the text + } + } +} + + +void BaseTreeView::saveLayout(KConfig *config, const QString &group) +{ + KListView::saveLayout(config, group); + if (! m_saveOpenFolder || ! qConfig.saveTrees) + return; + + KConfigGroupSaver saver(config, group); + BaseTreeBranch *btb; + int i = 0; + KFileTreeBranchIterator it( branches() ); + for ( ; it.current(); ++it) + { + btb = dynamic_cast<BaseTreeBranch *>( (*it) ); + if (btb && btb->rootUrl().isLocalFile()) { + ++i; + QStringList folderList; + // remember the root url so that I find the branch on restore + folderList.append(btb->rootUrl().url()); + btb->addOpenFolder(&folderList); + config->writePathEntry("OpenFolderList" + QString::number(i), folderList); + } + } + config->writeEntry("NumOpenFolderList", i); +} + + +void BaseTreeView::restoreLayout(KConfig *config, const QString &group) +{ + KListView::restoreLayout(config, group); + KConfigGroupSaver saver(config, group); + setShowToolTips( config->readBoolEntry("ShowToolTips", true) ); + + if (! m_saveOpenFolder || ! qConfig.saveTrees) + return; + + BaseTreeBranch *btb; + KFileTreeBranchIterator it( branches() ); + int maxBranch = config->readNumEntry("NumOpenFolderList", 0); + for (int i = 1; i <= maxBranch; ++i) + { + QStringList folderList = QuantaCommon::readPathListEntry(config, "OpenFolderList" + QString::number(i)); + if (folderList.count() > 1) { + KURL rootURL = (*folderList.begin()); + folderList.remove(folderList.begin()); // remove the root URL + KFileTreeBranchIterator it( branches() ); + for ( ; it.current(); ++it) + { + if ((*it)->rootUrl() == rootURL) { + btb = dynamic_cast<BaseTreeBranch *>( (*it) ); + if (btb) { + btb->folderToOpen = folderList; + btb->reopenFolder(); + break; + } + } + } + } + } +} + + +void BaseTreeView::slotCreateSiteTemplate() +{ + QString startDir; + if (Project::ref()->hasProject()) + { + startDir = Project::ref()->templateURL().url(); + } else + { + startDir = locateLocal("data", resourceDir + "templates/"); + } + KURL targetURL; + bool valid; + do { + valid = false; + targetURL = KFileDialog::getSaveURL(startDir, "*.tgz", this, i18n("Create Site Template File")); + if (targetURL.isEmpty()) + return; + if (targetURL.url().startsWith(KURL::fromPathOrURL(locateLocal("data", resourceDir + "templates/")).url())) + valid = true; + if (Project::ref()->hasProject() && targetURL.url().startsWith(Project::ref()->templateURL().url())) + valid = true; + if (!valid) + KMessageBox::error(this, i18n("Templates should be saved to the local or project template folder.")); + }while (!valid); + + KURL url = currentURL(); + //TODO: Implement creation from remote folders as well. Requires downloading of the files to a + //temporary directory + if (url.protocol() != "file") + { + KMessageBox::sorry(this, i18n("Currently you can create site templates only from local folders."), i18n("Unsupported Feature")); + return; + } + + KTempFile *tempFile = new KTempFile(tmpDir); + tempFile->setAutoDelete(true); + tempFile->close(); + KTar tar(tempFile->name(), "application/x-gzip"); + bool error = false; + if (tar.open(IO_WriteOnly)) + { + KURL::List fileList = QExtFileInfo::allFiles(url, "*", this); + for (KURL::List::Iterator it = fileList.begin(); it != fileList.end(); ++it) + { + if (!(*it).path().endsWith("/")) + { + QFile f((*it).path()); + if (f.open(IO_ReadOnly)) + { + QByteArray buffer(f.readAll()); + if (!tar.writeFile((*it).path().remove(url.path()), "user", "group", buffer.size(), buffer.data())) + { + error = true; + } + f.close(); + } else + error = true; + } + } + tar.close(); + } else + error = true; + if (!QuantaNetAccess::copy(KURL::fromPathOrURL(tempFile->name()), targetURL, m_parent, false)) + error = true; + + if (error) + KMessageBox::error(this, i18n("<qt>There was an error while creating the site template tarball.<br>Check that you can read the files from <i>%1</i>, you have write access to <i>%2</i> and that you have enough free space in your temporary folder.</qt>").arg(url.prettyURL(0, KURL::StripFileProtocol)).arg(targetURL.prettyURL(0, KURL::StripFileProtocol)), i18n("Template Creation Error")); + delete tempFile; +} + +void BaseTreeView::slotCreateFolder() +{ + bool ok; + QString folderName = KInputDialog::getText(i18n("Create New Folder"), i18n("Folder name:"), "", &ok, this); + if (ok) + { + KURL url = currentURL(); + if (currentKFileTreeViewItem()->isDir()) + url.setPath(url.path() + "/" + folderName + "/"); + else + url.setPath(url.directory() + "/" + folderName +"/"); + QuantaNetAccess::mkdir(url, this, -1); + } +} + +void BaseTreeView::slotCreateFile() +{ + bool ok; + QString fileName = KInputDialog::getText(i18n("Create New File"), i18n("File name:"), "", &ok, this); + if (ok) + { + KURL url = currentURL(); + if (currentKFileTreeViewItem()->isDir()) + url.setPath(url.path() + "/" + fileName); + else + url.setPath(url.directory() + "/" + fileName); + if (QExtFileInfo::exists(url, false, this)) + { + KMessageBox::error(this, i18n("<qt>Cannot create file, because a file named <b>%1</b> already exists.</qt>").arg(fileName), i18n("Error Creating File")); + return; + } + KTempFile *tempFile = new KTempFile(tmpDir); + tempFile->setAutoDelete(true); + tempFile->close(); + if (QuantaNetAccess::copy(KURL::fromPathOrURL(tempFile->name()), url, this)) + { + emit openFile(url); + } + delete tempFile; + } +} + +#include "basetreeview.moc" diff --git a/quanta/treeviews/basetreeview.h b/quanta/treeviews/basetreeview.h new file mode 100644 index 00000000..345b5a79 --- /dev/null +++ b/quanta/treeviews/basetreeview.h @@ -0,0 +1,362 @@ +/*************************************************************************** + BaseTreeView.h - description + ------------------- + begin : Thu Jun 1 2000 + copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com> + (C) 2001-2004 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. * + * * + ***************************************************************************/ + +#ifndef BASETREEVIEW_H +#define BASETREEVIEW_H + +//qt includes +#include <qvaluelist.h> + +//kde includes +#include <kfiletreebranch.h> +#include <kfiletreeview.h> +#include <kfiletreeviewitem.h> + +// quanta includes +#include "quantacommon.h" + +//foward declarations +class QListViewItem; +class QString; +class QPixmap; +class QPoint; +class QRegExp; +class QCloseEvent; + +class KAction; +class KFileItem; +class KPopupMenu; +class KPropertiesDialog; +class KURL; +class FileInfoDlg; +class BaseTreeViewToolTip; +class QuantaPlugin; + +/** + * @short a KFileTreeViewItem with some specials. + * + * @author Jens Herden <jens@kdewebdev.org> + */ +class BaseTreeViewItem : public KFileTreeViewItem { + +public: + BaseTreeViewItem( KFileTreeViewItem *parent, KFileItem* item, KFileTreeBranch *brnch ); + + /** + sorts folders separate from files + */ + QString key (int column, bool ascending) const; + + /** + makes compare independent from locale + */ + int compare( QListViewItem *i, int col, bool ascending ) const; + + /** + makes open files bold and the second column lighter + */ + void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align); + + /** + refresh icon + */ + void refreshIcon(); +}; + +/** + * @short a KFileTreeBranch that uses @ref BaseTreeViewItem and does some special filtering. + * + * @author Jens Herden <jens@kdewebdev.org> + */ +class BaseTreeBranch : public KFileTreeBranch { + Q_OBJECT + +public: + BaseTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden = false, KFileTreeViewItem *branchRoot = 0); + /** + get the BaseTreeViewItem + */ + virtual KFileTreeViewItem* createTreeViewItem( KFileTreeViewItem *parent, + KFileItem *fileItem ); + /** + does custom filtering + */ + bool matchesFilter(const KFileItem *item) const; + + /** + files matching to this will not be shown + */ + QRegExp excludeFilterRx; + + /** + adds the current open folders of the branch to a stringslist. + Attention: no check for double entries is done + + @param openFolder the list where to add the URL strings + */ + void addOpenFolder(QStringList *openFolder); + + /** opens the next folder in @ref folderToOpen */ + void reopenFolder(); + + /** list of folders to open */ + QStringList folderToOpen; + + /** inform the dirwatcher to update all open folders */ + void updateOpenFolder(); + +}; + + +/** + * @short the base class for many of Quantas treeviews + * + * @ref FilesTreeView, @ref ScriptTreeView, @ref ProjectTreeView and + * @ref TemplatesTreeView use this class. + * + */ +class BaseTreeView : public KFileTreeView { + Q_OBJECT + +public: + BaseTreeView(QWidget *parent = 0L, const char *name = 0L); + virtual ~BaseTreeView(); + + /** + * Saves the list view's layout (column widtsh, column order, sort column) + * to a KConfig group. Reimplemented to save the open folders. + * + * @param config the KConfig object to write to + * @param group the config group to use + */ + void saveLayout(KConfig *config, const QString &group); + + /** + * Reads the list view's layout from a KConfig group as stored with + * saveLayout. Reimplemented to load the open folders. + * + * @param config the KConfig object to read from + * @param group the config group to use + */ + void restoreLayout(KConfig *config, const QString &group); + + /** + * en/disable saving a list of open folders in @ref saveLayout and + * restoring the tree status in @ref restoreLayout + */ + void setSaveOpenFolder(bool b = true) { m_saveOpenFolder = b; }; + + /** reads property @ref setSaveOpenFolder */ + bool saveOpenFolder() { return m_saveOpenFolder; }; + +public slots: + /** + sets new project information + */ + void slotNewProjectLoaded(const QString &, const KURL &, const KURL &); + /** + repaints all treeview items + */ + void slotDocumentClosed(const KURL& url); + +protected slots: + + void slotCopy(); + void slotPaste(); + void slotDelete(); + virtual void slotJobFinished( KIO::Job *job); + void slotInsertInProject(); + void slotInsertDirInProject(); + virtual void slotReturnPressed(QListViewItem *item); + virtual void slotDropped (QWidget *, QDropEvent *, KURL::List&, KURL&); + /** + sends value from KIO::Job to progressbar + */ + virtual void slotPercent(KIO::Job *job, unsigned long value); + + void slotPopulateFinished(KFileTreeViewItem *item); + /** + shows open with dialog for the current item + */ + void slotOpenWith(); + + /** Opens the current item with the selected associated application */ + void slotOpenWithApplication(); + /** + Called for: double click, return, Open + + emits a signal (@ref openFile or @ref openImage) + or expands an archiv (@ref expandArchiv) in the tree + */ + virtual void slotSelectFile(QListViewItem *item); + /** + emits the signal @ref insertTag + */ + void slotInsertTag(); + /** + reloads the current branch + */ + void slotReload(); + /** + reloads all branches + */ + virtual void slotReloadAllTrees(); + /** + reloads one branche + */ + virtual void reload(BaseTreeBranch *btb); + /** + opens the properties dialog + */ + void slotProperties(); + /** + applies changed properties + */ + virtual void slotPropertiesApplied(); + /** + emits the signal @ref open + */ + void slotOpen(); + /** + emits the signal @ref closeFile + */ + void slotClose(); + + /** + starts the inline rename of the current item + */ + void slotStartRename(); + + /** + connect signal itemRenamed to this slot to handle inline rename + */ + virtual void slotRenameItem(QListViewItem* kvtvi, const QString & newText, int col); + /** + create a site template tarball from the selected directory + */ + virtual void slotCreateSiteTemplate(); + /** + Creates a folder under the current item + */ + virtual void slotCreateFolder(); + /** + Creates a file under the current item + */ + virtual void slotCreateFile(); + + virtual void slotOpenWithActivated(int id); + +protected: + /** + implement this to create a branch and add this branch to the treeview + @param url the root of the branch + @return the new branch + */ + virtual KFileTreeBranch* newBranch(const KURL& url) = 0; + + /** + called when an item was renamed in the properties dialog + the default implementation emits the signal @ref renamed + */ + virtual void itemRenamed(const KURL& , const KURL& ); + + /** + called when the description of an item was changed, + the default implementation does nothing + @param item the treeview item + @param newDesc the new description of item + */ + virtual void itemDescChanged(KFileTreeViewItem* item, const QString& newDesc) + { + Q_UNUSED(item); + Q_UNUSED(newDesc); + }; + /** + @return true if the clipboard contains one or more valid path + */ + bool isPathInClipboard(); + + /** + adds the Quanta fileinfopage to the properties dialog + @param propDlg the dialog where to add the page + @return pointer to to just added page + */ + virtual FileInfoDlg* addFileInfoPage(KPropertiesDialog *propDlg); + + /** + expands an archiv inside of the tree + @return true if expanding was possible + */ + bool expandArchiv (KFileTreeViewItem *item); + bool acceptDrag(QDropEvent* e ) const; + void findDrop(const QPoint &pos, QListViewItem *&parent, QListViewItem *&after); + + /** + this is for project and template tree to reduce includes there + */ + bool isFileOpen(const KURL &url); + + /** Inserts an Open With submenu into @param menu which lists + the possible applications that can open the current item and an + "Other" entry to bring up the Open With dialog. If no application + is associated with the type of the current item, the menu will bring up the Open With dialog immediately. + @param menu the menu where the Open With submenu should be inserted + @param position the position in this menu + */ + void insertOpenWithMenu(KPopupMenu *menu, int position); + KPropertiesDialog *propDlg; + QString m_projectName; + KURL m_projectBaseURL; + FileInfoDlg* fileInfoDlg; + /** the parent of the treeview + the passwords are cached there + */ + QWidget * m_parent; + + BaseTreeViewToolTip * m_tooltip; + // some stuff for renaming + void doRename(KFileTreeViewItem* kvtvi, const QString & newName); + /** reimplemented to reset renameable */ + void cancelRename(int col); + +signals: + void openFile(const KURL&); + void openImage(const KURL&); + void open(QListViewItem *name); + void insertDirInProject(const KURL&); + void insertFileInProject(const KURL&); + void insertTag(const KURL &, DirInfo); + /** + file or folder has been renamed + */ + void renamed(const KURL &, const KURL &); + /** + close the file in Quanta + */ + void closeFile( const KURL& ); + +private: + bool m_saveOpenFolder; + KPopupMenu *m_openWithMenu; + int m_openWithMenuId; + QValueList<KAction *> m_openWithActions; + QMap<int, QuantaPlugin*> m_pluginIds; +}; + +#endif diff --git a/quanta/treeviews/docfolder.cpp b/quanta/treeviews/docfolder.cpp new file mode 100644 index 00000000..02669a1e --- /dev/null +++ b/quanta/treeviews/docfolder.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + docfolder.cpp - description + ------------------- + begin : Fri Mar 3 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002 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. * + * * + ***************************************************************************/ + +// QT includes +#include <qstrlist.h> +#include <qpixmap.h> + +// KDE includes +#include <kconfig.h> +#include <kstandarddirs.h> +#include <kiconloader.h> + +// app includes +#include "docfolder.h" +#include "docitem.h" + +DocFolder::DocFolder(QListViewItem *parent, const QString &_name, KConfig *config, const QString &basePath) + : KListViewItem(parent) +{ + name = _name; + topLevel = false; + url = ""; + + QStrList list; + + config->readListEntry( name, list ); + + char *item; + + for ( list.last(); ( item = list.current() ) ; list.prev() ) { + if ( item[0] != '#' ) { + QString url = config->readEntry( item ); + DocItem *el = new DocItem( this, QString(item), basePath+url); + el->setPixmap( 0, SmallIcon("info") ); + } else + if ( item[0] == '#' ) { // current item is folder + item++; // remove leading # + QString l_url = config->readEntry( QString("folder_")+item, "" ); + DocFolder *el = new DocFolder(this, QString(item), config, basePath); + if ( ! l_url.isEmpty() ) + el->url = basePath+l_url; + el->setPixmap( 0, UserIcon("mini-book1") ); + el->setOpen( false ); + } + } +} + +DocFolder::DocFolder(QListView *parent, const QString &_name, KConfig *config, const QString &basePath) + : KListViewItem(parent) +{ + name = _name; + topLevel = false; + url = ""; + QStrList list; + + config->readListEntry( name, list ); + + char *item; + + for ( list.last(); ( item = list.current() ) ; list.prev() ) { + if ( item[0] != '#' ) { + QString url = config->readEntry( item ); + DocItem *el = new DocItem( this, QString(item), basePath+url); + el->setPixmap( 0, SmallIcon("info") ); + } else + if ( item[0] == '#' ) { // current item is folder + item++; // remove leading # + QString l_url = config->readEntry( QString("folder_")+item, "" ); + DocFolder *el = new DocFolder(this, QString(item), config, basePath); + if ( ! l_url.isEmpty() ) + el->url = basePath+l_url; + el->setPixmap( 0, UserIcon("mini-book1") ); + el->setOpen( false ); + } + } +} + + + +DocFolder::~DocFolder(){ +} + + +QString DocFolder::text( int i) const +{ + if (i == 0) + return name; + else + return ""; +} + +void DocFolder::setup() +{ + setExpandable( true ); + QListViewItem::setup(); +} +/** */ +void DocFolder::setOpen( bool o) +{ + QListViewItem::setOpen( o ); + if ( !topLevel ) { + if (o) + setPixmap( 0, UserIcon("mini-book2") ); + else + setPixmap( 0, UserIcon("mini-book1") ); + } else { + if (o) + setPixmap( 0, SmallIcon("folder_open") ); + else + setPixmap( 0, SmallIcon("folder") ); + } +} diff --git a/quanta/treeviews/docfolder.h b/quanta/treeviews/docfolder.h new file mode 100644 index 00000000..6b6668e1 --- /dev/null +++ b/quanta/treeviews/docfolder.h @@ -0,0 +1,50 @@ +/*************************************************************************** + docfolder.h - description + ------------------- + begin : Fri Mar 3 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002 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. * + * * + ***************************************************************************/ + +#ifndef DOCFOLDER_H +#define DOCFOLDER_H + +#include <qwidget.h> + +#include <klistview.h> + +/** +Class for forlder for +Doc tree + + *@author Yacovlev Alexander & Dmitry Poplavsky + */ + +class KConfig; + +class DocFolder : public KListViewItem { +public: + DocFolder(QListViewItem *parent, const QString &_name, KConfig *config, const QString &basePath); + DocFolder(QListView *parent, const QString &_name, KConfig *config, const QString &basePath); + ~DocFolder(); + QString text( int column ) const; + void setup(); + /** */ + void setOpen( bool o); + +public: + QString url; + QString name; + bool topLevel; +}; + +#endif diff --git a/quanta/treeviews/docitem.cpp b/quanta/treeviews/docitem.cpp new file mode 100644 index 00000000..7c9efa83 --- /dev/null +++ b/quanta/treeviews/docitem.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + docitem.cpp - description + ------------------- + begin : Fri Mar 3 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002 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 <qstrlist.h> + +#include <kconfig.h> + +#include "docitem.h" + +DocItem::DocItem(QListViewItem *parent, const QString &_name, const QString &_url) + : KListViewItem(parent) +{ + url = _url; + name = _name; +} + +DocItem::DocItem(QListView *parent, const QString &_name, const QString &_url) + : KListViewItem(parent) +{ + url = _url; + name = _name; +} + + +DocItem::~DocItem() +{ +} + + +QString DocItem::text( int i) const +{ + if (i == 0) + return name; + else + return ""; +} +//#include "docitem.moc" + diff --git a/quanta/treeviews/docitem.h b/quanta/treeviews/docitem.h new file mode 100644 index 00000000..94fff375 --- /dev/null +++ b/quanta/treeviews/docitem.h @@ -0,0 +1,45 @@ +/*************************************************************************** + docitem.h - description + ------------------- + begin : Fri Mar 3 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002 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. * + * * + ***************************************************************************/ + +#ifndef DOCITEM_H +#define DOCITEM_H + +#include <qwidget.h> + +#include <klistview.h> + +class KConfig; + +/** + *@author Yacovlev Alexander & Dmitry Poplavsky + */ + +class DocItem : public KListViewItem { + +public: + DocItem(QListViewItem *parent, const QString &_name, const QString &_url); + DocItem(QListView *parent, const QString &_name, const QString &_url); + ~DocItem(); + QString text( int column ) const; + +public: // Public attributes + QString url; + QString name; + +}; + +#endif diff --git a/quanta/treeviews/doctreeview.cpp b/quanta/treeviews/doctreeview.cpp new file mode 100644 index 00000000..fd9abf65 --- /dev/null +++ b/quanta/treeviews/doctreeview.cpp @@ -0,0 +1,194 @@ +/*************************************************************************** + doctreeview.cpp - description + ------------------- + begin : Sat Mar 4 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002, 2004 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. * + * * + ***************************************************************************/ + +// QT clases +#include <qstrlist.h> +#include <qheader.h> +#include <qpixmap.h> +#include <qdir.h> + +// KDE clases +#include <kconfig.h> +#include <kapplication.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kurl.h> + +// application clases +#include "doctreeview.h" +#include "docfolder.h" +#include "docitem.h" + +DocTreeView::DocTreeView(QWidget *parent, const char *name ) + : KListView(parent,name) +{ + + contextHelpDict = new QDict<QString>( 101, false ); + + setRootIsDecorated( true ); + header()->hide(); + setSorting(-1,false); + + setFrameStyle( Panel | Sunken ); + setLineWidth( 2 ); + addColumn(i18n("Name"), -1); + addColumn(""); + setFullWidth(true); + + projectDocFolder = new KListViewItem(this, i18n("Project Documentation")); + projectDocFolder->setOpen(true); + slotRefreshTree(); + setFocusPolicy(QWidget::ClickFocus); + + connect(this, SIGNAL(executed(QListViewItem *)), SLOT(clickItem(QListViewItem *)) ); + connect(this, SIGNAL(returnPressed(QListViewItem *)), SLOT(clickItem(QListViewItem *))); + connect(this, SIGNAL(doubleClicked(QListViewItem *)), SLOT(slotDoubleClicked(QListViewItem *))); + + m_contextMenu = new KPopupMenu(this); + m_menuReload = m_contextMenu->insertItem(i18n("&Reload"), this, SLOT(slotReloadProjectDocs())); + m_contextMenu->insertItem(SmallIcon("network"), i18n("&Download Documentation..."), this, SIGNAL(downloadDoc())); + connect(this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotMenu(KListView*, QListViewItem*, const QPoint&))); +} + + +DocTreeView::~DocTreeView(){ + contextHelpDict->setAutoDelete(true); + delete contextHelpDict; +} + +void DocTreeView::slotRefreshTree() +{ + for (QValueList<DocFolder *>::Iterator it = m_folderList.begin(); it != m_folderList.end(); ++it) + { + delete *it; + } + m_folderList.clear(); + QStringList docDirs = KGlobal::instance()->dirs()->findDirs("appdata", "doc"); + + for ( QStringList::Iterator it = docDirs.begin(); it != docDirs.end(); ++it ) + { + QString docDir = *it; + QDir dir(docDir, "*.docrc"); + QStringList files = dir.entryList(); + + for ( QStringList::Iterator it_f = files.begin(); it_f != files.end(); ++it_f ) + { + KConfig config( docDir + *it_f ); + config.setGroup("Tree"); + + QString relDocDir = config.readEntry("Doc dir"); + QString name = config.readEntry("Name").lower(); + + DocFolder *folder = new DocFolder(this, config.readEntry("Top Element"), &config , QDir::cleanDirPath(docDir+relDocDir)+"/"); + folder->setPixmap( 0, SmallIcon("folder_open") ); + folder->topLevel = true; + folder->setOpen(true); + m_folderList.append(folder); + + config.setGroup("Context"); + QStrList list; + config.readListEntry("ContextList", list ); + + for ( unsigned int i=0; i<list.count(); i++ ) + { + QString keyword = list.at(i); + QString *url = new QString(QDir::cleanDirPath(docDir + relDocDir + "/" + config.readEntry( list.at(i) ))); + contextHelpDict->insert( name + "|" + keyword, url ); + } + } + } + +} + +void DocTreeView::clickItem( QListViewItem *) +{ + QListViewItem *it = currentItem(); + if ( !it ) + return; + DocItem *dit = dynamic_cast< DocItem *>(it); + if ( dit ) + if ( ! dit->url.isEmpty() ) + emit openURL( dit->url); + + DocFolder *dfol = dynamic_cast< DocFolder *>(it); + if ( dfol ) + if ( ! dfol->url.isEmpty() ) + emit openURL( dfol->url ); + //else + // emit openURL( locate("appdata","doc/documentation.html") ); +} + + +QString * DocTreeView::contextHelp(const QString &keyword) +{ + QString word = keyword.mid(keyword.find("|")); + if (contextHelpDict->find(keyword)) + return contextHelpDict->find(keyword); + else + return contextHelpDict->find(word); //to support old documentation packages +} + +void DocTreeView::slotDoubleClicked(QListViewItem *item ) +{ + if (item) + { + item->setOpen(!item->isOpen()); + } +} + +void DocTreeView::slotAddProjectDoc(const KURL& url) +{ + QString path = url.path(); + int pos = path.find("/doc/"); + path = path.mid(pos + 5); + new DocItem(projectDocFolder, path, url.url()); +} + +void DocTreeView::slotMenu(KListView *, QListViewItem *item, const QPoint &point) +{ + m_contextMenu->setItemVisible(m_menuReload, false); + if (item) + { + setSelected(item, true); + if (currentItem() == projectDocFolder) + { + m_contextMenu->setItemVisible(m_menuReload, true); + } + } + m_contextMenu->popup(point); +} + +void DocTreeView::slotNewProjectLoaded(const QString &, const KURL &, const KURL &) +{ + slotReloadProjectDocs(); +} + +void DocTreeView::slotReloadProjectDocs() +{ + QListViewItem *child = projectDocFolder->firstChild(); + while (child) { + QListViewItem *c = child; + child = child->nextSibling(); + delete c; + } + emit reloadProjectDocs(); +} + +#include "doctreeview.moc" diff --git a/quanta/treeviews/doctreeview.h b/quanta/treeviews/doctreeview.h new file mode 100644 index 00000000..8061085d --- /dev/null +++ b/quanta/treeviews/doctreeview.h @@ -0,0 +1,71 @@ +/*************************************************************************** + doctreeview.h - description + ------------------- + begin : Sat Mar 4 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002, 2004 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. * + * * + ***************************************************************************/ + +#ifndef DOCTREEVIEW_H +#define DOCTREEVIEW_H + +//qt includes +#include <qdict.h> +#include <qvaluelist.h> + +//kde includes +#include <klistview.h> + +class DocFolder; +class KPopupMenu; + + +/** + *@author Yacovlev Alexander & Dmitry Poplavsky + */ + +class DocTreeView : public KListView { + Q_OBJECT +public: + DocTreeView(QWidget *parent=0, const char *name=0); + ~DocTreeView(); + + QString *contextHelp(const QString &keyword); + +public slots: + void slotNewProjectLoaded(const QString &, const KURL &, const KURL &); + void slotReloadProjectDocs(); + void slotAddProjectDoc(const KURL& url); + /** Re-reads the documentation directories. */ + void slotRefreshTree(); + +signals: + void openURL(const QString& ); + void reloadProjectDocs(); + void downloadDoc(); + +private slots: + void clickItem( QListViewItem *); + void slotDoubleClicked(QListViewItem *); + void slotMenu(KListView *, QListViewItem *item, const QPoint &point); + + +private: + + QDict<QString> *contextHelpDict; + QValueList<DocFolder *> m_folderList; + KListViewItem *projectDocFolder; + KPopupMenu *m_contextMenu; + int m_menuReload; +}; + +#endif diff --git a/quanta/treeviews/fileinfodlg.ui b/quanta/treeviews/fileinfodlg.ui new file mode 100644 index 00000000..f2fbd5fa --- /dev/null +++ b/quanta/treeviews/fileinfodlg.ui @@ -0,0 +1,94 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>FileInfoDlg</class> +<comment>/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ +</comment> +<widget class="QWidget"> + <property name="name"> + <cstring>FileInfoDlg</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>349</width> + <height>266</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>lineNum</cstring> + </property> + <property name="text"> + <string>Number of lines:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>imageNum</cstring> + </property> + <property name="text"> + <string>Number of images included:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>imageSize</cstring> + </property> + <property name="text"> + <string>Size of the included images:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>totalSize</cstring> + </property> + <property name="text"> + <string>Total file size:</string> + </property> + </widget> + <widget class="QListBox" row="5" column="0"> + <property name="name"> + <cstring>imageList</cstring> + </property> + <property name="selectionMode"> + <enum>NoSelection</enum> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>includedLabel</cstring> + </property> + <property name="text"> + <string>Included images:</string> + </property> + </widget> + <widget class="QLabel" row="6" column="0"> + <property name="name"> + <cstring>fileDescLbl</cstring> + </property> + <property name="text"> + <string>Description:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>fileDesc</cstring> + </property> + </widget> + <widget class="QLineEdit" row="7" column="0"> + <property name="name"> + <cstring>fileDesc</cstring> + </property> + </widget> + </grid> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/quanta/treeviews/filestreeview.cpp b/quanta/treeviews/filestreeview.cpp new file mode 100644 index 00000000..be4c6a7e --- /dev/null +++ b/quanta/treeviews/filestreeview.cpp @@ -0,0 +1,334 @@ +/*************************************************************************** + filestreeview.cpp - description + ------------------- + begin : Thu Jun 1 2000 + copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com> + (C) 2001-2004 Andras Mantia <amantoa@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. * + * * + ***************************************************************************/ + + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kinputdialog.h> +#include <kopenwith.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> +#include <kfiledialog.h> +#include <kprogress.h> +#include <kurl.h> + +// app includes +#include "filestreeview.h" +#include "resource.h" +#include "project.h" +#ifdef ENABLE_CVSSERVICE +#include "cvsservice.h" +#endif +#include "qextfileinfo.h" + + +//FilesTreeView implementation + +FilesTreeView::FilesTreeView(KConfig *config, QWidget *parent, const char *name) + : BaseTreeView(parent, name) +{ + setAcceptDrops(true); + setDragEnabled(true); + setSaveOpenFolder(true); + + m_config = config; + m_config->setGroup("General Options"); + // I must read this here because quanta_init has not done it yet + qConfig.showHiddenFiles = m_config->readBoolEntry("Show Hidden Files", true); + qConfig.saveTrees = m_config->readBoolEntry("Save Local Trees", true); + QStringList topStrList = QuantaCommon::readPathListEntry(m_config, "Top folders"); + QStringList topStrAliasList = QuantaCommon::readPathListEntry(m_config, "Top folder aliases"); + KURL url; + for (uint i = 0; i < topStrList.count(); i++) + { + url = KURL(); + QuantaCommon::setUrl(url, topStrList[i]); + if (!topURLList.contains(url)) + { + topURLList.append(url); + if (i < topStrAliasList.count()) + topURLAliases.insert(url.url(), topStrAliasList[i]); + else + topURLAliases.insert(url.url(), url.fileName()); + } + } + + m_config->setGroup("General Options"); + if (m_config->readBoolEntry("Home-Root Folder On", true)) + { + url = KURL(); + url.setPath("/"); + if (!topURLList.contains(url)) + topURLList.append(url); + url = KURL(); + url.setPath(QExtFileInfo::homeDirPath() + "/"); + if (!topURLList.contains(url)) + topURLList.append(url); + } + + m_fileMenu = new KPopupMenu(this); + + m_fileMenu->insertItem(SmallIcon("fileopen"), i18n("&Open"), this ,SLOT(slotOpen())); + m_fileMenu->insertItem(i18n("Insert &Tag"), this, SLOT(slotInsertTag())); + m_menuClose = m_fileMenu->insertItem(SmallIcon("fileclose"), i18n("Clos&e"), this, SLOT(slotClose())); + m_fileMenu->insertSeparator(); + m_insertFileInProject = m_fileMenu->insertItem(i18n("&Insert in Project..."), this, SLOT(slotInsertInProject())); + m_fileMenu->insertItem(SmallIcon("editcopy"), i18n("&Copy"), this, SLOT(slotCopy())); + m_fileMenu->insertItem(i18n("Re&name"), this, SLOT(slotStartRename())); + m_fileMenu->insertItem(SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + + KPopupMenu *createNewMenu = new KPopupMenu(this); + createNewMenu->insertItem(SmallIcon("folder_new"), i18n("F&older..."), this, SLOT(slotCreateFolder())); + createNewMenu->insertItem(SmallIcon("document"), i18n("&File..."), this, SLOT(slotCreateFile())); + + m_folderMenu = new KPopupMenu(); + + m_folderMenu->insertItem(SmallIcon("folder_new"), i18n("New Top &Folder..."), this, SLOT(slotNewTopFolder())); + m_menuTop = m_folderMenu->insertItem(i18n("&Add Folder to Top"), this, SLOT(slotAddToTop())); + m_folderMenu->insertItem(i18n("Create Site &Template..."), this, SLOT(slotCreateSiteTemplate())); + m_folderMenu->insertItem(SmallIcon("empty"), i18n("&Create New"), createNewMenu); + m_folderMenu->insertSeparator(); + m_insertFolderInProject = m_folderMenu->insertItem(i18n("&Insert in Project..."), this, SLOT(slotInsertDirInProject())); + m_folderMenu->insertItem(SmallIcon("editcopy"), i18n("&Copy"), this, SLOT(slotCopy())); + m_menuPasteFolder = m_folderMenu->insertItem(SmallIcon("editpaste"), i18n("&Paste"), this, SLOT(slotPaste())); + m_menuChangeAlias = m_folderMenu->insertItem(i18n("&Change Alias..."), this, SLOT(slotChangeAlias())); + m_menuFolderRename = m_folderMenu->insertItem(i18n("Re&name"), this, SLOT(slotStartRename())); + m_menuDel = m_folderMenu->insertItem( SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_folderMenu->insertSeparator(); + m_folderMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + m_reloadMenuId = m_folderMenu->insertItem(SmallIcon("revert"), i18n("&Reload"), this, SLOT(slotReload())); + + m_emptyMenu = new KPopupMenu(); + + m_emptyMenu->insertItem(i18n("New Top &Folder..."), this, SLOT(slotNewTopFolder()), 0, -1 , 0); + + addColumn(i18n("Files Tree"), -1); + addColumn(""); + + connect(this, SIGNAL(open(QListViewItem *)), + this, SLOT(slotSelectFile(QListViewItem *))); + connect(this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotMenu(KListView*, QListViewItem*, const QPoint&))); + + // generate top list of directories + for (uint i = 0; i < topURLList.count(); i++) + { + KURL url = topURLList[i]; + newBranch(url); + } + restoreLayout(m_config, className()); + // the restored size of the first column might be too large for the current content + // we set it to 10 and the listview will adjust it to the size of the largest entry + setColumnWidth(0, 10); +} + +FilesTreeView::~FilesTreeView() +{ +} + +KFileTreeBranch* FilesTreeView::newBranch(const KURL& url) +{ + BaseTreeBranch* newBrnch = 0; + KFileItem fileItem(KFileItem::Unknown, KFileItem::Unknown, url); + if (url.isLocalFile() && url.path() == "/") + { + newBrnch = new BaseTreeBranch(this, url, i18n("Root Folder"), SmallIcon(fileItem.iconName()), true); + } else + { + if (url.isLocalFile() && url.equals(KURL(QExtFileInfo::homeDirPath() + "/"), true)) + { + newBrnch = new BaseTreeBranch(this, url, i18n("Home Folder"), SmallIcon(fileItem.iconName()), true); + } else + { + QString s = url.fileName(); + if (s.isEmpty()) + s = "/"; + if (topURLAliases.contains(url.url())) + s = topURLAliases[url.url()]; + s += " [" + url.prettyURL() + "]"; + newBrnch = new BaseTreeBranch(this, url, s, SmallIcon(fileItem.iconName()), true); + } + } + newBrnch->setShowingDotFiles(qConfig.showHiddenFiles); + addBranch(newBrnch); + return newBrnch; +} + + + +/** RMB pressed, bring up the menu */ +void FilesTreeView::slotMenu(KListView* listView, QListViewItem *item, const QPoint &point) +{ + Q_UNUSED(listView); +#ifdef ENABLE_CVSSERVICE + KURL url = currentURL(); + if (Project::ref()->contains(url)) + CVSService::ref()->setRepository(Project::ref()->projectBaseURL().path()); + else + CVSService::ref()->setRepository(url.directory()); + if (url.isLocalFile()) + { + CVSService::ref()->setCurrentFile(url.path()); + } + else + CVSService::ref()->setCurrentFile(""); +#endif + if (item) + { + bool hasProject = !m_projectName.isNull(); + m_folderMenu->setItemVisible(m_menuChangeAlias, false); + m_folderMenu->setItemVisible(m_menuFolderRename, true); + m_folderMenu->setItemVisible(m_insertFolderInProject, hasProject); + m_fileMenu->setItemVisible(m_insertFileInProject, hasProject); + setSelected(item, true); + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if ( !curItem->isDir() ) + { + m_fileMenu->setItemVisible(m_menuClose, isFileOpen(currentURL())); + insertOpenWithMenu(m_fileMenu, 1); + m_fileMenu->popup( point); + } else { + m_folderMenu->setItemVisible( m_menuDel, true ); + m_folderMenu->setItemVisible( m_menuTop, true ); + m_folderMenu->setItemVisible(m_menuPasteFolder, isPathInClipboard()); + KURL url = curItem->url(); + if ( curItem == curItem->branch()->root() ) + { + m_folderMenu->setItemVisible(m_menuDel, false); + m_folderMenu->changeItem(m_menuTop, i18n("Remove From &Top")); + m_folderMenu->setItemVisible(m_menuChangeAlias, true); + m_folderMenu->setItemVisible(m_menuFolderRename, false); + + m_config->setGroup("General Options"); + if ((url == KURL("file:/") || url == KURL("file:" + QExtFileInfo::homeDirPath() + "/")) && + m_config->readBoolEntry("Home-Root Folder On", true) ) + m_folderMenu ->setItemVisible(m_menuTop, false); + m_folderMenu ->setItemVisible(m_reloadMenuId, true); + } + else + { + m_folderMenu->changeItem( m_menuTop, i18n("&Add Folder to Top")); + url.adjustPath(+1); + m_folderMenu->setItemVisible(m_menuTop, (topURLList.findIndex(url) == -1)); + m_folderMenu->setItemVisible(m_reloadMenuId, false); + } + m_folderMenu->popup( point); + } + } else { + m_emptyMenu->popup( point ); + } +} + + + +/** Add or remove folders to/from the top list */ +void FilesTreeView::slotAddToTop() +{ + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if ( !curItem ) return; + + if ( curItem->isDir() ) + { + KURL url(currentURL().url()); + url.adjustPath(+1); + if ( curItem != curItem->branch()->root() ) //it is not a top folder + { // add + if (topURLList.findIndex(url) == -1) + { + topURLList.append(url); + bool ok; + QString aliasName = KInputDialog::getText(i18n("Set Alias"), i18n("Alternative folder name:"), url.fileName(), &ok, this); + if (!ok) + aliasName = url.fileName(); + topURLAliases.insert(url.url(), aliasName); + newBranch(url); + } else { + KMessageBox::information(this, i18n("<qt><b>%1</b> is already a toplevel entry.</qt>").arg(url.url())); + } + } else + { // remove + topURLList.remove(url); + topURLAliases.remove(url.url()); + removeBranch(curItem->branch()); + } + } +} + +void FilesTreeView::slotNewTopFolder() +{ + KURL url = KFileDialog::getExistingURL(QString::null, this, i18n("Choose Local or Remote Folder")); + if (url.isEmpty()) return; + url.adjustPath(+1); + if (topURLList.findIndex(url) == -1) + { + bool ok; + QString aliasName = KInputDialog::getText(i18n("Set Alias"), i18n("Alternative folder name:"), url.fileName(), &ok, this); + if (!ok) + aliasName = url.fileName(); + topURLAliases.insert(url.url(), aliasName); + newBranch(url); + topURLList.append(url); + } else { + KMessageBox::information(this, i18n("<qt><b>%1</b> is already a toplevel entry.</qt>").arg(url.url())); + } +} + + +void FilesTreeView::plugCVSMenu() +{ +#ifdef ENABLE_CVSSERVICE + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(SmallIcon("cervisia"), i18n("C&VS"), CVSService::ref()->menu()); + m_folderMenu->insertSeparator(); + m_folderMenu->insertItem(SmallIcon("cervisia"), i18n("C&VS"), CVSService::ref()->menu()); +#endif +} + +void FilesTreeView::slotChangeAlias() +{ + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if ( !curItem ) return; + + if ( curItem->isDir() ) + { + KURL url(currentURL().url()); + url.adjustPath(+1); + if ( curItem == curItem->branch()->root() ) //it is not a top folder + { + if (topURLList.findIndex(url) != -1) + { + bool ok; + QString aliasName = KInputDialog::getText(i18n("Change Alias"), i18n("Alternative folder name:"), topURLAliases[url.url()], &ok, this); + if (ok) + { + topURLAliases.replace(url.url(), aliasName); + removeBranch(curItem->branch()); + newBranch(url); + } + } else { + KMessageBox::information(this, i18n("<qt><b>%1</b> is already a toplevel entry.</qt>").arg(url.url())); + } + } + } +} + + +#include "filestreeview.moc" diff --git a/quanta/treeviews/filestreeview.h b/quanta/treeviews/filestreeview.h new file mode 100644 index 00000000..a77ba3de --- /dev/null +++ b/quanta/treeviews/filestreeview.h @@ -0,0 +1,81 @@ +/*************************************************************************** + filestreeview.h - description + ------------------- + begin : Thu Jun 1 2000 + copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com> + (C) 2001-2004 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. * + * * + ***************************************************************************/ + +#ifndef FILESTREEVIEW_H +#define FILESTREEVIEW_H + +//qt includes +#include <qmap.h> + +// quanta includes +#include "basetreeview.h" + +//foward declarations +class QListViewItem; +class QPoint; +class KPopupMenu; +class KURL; + + +class FilesTreeView : public BaseTreeView { + Q_OBJECT + +public: + FilesTreeView(KConfig *config, QWidget *parent, const char *name = 0L); + virtual ~FilesTreeView(); + KURL::List topURLList; + QMap<QString, QString> topURLAliases; + void plugCVSMenu(); + +protected slots: + /** + opens dialog to choose a url for a new branch + */ + void slotNewTopFolder(); + + virtual void slotMenu(KListView *listView, QListViewItem *item, const QPoint &point); + /** + creates a new branch from the current url + */ + void slotAddToTop(); + /** + Changes the alias (alternative name) for a top folder + */ + void slotChangeAlias(); + +protected: + virtual KFileTreeBranch* newBranch(const KURL& url); + + KPopupMenu *m_fileMenu; + KPopupMenu *m_folderMenu; + KPopupMenu *m_emptyMenu; + int m_menuClose; ///< remembers the menu entry + int m_menuPasteFolder; ///< remembers the menu entry + int m_insertFileInProject; + int m_insertFolderInProject; + // config + KConfig *m_config; + +private: + int m_menuTop; + int m_menuChangeAlias; + int m_menuFolderRename; + int m_menuDel; + int m_reloadMenuId; +}; + +#endif diff --git a/quanta/treeviews/newtemplatedirdlg.cpp b/quanta/treeviews/newtemplatedirdlg.cpp new file mode 100644 index 00000000..bdf6d87f --- /dev/null +++ b/quanta/treeviews/newtemplatedirdlg.cpp @@ -0,0 +1,29 @@ +/*************************************************************************** + newtemplatedirdlg.cpp - description + ------------------- + begin : Fri Jun 21 2002 + copyright : (C) 2002 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#include <qpushbutton.h> +#include "newtemplatedirdlg.h" +#include "newtemplatedirdlg.moc" + +NewTemplateDirDlg::NewTemplateDirDlg(QWidget *parent, const char *name ) : TemplateDirForm(parent,name) +{ + setCaption(name); + connect( buttonOk, SIGNAL(clicked()), SLOT(accept()) ); + connect( buttonCancel, SIGNAL(clicked()), SLOT(reject()) ); +} + +NewTemplateDirDlg::~NewTemplateDirDlg() +{ +} diff --git a/quanta/treeviews/newtemplatedirdlg.h b/quanta/treeviews/newtemplatedirdlg.h new file mode 100644 index 00000000..daa6864a --- /dev/null +++ b/quanta/treeviews/newtemplatedirdlg.h @@ -0,0 +1,33 @@ +/*************************************************************************** + newtemplatedirdlg.h - description + ------------------- + begin : Fri Jun 21 2002 + copyright : (C) 2002 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef NEWTEMPLATEDIRDLG_H +#define NEWTEMPLATEDIRDLG_H + +#include <qwidget.h> +#include <templatedirform.h> + +/** + *@author Andras Mantia + */ + +class NewTemplateDirDlg : public TemplateDirForm { + Q_OBJECT +public: + NewTemplateDirDlg(QWidget *parent=0, const char *name=0); + ~NewTemplateDirDlg(); +}; + +#endif diff --git a/quanta/treeviews/projecttreeview.cpp b/quanta/treeviews/projecttreeview.cpp new file mode 100644 index 00000000..dc8744aa --- /dev/null +++ b/quanta/treeviews/projecttreeview.cpp @@ -0,0 +1,674 @@ +/*************************************************************************** + projecttreeview.cpp - description + ------------------- + begin : Tue Mar 14 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2001-2004 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. * + * * + ***************************************************************************/ + +// QT includes +#include <qpainter.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qdict.h> + +// KDE includes +#include <klocale.h> +#include <kiconloader.h> +#include <kinputdialog.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <kpopupmenu.h> +#include <kpropertiesdialog.h> +#include <ktempfile.h> +#include <kapplication.h> +#include <kstringhandler.h> + +// app includes +#include "projecttreeview.h" +#include "projectlist.h" +#include "projecturl.h" +#include "quantacommon.h" +#include "qextfileinfo.h" +#include "resource.h" +#include "fileinfodlg.h" +#ifdef ENABLE_CVSSERVICE +#include "cvsservice.h" +#endif + +//ProjectTreeViewItem implementation +ProjectTreeViewItem::ProjectTreeViewItem( KFileTreeViewItem *parent, KFileItem* item, KFileTreeBranch *brnch ) +: BaseTreeViewItem( parent, item, brnch) +{ +} + +void ProjectTreeViewItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int align) +{ + QFont f = p->font(); + if (ProjectTreeView::ref()->isDocumentFolder(url())) + { + f.setItalic(true); + if (text(1).isEmpty()) + setText(1, i18n("Document Base Folder")); + } else + { + if (text(1) == i18n("Document Base Folder")) + setText(1, ""); + } + p->setFont(f); + BaseTreeViewItem::paintCell( p, cg, column, width, align ); +} + +//ProjectTreeBranch implementation +ProjectTreeBranch::ProjectTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden, + KFileTreeViewItem *branchRoot) + : BaseTreeBranch(parent, url, name, pix, showHidden, branchRoot) +{ +} + +KFileTreeViewItem* ProjectTreeBranch::createTreeViewItem(KFileTreeViewItem *parent, + KFileItem *fileItem ) +{ + BaseTreeViewItem *tvi = 0; + if( parent && fileItem ) + { + tvi = new ProjectTreeViewItem( parent, fileItem, this ); + if (tvi) + { + // we assume there are childs + tvi->setExpandable(tvi->isDir()); + if (urlList) { + tvi->setVisible(urlList->contains(fileItem->url())); // only listelements + } + } + } + else + kdDebug(24000) << "ProjectTreeBranch::createTreeViewItem: Have no parent" << endl; + return tvi; +} + +//ProjectTreeView implementation +ProjectTreeView::ProjectTreeView(QWidget *parent, const char *name ) + : BaseTreeView(parent,name), m_projectFiles(0) +{ + //setSelectionModeExt(KListView::Extended); + setRootIsDecorated(false); + addColumn(i18n("Project Files"), -1); + addColumn(i18n("Description"), -1); + setDragEnabled(true); + setAcceptDrops(true); + setItemsRenameable(true); + setRenameable(0, false); + setRenameable(1, true); + + m_projectBaseURL = KURL(); + newBranch(m_projectBaseURL); // create an empty project branch + m_projectDir->root()->setEnabled(false); + + m_uploadStatusMenu = new KPopupMenu(this); + m_alwaysUploadId = m_uploadStatusMenu->insertItem(i18n("&When Modified"), this, SLOT(slotAlwaysUpload())); + m_neverUploadId = m_uploadStatusMenu->insertItem(i18n("&Never"), this, SLOT(slotNeverUpload())); + m_confirmUploadId = m_uploadStatusMenu->insertItem(i18n("&Confirm"), this, SLOT(slotConfirmUpload())); + connect(m_uploadStatusMenu, SIGNAL(aboutToShow()), this, SLOT(slotUploadMenuAboutToShow())); + + m_fileMenu = new KPopupMenu(this); + + m_fileMenu->insertItem(SmallIcon("fileopen"), i18n("&Open"), this, SLOT(slotOpen())); + m_openInQuantaId = m_fileMenu->insertItem(i18n("Load Toolbar"), this, SLOT(slotLoadToolbar())); + m_fileMenu->insertItem(i18n("Insert &Tag"), this, SLOT(slotInsertTag())); + m_menuClose = m_fileMenu->insertItem(SmallIcon("fileclose"), i18n("Clos&e"), this, SLOT(slotClose())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(SmallIcon("up"), i18n("&Upload File..."), this, SLOT(slotUploadSingleURL())); + m_fileMenu->insertItem(SmallIcon("up"), i18n("&Quick File Upload"), this, SLOT(slotQuickUploadURL())); + m_fileMenu->insertItem(i18n("Re&name"), this, SLOT(slotStartRename())); + m_fileMenu->insertItem( i18n("&Remove From Project"), this, SLOT(slotRemoveFromProject(int))); + m_fileMenu->insertItem(SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(i18n("Upload &Status"), m_uploadStatusMenu); + m_fileMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + + KPopupMenu *createNewMenu = new KPopupMenu(this); + createNewMenu->insertItem(SmallIcon("folder_new"), i18n("F&older..."), this, SLOT(slotCreateFolder())); + createNewMenu->insertItem(SmallIcon("document"), i18n("&File..."), this, SLOT(slotCreateFile())); + + m_folderMenu = new KPopupMenu(this); + + m_folderMenu->insertItem(SmallIconSet("filenew"), i18n("&Create New"), createNewMenu); + m_folderMenu->insertSeparator(); + m_folderMenu->insertItem(SmallIcon("up"), i18n("&Upload Folder..."), this, SLOT(slotUploadSingleURL())); + m_folderMenu->insertItem(SmallIcon("up"), i18n("&Quick Folder Upload"), this, SLOT(slotQuickUploadURL())); + m_folderMenu->insertItem(i18n("Create Site &Template..."), this, SLOT(slotCreateSiteTemplate())); + m_folderMenu->insertItem(i18n("Re&name"), this, SLOT(slotStartRename())); + m_folderMenu->insertItem(i18n("&Remove From Project"), this, SLOT(slotRemoveFromProject(int))); + m_folderMenu->insertItem(SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_folderMenu->insertSeparator(); + m_setDocumentRootId = m_folderMenu->insertItem(i18n("Document-&Base Folder"), this, SLOT(slotChangeDocumentFolderStatus())); + m_folderMenu->insertItem(i18n("Upload &Status"), m_uploadStatusMenu); + m_folderMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + + m_projectMenu = new KPopupMenu(this); + m_projectMenu->insertItem(SmallIconSet("filenew"), i18n("&Create New"), createNewMenu); + m_projectMenu->insertSeparator(); + m_projectMenu->insertItem(SmallIcon("up"), i18n("&Upload Project..."), this, SLOT(slotUploadProject())); + m_projectMenu->insertItem(SmallIcon("reload"), i18n("Re&scan Project Folder..."), this, SLOT(slotRescan())); + m_projectMenu->insertItem(SmallIcon("configure"), i18n("Project &Properties"), this, SLOT(slotOptions())); + m_projectMenu->insertItem(SmallIcon("revert"), i18n("&Reload"), this, SLOT(slotReload())); + m_projectMenu->insertSeparator(); + m_projectMenu->insertItem(i18n("Upload &Status"), m_uploadStatusMenu); + + + connect(this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotMenu(KListView*, QListViewItem*, const QPoint&))); + + connect(this, SIGNAL(open(QListViewItem *)), + this, SLOT(slotSelectFile(QListViewItem *))); + + restoreLayout(kapp->config(), className()); + // the restored size of the first column might be too large for the current content + // we set it to 10 and the listview will adjust it to the size of the largest entry + setColumnWidth(0, 10); +} + +ProjectTreeView::~ProjectTreeView(){ +} + + +KFileTreeBranch* ProjectTreeView::newBranch(const KURL& url) +{ + QString m_projectNameStr = m_projectName+" "; + if (m_projectName) + { + if (url.protocol() == "file") + { + m_projectNameStr += i18n("[local disk]"); + } else + { + m_projectNameStr += "[" + url.protocol() + "://" + url.user() + "@" + url.host() + "]"; + } + m_projectDir = new ProjectTreeBranch( this, url, m_projectNameStr, SmallIcon("ptab"), true); + m_projectDir->root()->setText(1, url.prettyURL()); + setDragEnabled(true); + setRootIsDecorated(true); + } else { + m_projectDir = new ProjectTreeBranch( this, url, i18n("No Project"), SmallIcon("ptab"), true); + m_projectDir->root()->setText(1, ""); + setDragEnabled(false); + setRootIsDecorated(false); + } + + connect(m_projectDir, SIGNAL(populateFinished(KFileTreeViewItem*)), + this, SLOT(slotPopulateFinished(KFileTreeViewItem*))); + addBranch(m_projectDir); + m_projectDir->urlList = m_projectFiles; // set list for filter + if (m_projectName) + m_projectDir->populate(m_projectDir->rootUrl(), m_projectDir->root()); + else + m_projectDir->root()->setEnabled(false); + + return m_projectDir; +} + + +/** slot for context menu */ +void ProjectTreeView::slotMenu(KListView *listView, QListViewItem *item, const QPoint& point) +{ + Q_UNUSED(listView); + KURL url = currentURL(); +#ifdef ENABLE_CVSSERVICE + CVSService::ref()->setRepository(m_projectBaseURL.path()); + if (url.isLocalFile()) + { + QString path = url.path(); + if (path == m_projectBaseURL.path()) + path += "/."; + CVSService::ref()->setCurrentFile(path); + } + else + CVSService::ref()->setCurrentFile(""); +#endif + ProjectTreeViewItem *curItem = static_cast<ProjectTreeViewItem *>(currentKFileTreeViewItem()); + if (item && curItem) + { + setSelected(item, true); + if (curItem == curItem->branch()->root()) + { + m_projectMenu->popup(point); + } else + { + if (!curItem->isDir()) + { + if (url.fileName().endsWith(toolbarExtension)) + { + m_fileMenu->setItemVisible(m_openInQuantaId, true); + } else + { + m_fileMenu->setItemVisible(m_openInQuantaId, false); + } + m_fileMenu->setItemVisible(m_menuClose, isFileOpen(url)); + insertOpenWithMenu(m_fileMenu, 1); + m_fileMenu->popup(point); + } else + { + if (m_documentFolderList.contains(url)) + m_folderMenu->setItemChecked(m_setDocumentRootId, true); + else + m_folderMenu->setItemChecked(m_setDocumentRootId, false); + m_folderMenu->popup(point); + } + } + } else + if (!m_projectName.isNull()) + { + setSelected(firstChild(), true); + m_projectMenu->popup(point); + } +} + + +/** Sets the project template directory */ +void ProjectTreeView::slotNewProjectLoaded(const QString &name, const KURL &baseURL, const KURL &templateURL) +{ + BaseTreeView::slotNewProjectLoaded(name, baseURL, templateURL); // set m_projectName and m_projectBaseURL + if (!m_projectName.isNull()) + { + QString projectNameStr = m_projectName+" "; + if (m_projectBaseURL.protocol() == "file") + { + projectNameStr += i18n("[local disk]"); + } else + { + projectNameStr += "["+m_projectBaseURL.protocol()+"://"+m_projectBaseURL.user()+"@"+m_projectBaseURL.host()+"]"; + } + m_projectDir->root()->setText(0, projectNameStr); + m_projectDir->root()->setText(1, m_projectBaseURL.prettyURL()); + setDragEnabled(true); + } + else + { + m_projectDir->root()->setText(0, i18n("No Project")); + m_projectDir->root()->setText(1, ""); + setDragEnabled(false); + } + m_documentFolderList.clear(); + m_documentFolderList.append(m_projectBaseURL); +} + +void ProjectTreeView::slotReloadTree( ProjectList *fileList, bool buildNewTree, const QStringList &folderToOpen) +{ + m_projectFiles = fileList; + m_documentFolderList.clear(); + m_documentFolderList.append(m_projectBaseURL); + + KURL url; + ProjectList::Iterator it( *m_projectFiles ); + for ( ; it.current(); ++it) { + if (it.current()->documentFolder) { + url = *(it.current()); + url.adjustPath(-1); + m_documentFolderList.append( url ); + } + } + + if (buildNewTree) + { + if (m_projectDir) + { + removeBranch(m_projectDir); + m_projectDir = 0L; + } + BaseTreeBranch *btb = dynamic_cast<BaseTreeBranch *>(newBranch(m_projectBaseURL)); + if (btb && folderToOpen.count() > 0) { + btb->folderToOpen = folderToOpen; + btb->reopenFolder(); + btb->updateOpenFolder(); + } + } else + { + if (m_projectDir){ + m_projectDir->urlList = m_projectFiles; // set list for filter + KFileTreeViewItem *item; + KFileTreeViewItem *rootItem = m_projectDir->root(); + KURL url; + QListViewItemIterator iter(this); + for ( ; iter.current(); ++iter ) + { + item = dynamic_cast <KFileTreeViewItem*> (iter.current()); + item->setVisible(m_projectFiles->contains(item->url()) || item == rootItem); + } + rootItem->setEnabled(true); + } + } +} + +void ProjectTreeView::slotOpen() +{ + BaseTreeView::slotSelectFile(currentItem()); +} + +void ProjectTreeView::slotLoadToolbar() +{ + if (currentItem()) + { + KURL urlToOpen = currentURL(); + if (urlToOpen.fileName().endsWith(toolbarExtension)) + { + emit loadToolbarFile(urlToOpen); + } + } +} + +void ProjectTreeView::slotCreateFolder() +{ + bool ok; + QString folderName = KInputDialog::getText(i18n("Create New Folder"), i18n("Folder name:"), "", &ok, this); + if (ok) + { + KURL url = currentURL(); + if (currentKFileTreeViewItem()->isDir()) + url.setPath(url.path() + "/" + folderName + "/"); + else + url.setPath(url.directory() + "/" + folderName +"/"); + if (QExtFileInfo::createDir(url, this)) + { + emit insertToProject(url); + } + } +} + +void ProjectTreeView::slotCreateFile() +{ + bool ok; + QString fileName = KInputDialog::getText(i18n("Create New File"), i18n("File name:"), "", &ok, this); + if (ok) + { + KURL url = currentURL(); + if (currentKFileTreeViewItem()->isDir()) + url.setPath(url.path() + "/" + fileName); + else + url.setPath(url.directory() + "/" + fileName); + if (QExtFileInfo::exists(url, false, this)) + { + KMessageBox::error(this, i18n("<qt>Cannot create file, because a file named <b>%1</b> already exists.</qt>").arg(fileName), i18n("Error Creating File")); + return; + } + KTempFile *tempFile = new KTempFile(tmpDir); + tempFile->setAutoDelete(true); + tempFile->close(); + if (QExtFileInfo::copy(KURL::fromPathOrURL(tempFile->name()), url)) + { + emit insertToProject(url); + emit openFile(url); + } + delete tempFile; + } +} + + +void ProjectTreeView::slotRemoveFromProject(int askForRemove) +{ + QListViewItem *item = currentItem(); + if (item) + { + KURL url = currentURL(); + QString nice = QExtFileInfo::toRelative(url, m_projectBaseURL).path(); + nice = KStringHandler::lsqueeze(nice, 60); + if ( !askForRemove || + KMessageBox::warningContinueCancel(this,i18n("<qt>Do you really want to remove <br><b>%1</b><br> from the project?</qt>").arg(nice), i18n("Remove From Project"), KStdGuiItem::remove(), "RemoveFromProject") == KMessageBox::Continue ) + { + if ( currentKFileTreeViewItem()->isDir() ) url.adjustPath(+1); + emit removeFromProject(url); + } + } +} + + +void ProjectTreeView::slotUploadSingleURL() +{ + if (currentItem()) + { + KURL url = currentURL(); + if ( currentKFileTreeViewItem()->isDir() ) url.adjustPath(+1); + emit uploadSingleURL(url, "", false, false); + } +} + +void ProjectTreeView::slotQuickUploadURL() +{ + if (currentItem()) + { + KURL url = currentURL(); + if ( currentKFileTreeViewItem()->isDir() ) url.adjustPath(+1); + emit uploadSingleURL(url, "", true, false); + } +} + +void ProjectTreeView::slotRescan() +{ + emit rescanProjectDir(); + if (!m_projectBaseURL.isLocalFile()) + slotReload(); +} + +/** Bring up the project options dialog */ +void ProjectTreeView::slotOptions() +{ + emit showProjectOptions(); +} + +/** No descriptions */ +void ProjectTreeView::slotUploadProject() +{ + emit uploadProject(); +} + +void ProjectTreeView::slotPopulateFinished(KFileTreeViewItem* item) +{ + BaseTreeView::slotPopulateFinished(item); + // populate descriptions + QString desc; + KFileTreeViewItem* file_item; + ProjectList::Iterator it( *m_projectFiles ); + for ( ; it.current(); ++it) + { + desc = it.current()->fileDesc; + if (! desc.isEmpty()) + { + file_item = m_projectDir->findTVIByURL( *(it.current()) ); + if (file_item) + file_item->setText(1, desc); + } + } + + if ( m_projectFiles->isEmpty() ) + m_projectDir->root()->setExpandable( false ); + /* FIXME: + * The below code can cause infinite recursion, possibly over slow links. + * setOpen call KFileTreeBranch::openURL, that calls KDirListerCache::listDir, + * that calls KDirListerCache::stop, that emit the signal cancelled, that + * is connected to KFileTreeBranch::slotCanceled, that emit populateFinished + * and we are back in this same function with item being the same and + * everything starts over again. */ +// else +// m_projectDir->setOpen( true ); + +} + + +void ProjectTreeView::itemDescChanged(KFileTreeViewItem* item, const QString& newDesc) +{ + if (item) { + item->setText(1, newDesc); + KURL url = item->url(); + if (item->isDir()) + url.adjustPath(1); + emit changeFileDescription(url, newDesc); + } +} + +void ProjectTreeView::slotAlwaysUpload() +{ + KFileTreeViewItem *kftvi = currentKFileTreeViewItem(); + if (! kftvi) + return; + KURL url = currentURL(); + if (kftvi->isDir()) + url.adjustPath(+1); + if (m_projectFiles->contains(url) || url == m_projectBaseURL) + { + emit changeUploadStatus(url, ProjectURL::AlwaysUpload); + } +} + +void ProjectTreeView::slotNeverUpload() +{ + KFileTreeViewItem *kftvi = currentKFileTreeViewItem(); + if (! kftvi) + return; + KURL url = currentURL(); + if (kftvi->isDir()) + url.adjustPath(+1); + if (m_projectFiles->contains(url) || url == m_projectBaseURL) + { + emit changeUploadStatus(url, ProjectURL::NeverUpload); + } +} + +void ProjectTreeView::slotConfirmUpload() +{ + KFileTreeViewItem *kftvi = currentKFileTreeViewItem(); + if (! kftvi) + return; + KURL url = currentURL(); + if (kftvi->isDir()) + url.adjustPath(+1); + if (m_projectFiles->contains(url) || url == m_projectBaseURL) + { + emit changeUploadStatus(url, ProjectURL::ConfirmUpload); + } +} + +void ProjectTreeView::slotUploadMenuAboutToShow() +{ + m_uploadStatusMenu->setItemChecked(m_alwaysUploadId, false); + m_uploadStatusMenu->setItemChecked(m_neverUploadId, false); + m_uploadStatusMenu->setItemChecked(m_confirmUploadId, false); + KFileTreeViewItem *kftvi = currentKFileTreeViewItem(); + if (! kftvi) + return; + KURL url = currentURL(); + if (kftvi->isDir()) + url.adjustPath(+1); + ProjectURL *proUrl = m_projectFiles->find( url ); + if (proUrl) + { + switch (proUrl->uploadStatus) + { + case ProjectURL::NeverUpload: + { + m_uploadStatusMenu->setItemChecked(m_neverUploadId, true); + break; + } + case ProjectURL::ConfirmUpload: + { + m_uploadStatusMenu->setItemChecked(m_confirmUploadId, true); + break; + } + case ProjectURL::AlwaysUpload: + default: + { + m_uploadStatusMenu->setItemChecked(m_alwaysUploadId, true); + break; + } + } + } +} + +void ProjectTreeView::slotChangeDocumentFolderStatus() +{ + KFileTreeViewItem *kftvi = currentKFileTreeViewItem(); + if (! kftvi) + return; + KURL url = currentURL(); + if (kftvi->isDir()) + url.adjustPath(+1); + if (!m_documentFolderList.contains(currentURL())) + { + m_documentFolderList.append(currentURL()); + emit changeUploadStatus(url, ProjectURL::AlwaysUpload); + emit changeDocumentFolderStatus(url, true); + } else + { + m_documentFolderList.remove(currentURL()); + emit changeUploadStatus(url, false); + } + currentItem()->repaint(); +} + +bool ProjectTreeView::isDocumentFolder(const KURL &url) +{ + return (m_documentFolderList.contains(url) > 0); +} + + +void ProjectTreeView::slotRenameItem(QListViewItem* kftvi, const QString& newText, int col) +{ + if (!kftvi) + return; + + if (col == 1) { + itemDescChanged(dynamic_cast <KFileTreeViewItem*> (kftvi), newText); + } else { + BaseTreeView::slotRenameItem(kftvi, newText, col); + } +} + + +FileInfoDlg* ProjectTreeView::addFileInfoPage(KPropertiesDialog* propDlg) +{ + FileInfoDlg* dlg = BaseTreeView::addFileInfoPage(propDlg); + if (dlg) { + dlg->fileDescLbl->show(); + dlg->fileDesc->show(); + } + return dlg; +} + + +void ProjectTreeView::plugCVSMenu() +{ +#ifdef ENABLE_CVSSERVICE + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(SmallIcon("cervisia"), i18n("C&VS"), CVSService::ref()->menu()); + m_folderMenu->insertSeparator(); + m_folderMenu->insertItem(SmallIcon("cervisia"), i18n("C&VS"), CVSService::ref()->menu()); + m_projectMenu->insertSeparator(); + m_projectMenu->insertItem(SmallIcon("cervisia"), i18n("C&VS"), CVSService::ref()->menu()); +#endif + +} + + +void ProjectTreeView::slotViewActivated(const KURL& url) +{ + if (! m_projectDir) return; + + KFileTreeViewItem* item = m_projectDir->findTVIByURL(url); + if (item){ + ensureItemVisible(item); + setSelected(item, true); + } +} + +#include "projecttreeview.moc" diff --git a/quanta/treeviews/projecttreeview.h b/quanta/treeviews/projecttreeview.h new file mode 100644 index 00000000..3bd7548d --- /dev/null +++ b/quanta/treeviews/projecttreeview.h @@ -0,0 +1,176 @@ +/*************************************************************************** + projecttreeview.h - description + ------------------- + begin : Tue Mar 14 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2001-2004 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. * + * * + ***************************************************************************/ + +#ifndef PROJECTTREEVIEW_H +#define PROJECTTREEVIEW_H + +//own includes +#include "basetreeview.h" +//#include "projecturl.h" + +class KIO::Job; +class FileInfoDlg; +class ProjectList; + +class ProjectTreeViewItem : public BaseTreeViewItem { + +public: + ProjectTreeViewItem( KFileTreeViewItem *parent, KFileItem* item, KFileTreeBranch *brnch ); + /** makes document root italics */ + void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align); +}; + +class ProjectTreeBranch : public BaseTreeBranch { + +public: + ProjectTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden = false, KFileTreeViewItem *branchRoot = 0L); + + /** check for CVS and visible*/ + virtual KFileTreeViewItem* createTreeViewItem(KFileTreeViewItem *parent, + KFileItem *fileItem ); + + /** only files in list will be shown */ + ProjectList *urlList; +}; + + + +class ProjectTreeView : public BaseTreeView { + Q_OBJECT + +public: + /** + * since this class is a singleton you must use this function to access it + * + * the parameters are only used at the first call to create the class + * + */ + static ProjectTreeView* const ref(QWidget *parent = 0L, const char *name = 0L) + { + static ProjectTreeView *m_ref; + if (!m_ref) m_ref = new ProjectTreeView(parent, name); + return m_ref; + } + + virtual ~ProjectTreeView(); + bool isDocumentFolder(const KURL &url); + ProjectTreeBranch* rootBranch() {return m_projectDir;} + void plugCVSMenu(); + +public slots: // Public slots + void slotOpen(); + void slotLoadToolbar(); + void slotReloadTree(ProjectList *a_fileList, bool buildNewtree, const QStringList &folderToOpen); + /** Sets new project information */ + void slotNewProjectLoaded(const QString &, const KURL &, const KURL &); + void slotPopulateFinished(KFileTreeViewItem* ); + /** makes the url visible in the tree */ + void slotViewActivated(const KURL&); + /** fills the list with the url's of the open folder */ + void slotGetTreeStatus(QStringList *folderToOpen) + { + m_projectDir->addOpenFolder(folderToOpen); + } + + + +protected slots: + void slotMenu(KListView *listView, QListViewItem *item, const QPoint &point); + void slotRenameItem(QListViewItem* kvtvi, const QString & newText, int col); + virtual void slotCreateFolder(); + virtual void slotCreateFile(); + +signals: // Signals + void removeFromProject( const KURL& ); + /** No descriptions */ + void rescanProjectDir(); + /** No descriptions */ + void showProjectOptions(); + void insertToProject(const KURL&); + void uploadSingleURL(const KURL&, const QString&, bool, bool); + void loadToolbarFile(const KURL&); + void uploadProject(); + void changeFileDescription(const KURL& url, const QString& desc); + void changeUploadStatus(const KURL& url, int status); + void changeDocumentFolderStatus(const KURL& url, bool status); + void reloadProject(); + +private: + /** The constructor is privat because we use singleton patter. + * If you need the class use ProjectTreeView::ref() for + * construction and reference + */ + ProjectTreeView(QWidget *parent, const char *name); + + ProjectTreeBranch *m_projectDir; + KPopupMenu *m_fileMenu; + KPopupMenu *m_folderMenu; + KPopupMenu *m_projectMenu; + KURL m_documentRootURL; + ProjectTreeViewItem *m_documentRootItem; + KURL::List m_documentFolderList; + KPopupMenu *m_uploadStatusMenu; + ProjectList *m_projectFiles; + int m_menuClose; ///< remembers the menu entry + + int m_openInQuantaId; ///< remembers the menu entry + int m_setDocumentRootId; + int m_alwaysUploadId; + int m_neverUploadId; + int m_confirmUploadId; + +protected: + /** + creates a branch and adds this branch to the treeview + @param url the root of the branch + @return the new branch + */ + virtual KFileTreeBranch* newBranch(const KURL& url); + /** + called when the description of an item was changed, + @param item the treeview item + @param newDesc the new description of item + */ + void itemDescChanged(KFileTreeViewItem* item, const QString& newDesc); + /** + adds the Quanta fileinfopage to the properties dialog + overwritten to enable the file description + @param propDlg the dialog where to add the page + @return pointer to to just added page + */ + virtual FileInfoDlg* addFileInfoPage(KPropertiesDialog *propDlg); + +private slots: // Private slots + /** No descriptions */ + void slotUploadProject(); + /** Bring up the project options dialog */ + void slotOptions(); + /** No descriptions */ + void slotRescan(); + void slotRemoveFromProject(int askForRemove = 1); + void slotUploadSingleURL(); + void slotQuickUploadURL(); + void slotAlwaysUpload(); + void slotNeverUpload(); + void slotConfirmUpload(); + void slotUploadMenuAboutToShow(); + void slotChangeDocumentFolderStatus(); +}; + +#endif diff --git a/quanta/treeviews/quantapropertiespage.ui b/quanta/treeviews/quantapropertiespage.ui new file mode 100644 index 00000000..5c7a9096 --- /dev/null +++ b/quanta/treeviews/quantapropertiespage.ui @@ -0,0 +1,247 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>QuantaPropertiesPage</class> +<comment>/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ +</comment> +<author>(C) 2002 Andras Mantia <amantia@kde.org></author> +<widget class="QWidget"> + <property name="name"> + <cstring>QuantaPropertiesPage</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>343</width> + <height>443</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>300</width> + <height>400</height> + </size> + </property> + <property name="caption"> + <string>Quanta Properties</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QWidgetStack" row="0" column="0"> + <property name="name"> + <cstring>typeStack</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>parentAttr</cstring> + </property> + <property name="text"> + <string>&Inherit type from parent (nothing)</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>&Type:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>typesCombo</cstring> + </property> + </widget> + <spacer row="0" column="3"> + <property name="name"> + <cstring>Spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>92</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KComboBox" row="0" column="2"> + <property name="name"> + <cstring>typesCombo</cstring> + </property> + </widget> + <widget class="QButtonGroup" row="2" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>prePostGroup</cstring> + </property> + <property name="title"> + <string></string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>usePrePostText</cstring> + </property> + <property name="text"> + <string>Use &pre/post text</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel1_2</cstring> + </property> + <property name="text"> + <string>Pre-text:</string> + </property> + </widget> + <widget class="QTextEdit" row="2" column="0"> + <property name="name"> + <cstring>preTextEdit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>Post-text:</string> + </property> + </widget> + <widget class="QTextEdit" row="4" column="0"> + <property name="name"> + <cstring>postTextEdit</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + </widget> + </grid> + </widget> + <spacer row="0" column="1"> + <property name="name"> + <cstring>Spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>93</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>WStackPage</cstring> + </property> + <attribute name="id"> + <number>1</number> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>filteringLabel</cstring> + </property> + <property name="text"> + <string>Filtering &action:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>actionCombo</cstring> + </property> + </widget> + <widget class="KComboBox" row="0" column="1"> + <property name="name"> + <cstring>actionCombo</cstring> + </property> + </widget> + <spacer row="1" column="1"> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </grid> + </widget> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>parentAttr</sender> + <signal>toggled(bool)</signal> + <receiver>typesCombo</receiver> + <slot>setDisabled(bool)</slot> + </connection> + <connection> + <sender>usePrePostText</sender> + <signal>toggled(bool)</signal> + <receiver>preTextEdit</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>usePrePostText</sender> + <signal>toggled(bool)</signal> + <receiver>postTextEdit</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>typesCombo</tabstop> + <tabstop>parentAttr</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/quanta/treeviews/scripttreeview.cpp b/quanta/treeviews/scripttreeview.cpp new file mode 100644 index 00000000..191be51c --- /dev/null +++ b/quanta/treeviews/scripttreeview.cpp @@ -0,0 +1,425 @@ +/*************************************************************************** + scripttreeview.cpp - description + ------------------- + begin : Thu Sep 16 2003 + copyright : (C) 2003-2004 by 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; version 2 of the License. * + * * + ***************************************************************************/ +//kde includes +#include <kapplication.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> +#include <kprocess.h> +#include <krun.h> +#include <kstandarddirs.h> +#include <ktar.h> +#include <ktempdir.h> +#include <ktempfile.h> +#include <kurl.h> +#include <kdebug.h> + +//qt includes +#include <qdir.h> +#include <qdom.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qlabel.h> +#include <qlineedit.h> +#include <qregexp.h> +#include <qstringlist.h> +#include <qtextedit.h> + +//other includes +#include <libxml/xmlmemory.h> +#include <libxml/debugXML.h> +#include <libxml/HTMLtree.h> +#include <libxml/xmlIO.h> +#include <libxml/DOCBparser.h> +#include <libxml/xinclude.h> +#include <libxml/catalog.h> +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> + +//app includes +#include "scripttreeview.h" +#include "resource.h" +#include "quantacommon.h" +#include "tagmaildlg.h" + +extern int xmlLoadExtDtdDefaultValue; + +ScriptTreeView::ScriptTreeView(QWidget *parent, const char *name ) + : BaseTreeView(parent,name) +{ + setSaveOpenFolder(true); + addColumn(i18n("Scripts"), -1); + addColumn(""); + + KURL url; + url.setPath(qConfig.globalDataDir + resourceDir + "scripts/"); + + BaseTreeBranch *m_globalDir; + m_globalDir = new BaseTreeBranch(this, url, i18n("Global Scripts"), SmallIcon("run"), true); + addBranch(m_globalDir); + + url.setPath(locateLocal("data", resourceDir + "scripts/")); + + BaseTreeBranch *m_localDir; + m_localDir = new BaseTreeBranch(this, url, i18n("Local Scripts"), SmallIcon("run"), true); + addBranch(m_localDir); + + // here you define which files should not be visible for the users + const QString excludeString = ".*\\.info$|.*\\.css$|.*\\.xsl$"; + m_globalDir->excludeFilterRx.setPattern(excludeString); + m_localDir->excludeFilterRx.setPattern(excludeString); + + m_fileMenu = new KPopupMenu(this); + m_fileMenu->insertItem(SmallIcon("info"), i18n("&Description"), this, SLOT(slotProperties())); + m_fileMenu->insertItem(SmallIcon("run"), i18n("&Run Script"), this, SLOT(slotRun())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(i18n("&Edit Script"), this, SLOT(slotEditScript())); + m_fileMenu->insertItem(i18n("Edit in &Quanta"), this, SLOT(slotEditInQuanta())); + m_fileMenu->insertItem(i18n("Edi&t Description"), this, SLOT(slotEditDescription())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(UserIcon("ball"), i18n("&Assign Action"), this, SLOT(slotAssignAction())); + m_fileMenu->insertItem(SmallIcon("mail_send"), i18n("&Send in Email..."), this, SLOT(slotSendScriptInMail())); + m_fileMenu->insertItem(SmallIcon("network"), i18n("&Upload Script..."), this, SLOT(slotUploadScript())); + + m_folderMenu = new KPopupMenu(this); + m_downloadMenuId = m_folderMenu->insertItem(SmallIcon("network"), i18n("&Download Script..."), this, SIGNAL(downloadScript())); + + + connect(this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotMenu(KListView*, QListViewItem*, const QPoint&))); + + restoreLayout( kapp->config(), className() ); + // the restored size of the first column might be too large for the current content + // we set it to 10 and the listview will adjust it to the size of the largest entry + setColumnWidth(0, 10); +} + +ScriptTreeView::~ScriptTreeView() +{ +} + +void ScriptTreeView::slotMenu(KListView *, QListViewItem *item, const QPoint &point) +{ + if (!item) + { + m_folderMenu->setItemVisible(m_downloadMenuId, true); + m_folderMenu->popup(point); + return; + } + setSelected(item, true); + + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if (!curItem->isDir()) + { + m_fileMenu->popup(point); + } else + { + if (curItem == curItem->branch()->root()) + { + m_folderMenu->setItemVisible(m_downloadMenuId, true); + } else + { + m_folderMenu->setItemVisible(m_downloadMenuId, false); + } + m_folderMenu->popup(point); + } +} + +void ScriptTreeView::slotSelectFile(QListViewItem *item) +{ + if (item) { + if ( !currentKFileTreeViewItem()->isDir() ) + { + KURL urlToOpen = infoFile(currentURL(), true); + emit openFileInPreview(urlToOpen); + } + } +} + +void ScriptTreeView::slotEditDescription() +{ + if ( !currentKFileTreeViewItem()->isDir() ) + { + KURL urlToOpen = infoFile(currentURL()); + emit showPreviewWidget(false); + emit openFile(urlToOpen); + } +} + +void ScriptTreeView::slotEditScript() +{ + if ( !currentKFileTreeViewItem()->isDir() ) + { + emit showPreviewWidget(false); + KURL urlToOpen = currentURL(); + KURL infoUrl = infoFile(urlToOpen); + QString editApp = infoOptionValue(infoUrl, "editor"); + if (editApp.isEmpty()) + emit openFile(urlToOpen); + else + { + KProcess *proc = new KProcess(); + *proc << editApp << urlToOpen.path(); + proc->start(KProcess::DontCare); + } + } +} + + +void ScriptTreeView::slotRun() +{ + if ( !currentKFileTreeViewItem()->isDir() ) + { + KURL urlToOpen = currentURL(); + KURL infoUrl = infoFile(urlToOpen); + QString execApp = infoOptionValue(infoUrl, "interpreter"); + if (execApp.isEmpty()) + { + KURL::List list; + list.append(urlToOpen); + KRun::displayOpenWithDialog(list); + } + else + { + KProcess *proc = new KProcess(); + QStringList argsList = QStringList::split(' ', execApp); + *proc << argsList; + *proc << urlToOpen.path(); + proc->start(KProcess::DontCare); + } + } +} + + +void ScriptTreeView::slotEditInQuanta() +{ + if ( !currentKFileTreeViewItem()->isDir() ) + { + KURL urlToOpen = currentURL(); + emit showPreviewWidget(false); + emit openFile(urlToOpen); + } +} + +void ScriptTreeView::slotAssignAction() +{ + if ( !currentKFileTreeViewItem()->isDir() ) + { + KURL url = currentURL(); + KURL infoURL = infoFile(url); + QString execApp = infoOptionValue(infoURL, "interpreter"); + if (execApp.isEmpty()) + execApp = "sh"; + url.setPath(url.path().replace(locateLocal("data", resourceDir + "scripts/"), "%scriptdir/")); + url.setPath(url.path().replace(qConfig.globalDataDir + resourceDir + "scripts/", "%scriptdir/")); + emit assignActionToScript(url, execApp); + } +} + +QString ScriptTreeView::createScriptTarball() +{ + KURL url = currentURL(); + KURL infoURL = infoFile(url); + + KTempDir* tempDir = new KTempDir(tmpDir); + tempDir->setAutoDelete(true); + tempDirList.append(tempDir); + QString tempFileName=tempDir->name() + url.fileName() + ".tgz"; + + //pack the .tag files and the description.rc into a .tgz file + KTar tar(tempFileName, "application/x-gzip"); + tar.open(IO_WriteOnly); + + KURL::List files; + files.append(url); + files.append(infoURL); + files.append(KURL().fromPathOrURL(qConfig.globalDataDir + resourceDir + "scripts/info.xsl")); + for ( KURL::List::Iterator it_f = files.begin(); it_f != files.end(); ++it_f ) + { + QFile file((*it_f).path()); + file.open(IO_ReadOnly); + QByteArray bArray = file.readAll(); + tar.writeFile((*it_f).fileName(), "user", "group", bArray.size(), bArray.data()); + file.close(); + } + tar.close(); + + return tempFileName; +} + +void ScriptTreeView::slotSendScriptInMail() +{ + if ( !currentKFileTreeViewItem()->isDir() ) + { + + QStringList attachmentFile; + attachmentFile += createScriptTarball(); + + TagMailDlg *mailDlg = new TagMailDlg( this, i18n("Send script in email")); + QString toStr; + QString message = i18n("Hi,\n This is a Quanta Plus [http://quanta.kdewebdev.org] script tarball.\n\nHave fun.\n"); + QString titleStr; + QString subjectStr; + + mailDlg->TitleLabel->setText(i18n("Content:")); +/* mailDlg->titleEdit->setFixedHeight(60); + mailDlg->titleEdit->setVScrollBarMode(QTextEdit::Auto); + mailDlg->titleEdit->setHScrollBarMode(QTextEdit::Auto);*/ + if ( mailDlg->exec() ) + { + if ( !mailDlg->lineEmail->text().isEmpty()) + { + toStr = mailDlg->lineEmail->text(); + subjectStr = (mailDlg->lineSubject->text().isEmpty())?i18n("Quanta Plus Script"):mailDlg->lineSubject->text(); + if ( !mailDlg->titleEdit->text().isEmpty()) + message = mailDlg->titleEdit->text(); + } else + { + KMessageBox::error(this,i18n("No destination address was specified.\n Sending is aborted."),i18n("Error Sending Email")); + delete mailDlg; + return; + } + kapp->invokeMailer(toStr, QString::null, QString::null, subjectStr, message, QString::null, attachmentFile); + } + delete mailDlg; + + } +} + +void ScriptTreeView::slotUploadScript() +{ + if ( !currentKFileTreeViewItem()->isDir() ) + { + QString fileName = createScriptTarball(); + emit uploadScript(fileName); + } +} + +KURL ScriptTreeView::infoFile(const KURL& url, bool htmlVersion) +{ + KURL returnUrl = url; + QString fileName = returnUrl.fileName(); + //fileName.truncate(fileName.length() - QFileInfo(fileName).extension().length() - 1); + fileName.append(".info"); + returnUrl.setFileName(fileName); + if (!QFileInfo(returnUrl.path()).exists()) + { + QFile f(returnUrl.path()); + if (f.open(IO_WriteOnly)) + { + QTextStream str(&f); + str.setEncoding(QTextStream::UnicodeUTF8); + str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; + str << "<?xml-stylesheet type=\"text/xsl\" href=\"info.xsl\" ?>" << endl; + str << "<!DOCTYPE QuantaScriptInfo>" << endl; + str << "<INFO>" << endl; + str << " <options editor=\"\" interpreter=\"\" />" << endl; + str << " <name>" << url.fileName() << "</name>" << endl; + str << " <author></author>" << endl; + str << " <email></email>" << endl; + str << " <website></website>" << endl; + str << " <version></version>" << endl; + str << " <license></license>" << endl; + str << " <about></about>" << endl; + str << "</INFO>" << endl; + f.close(); + } + } + + if (htmlVersion) + { + KTempFile *tempInfoFile = 0L; + if (!QFileInfo(returnUrl.path()).exists()) + { + tempInfoFile = new KTempFile(tmpDir); + tempInfoFile->setAutoDelete(true); + returnUrl = KURL::fromPathOrURL(tempInfoFile->name()); + QTextStream str(tempInfoFile->file()); + str.setEncoding(QTextStream::UnicodeUTF8); + str << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; + str << "<?xml-stylesheet type=\"text/xsl\" href=\"info.xsl\" ?>" << endl; + str << "<!DOCTYPE QuantaScriptInfo>" << endl; + str << "<INFO>" << endl; + str << " <options editor=\"\" interpreter=\"\" />" << endl; + str << " <name>" << url.fileName() << "</name>" << endl; + str << " <author></author>" << endl; + str << " <email></email>" << endl; + str << " <website></website>" << endl; + str << " <version></version>" << endl; + str << " <license></license>" << endl; + str << " <about></about>" << endl; + str << "</INFO>" << endl; + tempInfoFile->close(); + tempFileList.append(tempInfoFile); + } + KTempFile *tempFile = new KTempFile(tmpDir); + tempFile->setAutoDelete(true); + //apply the stylesheet + xsltStylesheetPtr cur = NULL; + xmlDocPtr doc, res; + xmlSubstituteEntitiesDefault(1); + xmlLoadExtDtdDefaultValue = 1; + QString xslFile = qConfig.globalDataDir + resourceDir + "scripts/info.xsl"; + cur = xsltParseStylesheetFile(xmlCharStrndup(xslFile.utf8(), xslFile.utf8().length())); + doc = xmlParseFile(returnUrl.path().utf8()); + res = xsltApplyStylesheet(cur, doc, 0); + xsltSaveResultToFile(tempFile->fstream(), res, cur); + + xsltFreeStylesheet(cur); + xmlFreeDoc(res); + xmlFreeDoc(doc); + + xsltCleanupGlobals(); + xmlCleanupParser(); + tempFile->close(); + + tempFileList.append(tempFile); + return KURL().fromPathOrURL(tempFile->name()); + } else + return returnUrl; +} + +QString ScriptTreeView::infoOptionValue(const KURL& infoURL, const QString& optionName) +{ + QString value; + QFile f(infoURL.path()); + if (f.open(IO_ReadOnly)) + { + QDomDocument doc; + doc.setContent(&f); + f.close(); + QDomNodeList nodes = doc.elementsByTagName("options"); + if (nodes.count() > 0) + { + QDomElement el = nodes.item(0).toElement(); + value = el.attribute(optionName); + } + } + return value; +} + + +void ScriptTreeView::slotProperties() +{ + KFileTreeViewItem *item = currentKFileTreeViewItem(); + if (item) + slotSelectFile(item); +} + + +#include "scripttreeview.moc" diff --git a/quanta/treeviews/scripttreeview.h b/quanta/treeviews/scripttreeview.h new file mode 100644 index 00000000..7cf2b145 --- /dev/null +++ b/quanta/treeviews/scripttreeview.h @@ -0,0 +1,220 @@ +/*************************************************************************** + scripttreeview.h - description + ------------------- + begin : Thu Sep 16 2003 + copyright : (C) 2003-2004 by 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; version 2 of the License. * + * * + ***************************************************************************/ +#ifndef SCRIPTTREEVIEW_H +#define SCRIPTTREEVIEW_H + +//own includes +#include "basetreeview.h" + +/** + * @short treeview with all in Quanta available scripts. + * + * You can manage and excecute scripts from here. + * + * There are local and global scripts in different branches. + * + * For every script should exist an .info file! + * + * The .info file is an xhtml file with the extention .info and + * must be in one folder together with the script. + * + * Inside of your .info file should be an options tag like this + * example: + * + * <options editor="kmdr-editor" interpreter="kmdr-executor" /> + * + * Here is defined which program is used for editing and executing the script. + * + * @author Andras Mantia <amantia@kde.org> + */ +class ScriptTreeView : public BaseTreeView { + Q_OBJECT + + +public: + ScriptTreeView(QWidget *parent, const char *name = 0L); + ~ScriptTreeView(); + +protected slots: + + /** + * displays the RBM + * + * + * @param listView KListView where the event comes from + * + * @param item QListViewItem where the mousepointer is hovering + * + * @param point QPoint coordinates of the event + * + */ + virtual void slotMenu(KListView *listView, QListViewItem *item, const QPoint &point); + + /** + * slot of QListView + * + * shows the .info file for the script + * + * @param item the selected QListViewItem + */ + virtual void slotSelectFile(QListViewItem *item); + + /** + * slot for the RBM + * + * invokes the editor for a script + */ + void slotEditScript(); + + /** + * slot for the RBM + * + * opens the script in Quanta + * + * if @ref infoOptionValue can not find the definition of the editor + * in the .info file the script will be opened in Quanta + */ + void slotEditInQuanta(); + + /** + * slot for the RBM + * + * opens the .info file of the script in Quanta + */ + void slotEditDescription(); + + /** + * slot for the RBM + * + * excecutes the script + * + * If @ref infoOptionValue can not find the definition of the interpreter + * in the .info file you will get a open-with dialog to choose a program. + */ + void slotRun(); + + /** + * slot for the RBM + * + * opens an dialog to assign an action to this script + */ + void slotAssignAction(); + + /** + * slot for the RBM + * + * packs and sends the script as attachment to an email + */ + void slotSendScriptInMail(); + + /** + * slot for the RBM + * + * packs and uploads the script to the main server + */ + void slotUploadScript(); + + /** + * slot for the RBM + * + * shows .info file for the script + * + * calls @ref slotSelectFile + */ + void slotProperties(); + +protected: + + /** + * don't need this in the class but it is abstract in the base class + * so I need to implement it + */ + virtual KFileTreeBranch* newBranch(const KURL& url) + { + Q_UNUSED(url) + return 0l; + }; + +signals: + + /** + * emited from @ref slotSelectFile to display the .info file + */ + void openFileInPreview(const KURL&); + + /** + * emited from @ref slotAssignAction to open the assignment dialog + */ + void assignActionToScript(const KURL&, const QString&); + + /** + * emited to make the script describtion visible + */ + void showPreviewWidget(bool); + + /** + * emitted to request downloading of a script from the main server + */ + void downloadScript(); + + /** + * request to upload the @ref fileName script tarball + */ + void uploadScript(const QString& fileName); + +private: + /** + * make the default constructor private to force the use of the other one + */ + ScriptTreeView() { }; + + /** + * creates the URL of the .info file + * + * @param url URL of the script file + * @param htmlVersion if true returns the HTML version of the file + * + * @return URL of the matching .info file (no check is done if the file exists) + */ + KURL infoFile(const KURL& url, bool htmlVersion = false); + + /** + * query options from the .info file + * + * inside of your .info file only the first options tag is located + * + * @param infoURL URL of the .info file + * + * @param optionName name of the option you want to query + * + * @return the value of the option + */ + QString infoOptionValue(const KURL& infoURL, const QString& optionName); + + /** Create a script tarball which can be uploaded or sent in email. Returns + * the name of the created file or QString::null if creation has failed. + */ + QString createScriptTarball(); + + /** + * remember the menu for manipulation + */ + KPopupMenu *m_fileMenu; + KPopupMenu *m_folderMenu; + + int m_downloadMenuId; +}; + +#endif diff --git a/quanta/treeviews/servertreeview.cpp b/quanta/treeviews/servertreeview.cpp new file mode 100644 index 00000000..024e31d5 --- /dev/null +++ b/quanta/treeviews/servertreeview.cpp @@ -0,0 +1,195 @@ +/*************************************************************************** + filestreeview.cpp - description + ------------------- + begin : Thu Jun 1 2000 + copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com> + (C) 2001-2004 Andras Mantia <amantoa@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. * + * * + ***************************************************************************/ + +// Qt includes +#include <qpainter.h> + +// KDE includes +#include <kdebug.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kopenwith.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> +#include <kfiledialog.h> +#include <kprogress.h> +#include <kurl.h> + +// app includes +#include "servertreeview.h" +#include "resource.h" +#include "project.h" +#include "qextfileinfo.h" + + +ServerTreeViewItem::ServerTreeViewItem( KFileTreeViewItem *parent, KFileItem* item, KFileTreeBranch *brnch ) +: BaseTreeViewItem( parent, item, brnch) +{ +} + +void ServerTreeViewItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int align) +{ + QColorGroup _cg( cg ); + KURL baseURL = Project::ref()->projectBaseURL(); + KURL relURL = baseURL; + relURL.setPath(QExtFileInfo::toRelative(url(), branch()->url()).path()); + KURL url = QExtFileInfo::toAbsolute(relURL, baseURL); + if ( !Project::ref()->contains(url) ) + { + QFont f = p->font(); + f.setItalic(true); + p->setFont(f); + int h, s, v; + p->pen().color().getHsv(&h, &s, &v); + v = (v < 155 ? v + 100 : 255); + _cg.setColor(QColorGroup::Text, QColor(h, s, v, QColor::Hsv)); + }; + BaseTreeViewItem::paintCell( p, _cg, column, width, align ); +} + +//ServerTreeBranch implementation +ServerTreeBranch::ServerTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden, KFileTreeViewItem *branchRoot) + : BaseTreeBranch(parent, url, name, pix, showHidden, branchRoot) +{ +} + +KFileTreeViewItem* ServerTreeBranch::createTreeViewItem(KFileTreeViewItem *parent, KFileItem *fileItem ) +{ + BaseTreeViewItem *tvi = 0; + if( parent && fileItem ) + { + tvi = new ServerTreeViewItem( parent, fileItem, this ); + } + else + kdDebug(24000) << "ServerTreeBranch::createTreeViewItem: Have no parent" << endl; + return tvi; +} + +///////////////////////////////////////////////////////////////////////////////////// +// +// ServerTreeView implementation +// +// +ServerTreeView::ServerTreeView(KConfig *config, QWidget *parent, const KURL &url, const char *name) + : BaseTreeView(parent, name) +{ + setAcceptDrops(true); + setDragEnabled(true); + + m_config = config; + m_config->setGroup("General Options"); + // I must read this here because quanta_init has not done it yet + qConfig.showHiddenFiles = m_config->readBoolEntry("Show Hidden Files", true); + + m_fileMenu = new KPopupMenu(); + + m_fileMenu->insertItem(SmallIcon("fileopen"), i18n("&Open"), this ,SLOT(slotOpen())); + m_fileMenu->insertItem(i18n("Open &With..."), this, SLOT(slotOpenWith())); + m_menuClose = m_fileMenu->insertItem(SmallIcon("fileclose"), i18n("Clos&e"), this, SLOT(slotClose())); + m_fileMenu->insertSeparator(); +// m_insertFileInProject = m_fileMenu->insertItem(i18n("&Insert in Project..."), this, SLOT(slotInsertInProject())); + m_fileMenu->insertItem(SmallIcon("editcopy"), i18n("&Copy"), this, SLOT(slotCopy())); + m_fileMenu->insertItem(SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_fileMenu->insertItem(i18n("Re&name"), this, SLOT(slotStartRename())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + + m_folderMenu = new KPopupMenu(); + +// m_insertFolderInProject = m_folderMenu->insertItem(i18n("&Insert in Project..."), this, SLOT(slotInsertDirInProject())); + m_folderMenu->insertItem(SmallIcon("editcopy"), i18n("&Copy"), this, SLOT(slotCopy())); + m_menuPasteFolder = m_folderMenu->insertItem(SmallIcon("editpaste"), i18n("&Paste"), this, SLOT(slotPaste())); + m_menuDel = m_folderMenu->insertItem( SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_renameId = m_folderMenu->insertItem(i18n("Re&name"), this, SLOT(slotStartRename())); + m_folderMenu->insertSeparator(); + m_folderMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + m_reloadMenuId = m_folderMenu->insertItem(SmallIcon("revert"), i18n("&Reload"), this, SLOT(slotReload())); + + addColumn(i18n("Upload Tree"), -1); + addColumn(""); + + connect(this, SIGNAL(open(QListViewItem *)), + this, SLOT(slotSelectFile(QListViewItem *))); + connect(this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotMenu(KListView*, QListViewItem*, const QPoint&))); + connect(Project::ref(), SIGNAL(reloadTree(ProjectList *, bool, const QStringList &)), + this, SLOT(slotReloadTree(ProjectList *, bool, const QStringList &))); + + restoreLayout(m_config, "UploadTreeView"); // a fixed name only for the tooltip configuration + // the restored size of the first column might be too large for the current content + // we set it to 10 and the listview will adjust it to the size of the largest entry + setColumnWidth(0, 10); + newBranch(url); +} + +ServerTreeView::~ServerTreeView() +{ +} + +KFileTreeBranch* ServerTreeView::newBranch(const KURL& url) +{ + KURL branchURL = url; + branchURL.adjustPath(+1); + BaseTreeBranch* newBrnch = 0; + newBrnch = new ServerTreeBranch(this, branchURL, branchURL.prettyURL(), SmallIcon("up"), true); + newBrnch->setShowingDotFiles(qConfig.showHiddenFiles); + addBranch(newBrnch); + return newBrnch; +} + + +/** RMB pressed, bring up the menu */ +void ServerTreeView::slotMenu(KListView* listView, QListViewItem *item, const QPoint &point) +{ + Q_UNUSED(listView); + if (item) + { + setSelected(item, true); + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if ( !curItem->isDir() ) + { + m_fileMenu->setItemVisible(m_menuClose, isFileOpen(currentURL())); + m_fileMenu->popup(point); + } else { + m_folderMenu->setItemVisible(m_menuPasteFolder, isPathInClipboard()); + bool root = (curItem == curItem->branch()->root()); + m_folderMenu->setItemVisible(m_menuDel, ! root); + m_folderMenu->setItemVisible(m_reloadMenuId, root); + m_folderMenu->setItemVisible(m_renameId, ! root); + m_folderMenu->popup(point); + } + } +} + + +void ServerTreeView::slotReloadTree( ProjectList *fileList, bool buildNewTree, const QStringList &folderToOpen) +{ + Q_UNUSED(fileList); + Q_UNUSED(buildNewTree); + Q_UNUSED(folderToOpen); + + QListViewItemIterator iter(this); + for ( ; iter.current(); ++iter ) + { + iter.current()->repaint(); + } +} + +#include "servertreeview.moc" diff --git a/quanta/treeviews/servertreeview.h b/quanta/treeviews/servertreeview.h new file mode 100644 index 00000000..c49b5a60 --- /dev/null +++ b/quanta/treeviews/servertreeview.h @@ -0,0 +1,92 @@ +/*************************************************************************** + servertreeview.h - description + ------------------- + begin : Thu Jun 1 2000 + copyright : (C) 2000 by Dmitry Poplavsky & Alexander Yakovlev & Eric Laffoon <pdima@users.sourceforge.net,yshurik@linuxfan.com,sequitur@easystreet.com> + (C) 2001-2004 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. * + * * + ***************************************************************************/ + +#ifndef SERVERTREEVIEW_H +#define SERVERTREEVIEW_H + +// quanta includes +#include "basetreeview.h" + +//foward declarations +class QListViewItem; +class QPoint; +class KPopupMenu; +class KURL; +class ProjectList; + +/** + TreeViewItem with special painter +*/ + +class ServerTreeViewItem : public BaseTreeViewItem { + +public: + ServerTreeViewItem( KFileTreeViewItem *parent, KFileItem* item, KFileTreeBranch *brnch ); + /** makes document not in project lighter */ + void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align); +}; + +/** + the branch for using @ref ServerTreeViewItem +*/ + +class ServerTreeBranch : public BaseTreeBranch { + +public: + ServerTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden = false, KFileTreeViewItem *branchRoot = 0L); + + /** check for CVS and visible*/ + virtual KFileTreeViewItem* createTreeViewItem(KFileTreeViewItem *parent, + KFileItem *fileItem ); +}; + + +class ServerTreeView : public BaseTreeView { + Q_OBJECT + +public: + ServerTreeView(KConfig *config, QWidget *parent, const KURL &url, const char *name = 0L); + virtual ~ServerTreeView(); + +protected slots: + + void slotMenu(KListView *listView, QListViewItem *item, const QPoint &point); + + /** repaints the treeview items, because they might be added to or removed from the project*/ + void slotReloadTree( ProjectList *fileList, bool buildNewTree, const QStringList &folderToOpen); + +protected: + KFileTreeBranch* newBranch(const KURL& url); + + KPopupMenu *m_fileMenu; + KPopupMenu *m_folderMenu; + int m_menuClose; ///< remembers the menu entry + int m_menuPasteFolder; ///< remembers the menu entry + int m_insertFileInProject; + int m_insertFolderInProject; + // config + KConfig *m_config; + +private: + int m_menuDel; + int m_reloadMenuId; + int m_renameId; +}; + +#endif diff --git a/quanta/treeviews/structtreetag.cpp b/quanta/treeviews/structtreetag.cpp new file mode 100644 index 00000000..2742bcea --- /dev/null +++ b/quanta/treeviews/structtreetag.cpp @@ -0,0 +1,217 @@ +/*************************************************************************** + structtreetag.cpp - description + ------------------- + begin : Sat Apr 29 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002, 2003 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. * + * * + ***************************************************************************/ +//qt include +#include <qregexp.h> + +// KDE includes +#include <kiconloader.h> +#include <klocale.h> + +// app includes +#include "structtreeview.h" +#include "structtreetag.h" +#include "messageoutput.h" +#include "tag.h" +#include "node.h" +#include "quantacommon.h" +#include "document.h" +#include "resource.h" + +StructTreeTag::StructTreeTag(QListView *parent, QString a_title) + : KListViewItem(parent, a_title) +{ + node = 0L; + hasOpenFileMenu = false; + groupTag = 0L; + parentTree = static_cast<StructTreeView*>(parent); +} + +StructTreeTag::StructTreeTag(StructTreeTag *parent, Node *a_node, const QString a_title, + QListViewItem *after ) +: KListViewItem(parent, after, a_title) +{ + parentTree = parent->parentTree; + hasOpenFileMenu = false; + groupTag = 0L; + static const QString space = " "; + static const QRegExp nbspRx(" |\\n"); + node = a_node; + if (node) + { + Tag *tag = node->tag; + QString title = tag->name.lower(); + if (a_title.isEmpty()) + { + switch (tag->type) + { + case Tag::XmlTag: + { + if (title == "font") + { + setPixmap( 0, UserIcon("tag_font_small") ); + if ( tag->attrCount() ) + title = space + tag->attribute(0) + "=" + tag->attributeValue(0); + else + title = ""; + } else + if (title == "img") + { + setPixmap( 0, SmallIcon("image") ); + title = space + tag->attributeValue("src"); + + } else + if (title == "a") + { + setPixmap( 0, SmallIcon("www") ); + if ( tag->hasAttribute("href") ) + title = space + "href "+ tag->attributeValue("href"); + if ( tag->hasAttribute("name") ) + title = space + "name "+ tag->attributeValue("name"); + } else + if ( title == "br") + { + setPixmap( 0, UserIcon("tag_br_small") ); + title = ""; + } else + if ( title == "hr") + { + setPixmap( 0, UserIcon("tag_hr_small") ); + title = ""; + } else + if ( title == "li") + { + setPixmap( 0, UserIcon("ball") ); + title = ""; + } else + if ( title == "p") + { + setPixmap( 0, UserIcon("tag_p") ); + title = ""; + } + + if (!typingInProgress) + { + QTag *parentQTag = 0L; + if (node->parent) + parentQTag = QuantaCommon::tagFromDTD(node->parent); + QString qTagName = node->tag->dtd()->caseSensitive ? node->tag->name : node->tag->name.upper(); + int line, col; + node->tag->beginPos(line, col); + if (parentQTag && !parentQTag->childTags.contains(qTagName) && + !parentQTag->childTags.isEmpty()) + { + node->tag->write()->setErrorMark(line); + QString parentTagName = node->tag->dtd()->caseSensitive ? node->parent->tag->name : node->parent->tag->name.upper(); + parentTree->showMessage(i18n("Line %1: %2 is not a possible child of %3.\n").arg(line + 1).arg(qTagName).arg(parentTagName)); + } + QString nextTagName; + if (node->next) + { + nextTagName = node->tag->dtd()->caseSensitive ? node->next->tag->name : node->next->tag->name.upper(); + } + parentQTag = QuantaCommon::tagFromDTD(node); + if (parentQTag && !parentQTag->isSingle() && + !parentQTag->isOptional() && + (!node->next || ( !node->getClosingNode())) ) + { + node->tag->write()->setErrorMark(line); + parentTree->showMessage(i18n("Line %1, column %2: Closing tag for %3 is missing.").arg(line + 1).arg(col + 1).arg(qTagName)); + } else + if (!parentQTag && node->tag->name.upper() != "!DOCTYPE") + { + node->tag->write()->setErrorMark(line); + parentTree->showMessage(i18n("Line %1, column %2: %3 is not part of %4.").arg(line + 1).arg(col + 1).arg(qTagName).arg(node->tag->dtd()->nickName)); + } + } + break; + } + case Tag::Text: + { + title = tag->tagStr(); + title = title.left(70).stripWhiteSpace(); + title.replace( nbspRx," "); + break; + } + case Tag::Comment: + { + setPixmap( 0, UserIcon("tag_comm") ); + title = tag->tagStr(); + title = title.left(70).stripWhiteSpace(); + title.replace( nbspRx," "); + break; + } + case Tag::ScriptTag: + { + title = tag->name; + break; + } + case Tag::Empty: + { + title = i18n("Empty tag"); + break; + } + case Tag::ScriptStructureBegin: + { + title = tag->cleanStr.stripWhiteSpace(); + break; + } + default: + { + if (!typingInProgress && node->tag->type == Tag::XmlTagEnd && !node->tag->name.isEmpty()) + { + int line, col; + node->tag->beginPos(line, col); + QString qTagName = node->tag->dtd()->caseSensitive ? node->tag->name : node->tag->name.upper(); + QString qPrevTagName; + if (node->prev) + qPrevTagName = node->tag->dtd()->caseSensitive ? node->prev->tag->name : node->prev->tag->name.upper(); + if (!node->prev || qTagName != "/" + qPrevTagName) + { + node->tag->write()->setErrorMark(line); + parentTree->showMessage(i18n("Line %1, column %2: Opening tag for %3 is missing.").arg(line + 1).arg(col + 1).arg(qTagName)); + } + } + title = tag->tagStr().left(70).stripWhiteSpace(); + } + + + } + } else + { + title = a_title; + } + + title.replace(newLineRx," "); + setText(0, title); + node->listItems.append(this); + } +} + +StructTreeTag::StructTreeTag(StructTreeTag *parent, QString a_title ) +: KListViewItem(parent, a_title) +{ + node = 0L; + hasOpenFileMenu = false; + groupTag = 0L; + parentTree = parent->parentTree; +} + + +StructTreeTag::~StructTreeTag(){ + if (node) + node->listItems.remove(node->listItems.find(this)); +} diff --git a/quanta/treeviews/structtreetag.h b/quanta/treeviews/structtreetag.h new file mode 100644 index 00000000..0b365b0c --- /dev/null +++ b/quanta/treeviews/structtreetag.h @@ -0,0 +1,45 @@ +/*************************************************************************** + structtreetag.h - description + ------------------- + begin : Sat Apr 29 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002, 2003 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. * + * * + ***************************************************************************/ + +#ifndef STRUCTTREETAG_H +#define STRUCTTREETAG_H + +#include <klistview.h> + +class Tag; +class Node; +class StructTreeView; +/**tag in structure widget + *@author Yacovlev Alexander & Dmitry Poplavsky & Andras Mantia + */ + +class StructTreeTag : public KListViewItem { + +public: + StructTreeTag(QListView *parent, const QString a_title = QString::null ); + StructTreeTag(StructTreeTag *parent, Node *a_node, const QString a_title = QString::null, QListViewItem *after = 0L); + StructTreeTag(StructTreeTag *parent, const QString a_title = QString::null ); + ~StructTreeTag(); + + Node *node; + bool hasOpenFileMenu; + Tag* groupTag; + QRegExp fileNameRx; + StructTreeView *parentTree; +}; + +#endif diff --git a/quanta/treeviews/structtreeview.cpp b/quanta/treeviews/structtreeview.cpp new file mode 100644 index 00000000..f6f55b40 --- /dev/null +++ b/quanta/treeviews/structtreeview.cpp @@ -0,0 +1,1071 @@ +/*************************************************************************** + structtreeview.cpp - description + ------------------- + begin : Sat Apr 29 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002, 2003 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. * + * * + ***************************************************************************/ + +// system headers +#include <assert.h> + +// QT headers +#include <qpixmap.h> +#include <qheader.h> +#include <qregexp.h> +#include <qdatetime.h> +#include <qdragobject.h> +#include <qcursor.h> + +// KDE headers +#include <kapplication.h> +#include <kiconloader.h> +#include <kpopupmenu.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kconfig.h> +#include <kdebug.h> +#include <ktexteditor/view.h> + +// app includes +#include "messageoutput.h" +#include "node.h" +#include "qtag.h" +#include "document.h" +#include "resource.h" +#include "qextfileinfo.h" +#include "quantacommon.h" +#include "dtds.h" +#include "viewmanager.h" +#include "kafkacommon.h" +#include "cursors.h" +#include "undoredo.h" +#include "quantaview.h" +#include "wkafkapart.h" + +#include "structtreetag.h" +#include "structtreeview.h" +#include "structtreeview.moc" +extern GroupElementMapList globalGroupMap; + +StructTreeView::StructTreeView(QWidget *parent, const char *name ) + : KListView(parent,name), m_marker(0), m_draggedItem(0)/*, m_thisWidget(0)*/ +{ + for (int i = 0; i < 15; i++) + groupOpened.append(false); + top = 0L; + lastTag = 0L; + groupsCount = 0; + followCursorFlag = true; + config = kapp->config(); + + topOpened = true; + useOpenLevelSetting = true; + + setRootIsDecorated( true ); + header()->hide(); + setSorting(-1,false); + setAcceptDrops(false); // disabled d&d is broken + setDropVisualizer(true); + setDragEnabled(false); // disabled d&d is broken +// setSelectionModeExt(FileManager); disabled d&d is broken + + setFrameStyle( Panel | Sunken ); + setLineWidth( 2 ); + addColumn( i18n("Name"), -1 ); + + setFocusPolicy(QWidget::ClickFocus); + + dtdMenu = new KPopupMenu(this); + + dtdMenu->insertItem(i18n("All Present DTEP")); + dtdMenu->insertSeparator(); + dtdList = DTDs::ref()->nickNameList(); + for(uint i = 0; i < dtdList.count(); i++ ) + { + dtdMenu->insertItem(dtdList[i], i, -1); + } + + connect(dtdMenu, SIGNAL(activated(int)), this, SLOT(slotDTDChanged(int))); + + connect(this, SIGNAL(dropped(QDropEvent*, QListViewItem*, QListViewItem*)), + SLOT(slotDropped(QDropEvent*, QListViewItem*, QListViewItem*))); + + emptyAreaMenu = new KPopupMenu(this); + emptyAreaMenu->insertItem(i18n("Show Groups For"), dtdMenu); + emptyAreaMenu->insertItem(SmallIcon("reload"), i18n("&Reparse"), this, SLOT(slotReparseMenuItem())); + + popupMenu = new KPopupMenu(this); + + popupMenu -> insertItem( i18n("Show Groups For"), dtdMenu); + popupMenu -> insertSeparator(); + popupMenu -> insertItem( i18n("Select Tag Area"), this ,SLOT(slotSelectTag())); + popupMenu -> insertItem( i18n("Go to End of Tag"), this ,SLOT(slotGotoClosingTag())); + openFileMenuId = popupMenu -> insertItem( i18n("Open File"), this ,SLOT(slotOpenFile())); + popupMenu -> insertSeparator(); + popupMenu -> insertItem( i18n("Open Subtrees"), this ,SLOT(slotOpenSubTree())); + popupMenu -> insertItem( i18n("Close Subtrees"),this ,SLOT(slotCloseSubTree())); + popupMenu -> insertSeparator(); +#if 0 + popupMenu -> insertItem( i18n("Remove"),this ,SLOT(slotRemoveTags())); + popupMenu -> insertSeparator(); +#endif + popupMenu -> insertItem( SmallIcon("reload"), i18n("&Reparse"), this ,SLOT(slotReparseMenuItem())); + followCursorId = popupMenu -> insertItem( i18n("Follow Cursor"), this ,SLOT(changeFollowCursor())); + + popupMenu -> setItemChecked ( followCursorId, followCursor() ); + + + connect( this, SIGNAL(mouseButtonPressed(int, QListViewItem*, const QPoint&, int)), + this, SLOT (slotMouseClicked(int, QListViewItem*, const QPoint&, int))); + + connect( this, SIGNAL(doubleClicked(QListViewItem *)), SLOT(slotDoubleClicked(QListViewItem *))); + + connect(this, SIGNAL(expanded(QListViewItem *)), SLOT(slotExpanded(QListViewItem *))); + connect(this, SIGNAL(collapsed(QListViewItem *)), SLOT(slotCollapsed(QListViewItem *))); + + write = 0L; + timer = new QTime(); + timer->start(); + m_dirty = true; +} + + +StructTreeView::~StructTreeView(){ + delete timer; +} + +/** builds the structure tree */ +void StructTreeView::buildTree(Node *baseNode, int openLevel, bool groupOnly) +{ +#ifdef DEBUG_PARSER + kdDebug(24000) << "Starting to rebuild the structure tree. Grouponly = " << groupOnly << endl; +#endif + if (!groupOnly) + { + top = new StructTreeTag( this, i18n("Document Structure") ); + top->setOpen(topOpened); + emit clearProblemOutput(); + } + Node *currentNode = baseNode; + StructTreeTag *currentItem = top; //after this + StructTreeTag *item = 0L; + StructTreeTag *parentItem = top; //under this + int level = 0; + QString title; + QString tagStr; + QString tmpStr; + int groupId = 0; + const DTDStruct* parsingDTD; + for (uint index = 0; index < m_parsingDTDList.count(); index++) + { + parsingDTD = m_parsingDTDList[index]; + if (parsingDTD->family == Script) + { + StructTreeGroup group; + uint gCount = parsingDTD->structTreeGroups.count(); + for (uint i = 0; i < gCount; i++) + { + group = parsingDTD->structTreeGroups[i]; + StructTreeTag *groupTag = new StructTreeTag(this, i18n(group.name.utf8()) + " [" + parsingDTD->nickName+"]"); + if (!group.icon.isEmpty()) + { + groupTag->setPixmap(0, SmallIcon(group.icon)); + } + groupTag->setOpen(groupOpened[groupId]); +#ifdef DEBUG_PARSER + kdDebug(24001) << "Grouptag created: " << groupId << " " << groupTag->text(0) << " "<< groupTag << endl; +#endif + groups.append(groupTag); + groupIds.insert(group.name + parsingDTD->name, groupId); + groupId++; + } + } else + { + QMap<QString, XMLStructGroup>::ConstIterator it; + for (it = parsingDTD->xmlStructTreeGroups.begin(); it != parsingDTD->xmlStructTreeGroups.end(); ++it) + { + XMLStructGroup group = it.data(); + StructTreeTag *groupTag = new StructTreeTag(this, i18n(group.name.utf8()) + " [" + parsingDTD->nickName+"]"); + if (!group.icon.isEmpty()) + { + groupTag->setPixmap(0, SmallIcon(group.icon)); + } + groupTag->setOpen(groupOpened[groupId]); +#ifdef DEBUG_PARSER + kdDebug(24001) << "Grouptag created: " << groupId << " " << groupTag->text(0) << " "<< groupTag << endl; +#endif + groups.append(groupTag); + groupIds.insert(group.name + parsingDTD->name, groupId); + groupId++; + } + + } + } + groupsCount = groupId; + QMap<QString, QListViewItem*> lastItemInGroup; + QMap<QString, QListViewItem*> groupItems; + while (currentNode) + { + if (!groupOnly) + { + title = ""; + item = new StructTreeTag(parentItem, currentNode, title, currentItem); + item->setOpen(level < openLevel); + currentNode->mainListItem = item; + + if ( (!qConfig.showEmptyNodes && currentNode->tag->type == Tag::Empty) || + (!qConfig.showClosingTags && + (currentNode->tag->type == Tag::XmlTagEnd || + currentNode->tag->type == Tag::ScriptStructureEnd) ) ) + { + item->setVisible(false); + } + } + const DTDStruct *dtd = currentNode->tag->dtd(); + //add all the group elements belonging to this node to the tree + for (QValueList<GroupElement*>::ConstIterator it = currentNode->m_groupElements.constBegin(); it != currentNode->m_groupElements.constEnd(); ++it) + { + GroupElement *groupElement = (*it); + if (!groupIds.contains(groupElement->group->name + dtd->name)) + continue; + StructTreeTag *groupItem = groups[groupIds[groupElement->group->name + dtd->name]]; + QListViewItem* insertAfter = 0L; + QListViewItem* insertUnder = groupItem; + if (groupItems.contains(groupElement->group->name + groupElement->tag->name)) + insertUnder = groupItems[groupElement->group->name + groupElement->tag->name]; + if (lastItemInGroup.contains(groupElement->group->name)) + insertAfter = lastItemInGroup[groupElement->group->name]; + + StructTreeTag *item = new StructTreeTag(static_cast<StructTreeTag*>(insertUnder), currentNode, groupElement->tag->name, insertAfter); + item->groupTag = groupElement->tag; + if (insertUnder == groupItem) + { + groupItems[groupElement->group->name + groupElement->tag->name] = item; + lastItemInGroup[groupElement->group->name] = item; + } + item->hasOpenFileMenu = groupElement->group->hasFileName; + item->fileNameRx = groupElement->group->fileNameRx; +#ifdef DEBUG_PARSER + kdDebug(24001) << "Tree element "<< groupElement->tag->tagStr() << "[" << groupElement->group->name<<"]"<< " inserted: " << item << " under " <<insertUnder << " after " << insertAfter << endl; +#endif + } + + //go to the child node, if it exists + if (currentNode->child) + { + currentNode = currentNode->child; + parentItem = item; + currentItem = 0L; + level++; + } else + { + //go to the next node if it exists + if (currentNode->next) + { + currentNode = currentNode->next; + currentItem = item; + } else + { + //go up some levels, to the parent, if the node has no child or next + while (currentNode) + { + level--; + //parentItem = dynamic_cast<StructTreeTag*>(parentItem->parent()); + if (currentNode->parent && currentNode->parent->next) + { + currentNode = currentNode->parent->next; + break; + } else + { + currentNode = currentNode->parent; + } + } + if (!groupOnly && currentNode) + { + if (currentNode->prev) + currentItem = static_cast<StructTreeTag*>(currentNode->prev->mainListItem); + if (currentNode->parent) + { + parentItem = static_cast<StructTreeTag*>(currentNode->parent->mainListItem); + if (!parentItem) + { + parentItem = top; + } + } + else + { + parentItem = top; + } + } + + } + } + } + //add the externally found items to the tree + QListViewItem *insertUnder; + QListViewItem *insertAfter; + QListViewItem *listItem; + GroupElementMapList::Iterator it; + IncludedGroupElementsMap::Iterator externalIt; + for (uint index = 0; index < m_parsingDTDList.count(); index++) + { + parsingDTD = m_parsingDTDList[index]; + if (parsingDTD->family == Script) + { + StructTreeGroup group; + uint gCount = parsingDTD->structTreeGroups.count(); + for (uint i = 0; i < gCount; i++) + { + group = parsingDTD->structTreeGroups[i]; + groupId = groupIds[group.name + parsingDTD->name]; + QString name = group.name+"|"; + StructTreeTag *groupTag = groups[groupId]; + for (externalIt = parser->includedMap.begin(); externalIt != parser->includedMap.end(); ++externalIt) + { + insertUnder = new StructTreeTag(static_cast<StructTreeTag*>(groupTag), 0L, externalIt.key(), groupTag); + insertAfter = insertUnder; + IncludedGroupElements elements = externalIt.data(); + GroupElementMapList::Iterator elIt; + for (elIt = elements[group.name].begin(); elIt != elements[group.name].end(); ++elIt) + { + listItem = new StructTreeTag(static_cast<StructTreeTag*>(insertUnder), elIt.data()[0]->node, elIt.key(), insertAfter); + static_cast<StructTreeTag*>(listItem)->hasOpenFileMenu = group.hasFileName; + static_cast<StructTreeTag*>(listItem)->fileNameRx = group.fileNameRx; + insertAfter = listItem; + } + if (!insertUnder->firstChild()) + delete insertUnder; + else + insertUnder->sortChildItems(0, true); + } + groupTag->sortChildItems(0, true); + } + } + } +} + +/** Delete the items */ +void StructTreeView::deleteList(bool groupOnly) +{ + if (!groupOnly && top ) + { + topOpened = top->isOpen(); + delete top; + top = 0L; + } + for (uint i = 0; i < groupsCount; i++) + { + groupOpened.append(groups[i]->isOpen()); +#ifdef DEBUG_PARSER + kdDebug(24001) << "Grouptag deleted: " << i << " " << groups[i]->text(0) << endl; +#endif + delete groups[i]; + } + groups.clear(); + groupIds.clear(); + groupsCount = 0; +} + +/** repaint document structure */ +void StructTreeView::slotReparse(Document *w, Node* node, int openLevel, bool groupOnly) +{ + timer->restart(); + if (typingInProgress) + return; + deleteList(groupOnly); + if (!node) + return; + write = w; + if (write) + write->clearAnnotations(); + write->clearErrorMarks(); + buildTree(node, openLevel, groupOnly); + + kdDebug(24000) << "StructTreeView building: " << timer->elapsed() << " ms\n"; + + const DTDStruct *parsingDTD; + int groupId = 0; + for (uint index = 0; index < m_parsingDTDList.count(); index++) + { + parsingDTD = m_parsingDTDList[index]; + if (parsingDTD->family == Script) + { + uint gCount = parsingDTD->structTreeGroups.count(); + for (uint i = 0; i < gCount; i++) + { + StructTreeTag *groupTag = groups[groupId]; + if (groupTag->childCount() == 0) + { + if (qConfig.showEmptyNodes) + { + //kdDebug(24000) << "No elements in group: " << groupId << " " << groupTag->text(0) << endl; + groupTag->setText(0, i18n(parsingDTD->structTreeGroups[i].noName.utf8()) + " [" + parsingDTD->nickName+"]"); + } else + { + groupTag->setVisible(false); + } + } + groupId++; + } + } else + { + QMap<QString, XMLStructGroup>::ConstIterator it; + uint i = 0; + for (it = parsingDTD->xmlStructTreeGroups.begin(); it != parsingDTD->xmlStructTreeGroups.end(); ++it) + { + StructTreeTag *groupTag = groups[groupId]; + if (groupTag->childCount() == 0) + { + if (qConfig.showEmptyNodes) + { + //kdDebug(24000) << "No elements in group: " << groupId << " " << groupTag->text(0) << endl; + groupTag->setText(0, i18n(it.data().noName.utf8()) + " [" + parsingDTD->nickName+"]"); + } else + { + groupTag->setVisible(false); + } + } + i++; + groupId++; + } + } + } + useOpenLevelSetting = false; + m_dirty = false; +} + +void StructTreeView::slotGotoTag( QListViewItem *item ) +{ + StructTreeTag *it = dynamic_cast<StructTreeTag*>(item); + if (!m_dirty && it && it->node && it->node->tag) + { + Tag *tag = new Tag(*it->node->tag); + int line, col; + tag->beginPos(line, col); + if (!it->node->fileName.isEmpty()) + { + KURL url; + QuantaCommon::setUrl(url, it->node->fileName); + emit openFile(url); + } + int el, ec; + tag->endPos(el, ec); +/* + kdDebug(24000) << "Node area: " << line << ", " << col << ", " << el << ", " << ec << endl; + kdDebug(24000) << "Node type: " << tag->type << endl; + kdDebug(24000) << "Node str: " << tag->tagStr() << endl; + kdDebug(24000) << "Node cleanstr: " << tag->cleanStr << endl; +*/ + if (tag->type == Tag::XmlTag || tag->type == Tag::XmlTagEnd) + col++; //position the cursor inside the tag + emit newCursorPosition(line, col); + Document *w = ViewManager::ref()->activeDocument(); + if (w) + w->view()->setFocus(); + delete tag; + } +} + + +void StructTreeView::slotMouseClicked(int button, QListViewItem *item, const QPoint& point, int dummy) +{ + if (item) + { + config->setGroup("Parser options"); + + QString handleMBM = config->readEntry("MBM", i18n("Select Tag Area")); + QString handleLBM = config->readEntry("LBM", i18n("Find tag")); + QString handleDoubleClick = config->readEntry("Double click", i18n("Select Tag Area")); + + setSelected(item, true); + + if (button == Qt::RightButton) + { + if (dynamic_cast<StructTreeTag*>(item)) + { + popupMenu->setItemVisible(openFileMenuId, static_cast<StructTreeTag*>(item)->hasOpenFileMenu); + } + popupMenu->popup(point); + return; + } + + if (button == Qt::LeftButton) + { + if (handleLBM == i18n("Find Tag && Open Tree")) + setOpen(item, !isOpen(item)); + setSelected(item, true); + + bool const ctrlPressed = KApplication::keyboardMouseState() & Qt::ControlButton; + + if(ctrlPressed) + setContiguousSelectedItems(); + + if(ViewManager::ref()->activeView()->hadLastFocus() == QuantaView::VPLFocus) + slotMouseClickedVPL(button, item, point, dummy); + else + slotGotoTag(item); + } + + if (button == Qt::MidButton) + { + if (handleMBM == i18n("nothing")) + return; + + if (handleMBM == i18n("Find Tag && Open Tree")) + { + setOpen(item, !isOpen(item)); + setSelected(item, true); + slotGotoTag(item); + } + + if (handleMBM == i18n("Select Tag Area")) + slotSelectTag(); + + if (handleMBM == i18n("Go to End of Tag")) + slotGotoClosingTag(); + + setSelected(item, true); + } + } else + if (button == Qt::RightButton) + emptyAreaMenu->popup(point); +} + + +void StructTreeView::slotDoubleClicked( QListViewItem *item) +{ + config->setGroup("Parser options"); + + if ( config->readEntry("Double click") != i18n("nothing") ) + { + slotSelectTag(); + } else + { + item->setOpen(!item->isOpen()); + } +} + + + +void StructTreeView::slotReparseMenuItem() +{ + useOpenLevelSetting = true; + emit needReparse(); +} + +void StructTreeView::slotGotoClosingTag() +{ + QListViewItem *item = currentItem(); + StructTreeTag *it = dynamic_cast<StructTreeTag*>(item); + if (!m_dirty && it && it->node) + { + int newLine, newCol; + Tag *tag = it->node->tag; + if (tag->single || !it->node->next) + { + tag->endPos(newLine, newCol); + } else + { + if (tag->closingMissing) + { + Node *node = it->node; + while (node->child) node = node->child; + node->tag->endPos(newLine, newCol); + } else + { + it->node->next->tag->endPos(newLine, newCol); + } + } + + emit newCursorPosition( newLine, newCol + 1 ); + } +} + +void StructTreeView::slotSelectTag() +{ + bool newFileOpened = false; + QListViewItem *item = currentItem(); + StructTreeTag *it = dynamic_cast<StructTreeTag*>(item); + if (!m_dirty && it && it->node) + { + int bLine, bCol, eLine, eCol; + if (it->node->fileName.isEmpty()) + { + if (it->groupTag) + { + Tag *tag = it->groupTag; + tag->beginPos(bLine, bCol); + tag->endPos(eLine, eCol); + } else + { + Tag *tag = it->node->tag; + if (tag->single || !it->node->next) + { + tag->endPos(eLine, eCol); + } else + { + emit selectTagArea(it->node); + return; + } + tag->beginPos(bLine, bCol); + } + } else + { + KURL url; + QuantaCommon::setUrl(url, it->node->fileName); + it->node->tag->beginPos(bLine, bCol); + it->node->tag->endPos(eLine, eCol); + eCol--; + emit openFile(url); + newFileOpened = true; + + } + emit selectArea( bLine, bCol, eLine, eCol + 1); + + if (!newFileOpened) + { + setSelected(item, true); + it->node->tag->write()->view()->setFocus(); + } + } +} + + +/** Do the recursive opening or closing of the trees */ +void StructTreeView::setOpenSubTree( QListViewItem *it, bool open) +{ + if (it) + { + it->setOpen(open); + setOpenSubTree( it->nextSibling(), open ); + setOpenSubTree( it->firstChild(), open ); + } +} + +/** Recursively open the tree and all its subtrees */ +void StructTreeView::slotOpenSubTree() +{ + QListViewItem *item = currentItem(); + if (item) + { + item->setOpen( true ); + setOpenSubTree( item->firstChild(), true ); + } +} + + +/** Recursively close the tree and all its subtrees */ +void StructTreeView::slotCloseSubTree() +{ + QListViewItem *item = currentItem(); + if (item) + { + item->setOpen( false ); + setOpenSubTree( item->firstChild(), false ); + } +} + +/** Show the element in tree according to cursor position (x,y) */ +void StructTreeView::showTagAtPos(Node *node) +{ + if (followCursorFlag) + { + if (node && node->mainListItem) + { + clearSelection(); + ensureItemVisible(node->mainListItem); + setSelected(node->mainListItem, true); + } + } //if (followCursorFlag) +} + +void StructTreeView::setFollowCursor(bool follow) +{ + followCursorFlag = follow; + popupMenu->setItemChecked(followCursorId, follow); +} + +/** No descriptions */ +void StructTreeView::slotExpanded(QListViewItem *item) +{ + StructTreeTag *it = dynamic_cast<StructTreeTag*>(item); + if (!m_dirty && it && it->node) + it->node->opened = true; +} + +/** No descriptions */ +void StructTreeView::slotCollapsed(QListViewItem *item) +{ + StructTreeTag *it = dynamic_cast<StructTreeTag*>(item); + if (!m_dirty && it && it->node) + it->node->opened = false; +} +/** Do a reparse before showing. */ +void StructTreeView::showEvent(QShowEvent* /*ev*/) +{ + slotReparseMenuItem(); +} + +/** Do a reparse before showing. */ +void StructTreeView::hideEvent(QHideEvent* /*ev*/) +{ + emit clearProblemOutput(); +} + +enum { + DRAG_COPY = 0, + DRAG_MOVE = 1, + DRAG_CANCEL = 2 +}; + +void StructTreeView::setContiguousSelectedItems() +{ + kdDebug(25001) << "setContiguousSelectedItems" << endl; + + QPtrList<QListViewItem> selected_items = selectedItems(false); + + QListViewItem* first = selected_items.getFirst(); + QListViewItem* last = selected_items.getLast(); + + QListViewItemIterator it(first); + while(it.current() && it.current() != last) + { + QListViewItem* item = it.current(); + if(!item->isSelected()) + item->setSelected(true); + + ++it; + } +} + +bool StructTreeView::acceptDrag(QDropEvent* e) const +{ + static int i = 0; + kdDebug(25001) << "acceptDrag: " << ++i << endl; + + QPoint p = contentsToViewport(e->pos()); + QListViewItem* current_item = itemAt(p); + +// assert(m_thisWidget); + + static bool last_accept = false; + + if(current_item == m_marker) + { + e->accept(last_accept); +/* if(last_accept) + m_thisWidget->setCursor(Qt::ForbiddenCursor); + else + m_thisWidget->setCursor(Qt::ForbiddenCursor);*/ + kdDebug(25001) << "Princ�io: " << last_accept << endl; + + return last_accept; + } + else + m_marker = current_item; + + if(current_item == m_draggedItem || + !(e->provides("text/x-struct_tree_tag_item") || e->source() == (QWidget *)this) || !m_marker) + { + e->accept(false); + last_accept = false; +/* if(last_accept) + m_thisWidget->setCursor(Qt::ForbiddenCursor); + else + m_thisWidget->setCursor(Qt::ForbiddenCursor);*/ + kdDebug(25001) << "PROIBIDO! #1" << endl; + return false; + } + + Node* dragged_node = (dynamic_cast<StructTreeTag*> (m_draggedItem))->node; + Node* after_node = (dynamic_cast<StructTreeTag*> (m_marker))->node; + if(!after_node) + { + e->accept(false); + last_accept = false; +/* if(last_accept) + m_thisWidget->setCursor(Qt::ForbiddenCursor); + else + m_thisWidget->setCursor(Qt::ForbiddenCursor);*/ + kdDebug(25001) << "PROIBIDO! #2" << endl; + return false; + } + QTag* nodeQTag = QuantaCommon::tagFromDTD(after_node->parent); + bool is_child = (nodeQTag && nodeQTag->isChild(dragged_node)); + + if(!is_child) + kdDebug(25001) << "PROIBIDO! #3" << endl; + else + kdDebug(25001) << "ACEITE!" << endl; + + e->accept(is_child); + last_accept = is_child; +// if(last_accept) +// m_thisWidget->setCursor(Qt::ForbiddenCursor); +// else +// m_thisWidget->setCursor(Qt::ForbiddenCursor); + + return is_child; +} + +void StructTreeView::slotDropped(QDropEvent* e, QListViewItem* parent, QListViewItem* after) +{ + if(!e) + return; + if (e->source() != this) + return; // Only internal drags are supported atm + + if(!QTextDrag::canDecode(e)) + return; + + KPopupMenu *menu = new KPopupMenu( this ); + menu->insertItem( i18n("&Move Here"), DRAG_MOVE, 0 ); + menu->insertItem( SmallIcon("editcopy"), i18n("&Copy Here"), DRAG_COPY, 1 ); + menu->insertSeparator(); + menu->insertItem( SmallIcon("cancel"), i18n("C&ancel"), DRAG_CANCEL, 3 ); + int id = menu->exec(QCursor::pos(), 0); + + switch(id) { + case DRAG_COPY: + copySelectedItems(parent, after); + break; + case DRAG_MOVE: + moveSelectedItems(parent, after); + break; + case DRAG_CANCEL: // cancelled by menuitem + break; + case -1: // cancelled by Esc + break; + default: + break; + } + + m_draggedItem = 0; +} + +void StructTreeView::startDrag() +{ + // This a dummy drag object. Decode is made by the objects selected on the tree. + QTextDrag* drag = new QTextDrag(this); +// m_thisWidget = drag->source(); + drag->setSubtype("x-struct_tree_tag_item"); + drag->setPixmap(SmallIcon("node")); + drag->dragMove(); + +} + +void StructTreeView::contentsMousePressEvent(QMouseEvent* e) +{ + if(e->button() == LeftButton) + { + QPoint p = contentsToViewport(e->pos()); + m_draggedItem = itemAt(p); + m_marker = m_draggedItem; + } + KListView::contentsMousePressEvent(e); +} + +void StructTreeView::copySelectedItems(QListViewItem* parent, QListViewItem* after) +{ + StructTreeTag* parent_item = dynamic_cast<StructTreeTag*> (parent); + StructTreeTag* after_item = dynamic_cast<StructTreeTag*> (after); + if(!parent_item/* || !after_item*/) // can happen if the element is inserted as the first child + return; + + QPtrList<QListViewItem> selected_items = selectedItems(false); + QListViewItem* first_item = selected_items.getFirst(); + QListViewItem* last_item = selected_items.getLast(); + + Node* start_node = (dynamic_cast<StructTreeTag*> (first_item))->node; + Node* end_node = (dynamic_cast<StructTreeTag*> (last_item))->node; + assert(start_node && end_node); + + Node* start_node_subtree = 0; + if(start_node == end_node) + start_node_subtree = kafkaCommon::duplicateNodeSubtree(start_node, true); + else + start_node_subtree = kafkaCommon::getNodeSubtree(start_node, 0, end_node, end_node->tag->tagStr().length()); + + Node* parent_node = parent_item->node; + if(!parent_node) + return; + Node* next_node = 0; + if(after_item) + next_node = after_item->node->SNext(); + else + next_node = parent_node->firstChild(); + + NodeSelection cursor_holder; + NodeModifsSet *modifs = new NodeModifsSet(); + + kafkaCommon::DTDInsertNodeSubtree(start_node_subtree, parent_node, next_node, cursor_holder, modifs); + + write->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif, 0, false); +} + +void StructTreeView::moveSelectedItems(QListViewItem* parent, QListViewItem* after) +{ + StructTreeTag* parent_item = dynamic_cast<StructTreeTag*> (parent); + StructTreeTag* after_item = dynamic_cast<StructTreeTag*> (after); + if(!parent_item || !after_item) + return; + + QPtrList<QListViewItem> selected_items = selectedItems(false); + QListViewItem* first_item = selected_items.getFirst(); + QListViewItem* last_item = selected_items.getLast(); + + Node* start_node = (dynamic_cast<StructTreeTag*> (first_item))->node; + Node* end_node = (dynamic_cast<StructTreeTag*> (last_item))->node; + assert(start_node && end_node); + + Node* cursor_node = 0; + long cursor_offset = 0; + NodeModifsSet *modifs = new NodeModifsSet(); + + Node* start_node_subtree = 0; + if(start_node == end_node) + start_node_subtree = kafkaCommon::extractNodeSubtreeAux(start_node, end_node, modifs); + else + start_node_subtree = kafkaCommon::DTDExtractNodeSubtree(start_node, 0, end_node, end_node->tag->tagStr().length(), + &cursor_node, cursor_offset, modifs); + + Node* parent_node = parent_item->node; + if(!parent_node) + return; + Node* next_node = after_item->node->SNext(); + + NodeSelection cursor_holder(cursor_node, cursor_offset); + + kafkaCommon::DTDInsertNodeSubtree(start_node_subtree, parent_node, next_node, cursor_holder, modifs); + + write->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif, &cursor_holder, false); +} + +/** The treeview DTD has changed to id. */ +void StructTreeView::slotDTDChanged(int id) +{ + QString text = dtdMenu->text(id); + if (dtdMenu->indexOf(id) > 0) + { + QString dtdName = DTDs::ref()->getDTDNameFromNickName(text); + emit showGroupsForDTEP(dtdName, !dtdMenu->isItemChecked(id)); + } else + emit showGroupsForDTEP("clear", true); +} + +void StructTreeView::setParsingDTDs(const QStringList &parsingDTDList) +{ + m_parsingDTDList.clear(); + for (uint i = 0; i < dtdList.count(); i++) + { + dtdMenu->setItemChecked(i, false); + } + QString dtdNickName; + for (QStringList::ConstIterator it = parsingDTDList.constBegin(); it != parsingDTDList.constEnd(); ++it) + { + dtdNickName = DTDs::ref()->getDTDNickNameFromName(*it); + for (uint i = 0; i < dtdList.count(); i++) + { + if (dtdList[i] == dtdNickName) + dtdMenu->setItemChecked(i, true); + } + m_parsingDTDList.append(DTDs::ref()->find(*it)); + } +} + +void StructTreeView::slotOpenFile() +{ + StructTreeTag *item = dynamic_cast<StructTreeTag*>(currentItem()); + if (!m_dirty && item->node) + { + QString text = item->groupTag->name; + text.remove(item->fileNameRx); + KURL baseUrl = QExtFileInfo::path(write->url()); + KURL url = baseUrl; + QuantaCommon::setUrl(url, text.stripWhiteSpace()); + url = QExtFileInfo::toAbsolute(url, baseUrl); + if (QExtFileInfo::exists(url, true, this)) + { + if (QuantaCommon::checkMimeGroup(url, "text" )) + { + emit openFile(url); + } + else if (QuantaCommon::checkMimeGroup(url," image" )) + { + emit openImage(url); + } + } else + KMessageBox::error(this, i18n("<qt>The file <b>%1</b> does not exist or is not a recognized mime type.</qt>").arg(url.prettyURL(0, KURL::StripFileProtocol))); + } +} + +void StructTreeView::slotNodeTreeChanged() +{ + m_dirty = true; +} + +void StructTreeView::showMessage(const QString& message) +{ + emit showProblemMessage(message); +} + +void StructTreeView::slotMouseClickedVPL(int /*button*/, QListViewItem* item, const QPoint&, int) +{ + ViewManager::ref()->activeView()->setFocus(); + + QPtrList<QListViewItem> selected_items = selectedItems(true); + if(selected_items.count() == 1) + { + StructTreeTag* tag_item = dynamic_cast<StructTreeTag*> (item); + if(!tag_item) + return; + Node* node = tag_item->node; + if(!node) + return; + if(node->tag->type == Tag::Text || node->tag->type == Tag::Empty) + { + KafkaDocument::ref()->setCursor(node, 0); + } + } + else + { + Node* start_node = (dynamic_cast<StructTreeTag*> (selected_items.getFirst()))->node; + Node* end_node = (dynamic_cast<StructTreeTag*> (selected_items.getLast()))->node; + + NodeSelectionInd selection(start_node, 0, end_node, 1/*end_node->tag->tagStr().length()*/); + KafkaDocument::ref()->setCursorAndSelection(&selection); + } +} + +void StructTreeView::slotRemoveTags() +{ + QPtrList<QListViewItem> selected_items = selectedItems(true); + + Node* start_node = (dynamic_cast<StructTreeTag*> (selected_items.getFirst()))->node; + Node* end_node = start_node; + if(selected_items.count() > 1) + end_node = (dynamic_cast<StructTreeTag*> (selected_items.getLast()))->node; + + kafkaCommon::coutTree(start_node, 3); + + Node* cursor_node = 0; + long cursor_offset = 0; + + NodeModifsSet *modifs = new NodeModifsSet(); + kafkaCommon::DTDExtractNodeSubtree(start_node, 0, end_node, end_node->tag->tagStr().length(), &cursor_node, cursor_offset, modifs); + + NodeSelection* selection = new NodeSelection(cursor_node, cursor_offset); + + write->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif, selection, false); +} + diff --git a/quanta/treeviews/structtreeview.h b/quanta/treeviews/structtreeview.h new file mode 100644 index 00000000..4f59e7d3 --- /dev/null +++ b/quanta/treeviews/structtreeview.h @@ -0,0 +1,176 @@ +/*************************************************************************** + structtreeview.h - description + ------------------- + begin : Sat Apr 29 2000 + copyright : (C) 2000 by Yacovlev Alexander & Dmitry Poplavsky <pdima@mail.univ.kiev.ua> + (C) 2002, 2003 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. * + * * + ***************************************************************************/ + +#ifndef STRUCTTREEVIEW_H +#define STRUCTTREEVIEW_H + +#include <qmap.h> +#include <qvaluelist.h> + +#include <klistview.h> + +/**view class of document structure + *@author Andras Mantia & Paulo Moura Guedes & Yacovlev Alexander & Dmitry Poplavsky + */ + +class KPopupMenu; +class KConfig; +class KURL; +class QTime; + +class Node; +class StructTreeTag; +class Parser; +class Document; +struct DTDStruct; + +class StructTreeView : public KListView { + Q_OBJECT +public: + + /** + * since this class is a singleton you must use this function to access it + * + * the parameters are only used at the first call to create the class + * + */ + static StructTreeView* const ref(QWidget *parent = 0L, const char *name = 0L) + { + static StructTreeView *m_ref; + if (!m_ref) m_ref = new StructTreeView (parent, name); + return m_ref; + } + + ~StructTreeView(); + + + void setFollowCursor(bool); + bool followCursor() { return followCursorFlag; } + /** Show the element in tree according to cursor position (x,y) */ + void showTagAtPos(Node *node); + /** Delete the items */ + void deleteList(bool groupOnly); + void setParsingDTDs(const QStringList &parsingDTDList); + void showMessage(const QString& message); + + + bool useOpenLevelSetting; + +public slots: // Public slots + /** repaint document structure */ + void slotReparse(Document *w, Node* node, int openLevel = 3,bool groupOnly=false); + void slotMouseClicked(int button, QListViewItem*, const QPoint&, int); + void slotDoubleClicked( QListViewItem * ); + + // slots for RBM menu + void slotReparseMenuItem(); + void slotSelectTag(); + void slotGotoTag( QListViewItem *item ); + void slotGotoClosingTag(); + /** Recursively open the tree and all its subtrees */ + void slotOpenSubTree(); + /** Recursively close the tree and all its subtrees */ + void slotCloseSubTree(); + void changeFollowCursor() { setFollowCursor(!followCursorFlag); } + /** No descriptions */ + void slotCollapsed(QListViewItem *item); + /** No descriptions */ + void slotExpanded(QListViewItem *); + void slotOpenFile(); + void slotNodeTreeChanged(); + void slotRemoveTags(); + +signals: + void newCursorPosition( int col, int row ); + void selectTagArea(Node* node); + void selectArea(int col1, int row1, int col2, int row2 ); + void needReparse(); + void onTag( const QString &tag ); + void showGroupsForDTEP(const QString& dtep, bool show); + void openFile(const KURL&); + void openImage(const KURL&); + void showProblemMessage(const QString&); + void clearProblemOutput(); + +private: + + /** The constructor is private because we use singleton pattern. + * If you need the class use StructTreeView::ref() for + * construction and reference + */ + StructTreeView(QWidget *parent=0, const char *name=0); + /** builds the structure tree */ + void buildTree(Node *baseNode, int openLevel, bool groupOnly); + /** Do the recursive opening or closing of the trees */ + void setOpenSubTree(QListViewItem *it, bool open); + + /** Make ctrl have the same behavior has shift */ + void setContiguousSelectedItems(); + + void copySelectedItems(QListViewItem* parent, QListViewItem* after); + void moveSelectedItems(QListViewItem* parent, QListViewItem* after); + +private: + + int followCursorId; + bool followCursorFlag; + + KPopupMenu *popupMenu; + KPopupMenu *emptyAreaMenu; + KPopupMenu *dtdMenu; + StructTreeTag *lastTag; + KConfig *config; + QStringList dtdList; + QValueList<const DTDStruct*> m_parsingDTDList; + int openFileMenuId; + QMap<QString, uint> groupIds; + bool m_dirty; + StructTreeTag *top; + QValueList<StructTreeTag*> groups; + uint groupsCount; + + bool topOpened; + QValueList<bool> groupOpened; + + mutable QListViewItem* m_marker; //track that has the drag/drop marker under it + QListViewItem* m_draggedItem; +// mutable QWidget* m_thisWidget; // non const this hack for acceptDrag + +protected: // Protected methods + /** Do a reparse before showing. */ + virtual void showEvent(QShowEvent*); + /** Clear the problem output when hiding. */ + virtual void hideEvent(QHideEvent*); + + // drag functions + virtual bool acceptDrag(QDropEvent* e) const; + virtual void startDrag(); + virtual void contentsMousePressEvent(QMouseEvent* e); + +protected slots: // Protected slots + /** The treeview DTD has changed to id. */ + void slotDTDChanged(int id); + + void slotMouseClickedVPL(int button, QListViewItem*, const QPoint&, int); + virtual void slotDropped(QDropEvent* e, QListViewItem* parent, QListViewItem* after); + +protected: // Protected attributes + Document *write; + QTime *timer; +}; + +#endif diff --git a/quanta/treeviews/tagattributeitems.cpp b/quanta/treeviews/tagattributeitems.cpp new file mode 100644 index 00000000..4b74217d --- /dev/null +++ b/quanta/treeviews/tagattributeitems.cpp @@ -0,0 +1,538 @@ +/*************************************************************************** + tagattributeitems.cpp + --------------------- + copyright : (C) 2003 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +//qt includes +#include <qcombobox.h> +#include <qheader.h> +#include <qlineedit.h> +#include <qlistbox.h> +#include <qpainter.h> +#include <qstyle.h> + +//kde includes +#include <dcopref.h> +#include <kapplication.h> +#include <kcolorcombo.h> +#include <klistview.h> +#include <klocale.h> +#include <kurlrequester.h> +#include <kdebug.h> + +//app includes +#include "tagattributeitems.h" +#include "tagattributetree.h" +#include "node.h" +#include "tag.h" +#include "qtag.h" +#include "document.h" +#include "quantacommon.h" +#include "qextfileinfo.h" +#include "styleeditor.h" + +TopLevelItem::TopLevelItem(KListView* parent, const QString &title) +: KListViewItem(parent, title) +{ +} + +TopLevelItem::TopLevelItem(KListView* parent, QListViewItem* after, const QString &title) +: KListViewItem(parent, after, title) +{ +} + +TopLevelItem::~TopLevelItem() +{ +} + + +void TopLevelItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int align) +{ + if ( !p ) + return; + + // make toplevel item names bold + if (column == 0 && !parent()) + { + QFont f = p->font(); + f.setBold(true); + p->setFont(f); + } + KListViewItem::paintCell( p, cg, column, width, align ); + if (column == 0) + { + p->setPen(QPen(QColor(0,0,0))); + p->drawLine( width - 1, 0, width - 1, height()); + } +} + +ParentItem::ParentItem(TagAttributeTree *listView, QListViewItem* parent) +: KListViewItem(parent) +{ + m_listView = listView; + comboBox = new QComboBox(false, m_listView->viewport() ); + QRect r = m_listView->itemRect( this ); + if ( !r.size().isValid() ) + { + m_listView->ensureItemVisible( this ); + r = m_listView->itemRect( this ); + } + r.setX( m_listView->header()->sectionPos( 0 ) + 20); + r.setWidth( m_listView->header()->sectionSize( 0 ) - 20); + r = QRect( m_listView->viewportToContents( r.topLeft() ), r.size() ); + comboBox->resize( r.size() ); + m_listView->moveChild( comboBox, r.x(), r.y() ); +} + +ParentItem::~ParentItem() +{ + delete comboBox; +} + + +void ParentItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int align) +{ + if ( !p ) + return; + + KListViewItem::paintCell( p, cg, column, width, align ); + if (column == 0) + { + p->setPen(QPen(QColor(0,0,0))); + p->drawLine( width - 1, 0, width - 1, height()); + } +} + +void ParentItem::addNode(Node *node) +{ + if (node) + { + m_nodeList.append(node); + comboBox->insertItem(node->tag->name); + } +} + +Node* ParentItem::node(int index) +{ + return m_nodeList.at(index); +} + +void ParentItem::showList(bool show) +{ + if (show) + { + comboBox->show(); + QObject::connect(comboBox, SIGNAL(activated(int)), m_listView, SLOT(slotParentSelected(int))); + } + else + { + comboBox->hide(); + QObject::disconnect(comboBox, SIGNAL(activated(int)), m_listView, SLOT(slotParentSelected(int))); + } +} + +//Generic attribute item +AttributeItem::AttributeItem(QListViewItem* parent, const QString &title, const QString& title2) +: KListViewItem(parent, title, title2) +{ + lin = 0L; + lin2 = 0L; +} + +AttributeItem::AttributeItem(EditableTree* listView, QListViewItem* parent, const QString &title, const QString& title2) +: KListViewItem(parent, title, title2) +{ + m_listView = listView; + lin = new QLineEdit( m_listView->viewport() ); + lin2 = new QLineEdit( m_listView->viewport() ); + QObject::connect( lin, SIGNAL( returnPressed() ), m_listView, SLOT( editorContentChanged() ) ); + lin->hide(); + lin2->hide(); +} + +AttributeItem::AttributeItem(EditableTree *listView, const QString& title, const QString& title2) +: KListViewItem(listView, title, title2) +{ + m_listView = listView; + lin = new QLineEdit( m_listView->viewport() ); + lin2 = new QLineEdit( m_listView->viewport() ); + lin2->setText(title); + lin->setText(title2); + QObject::connect( lin, SIGNAL( returnPressed() ), m_listView, SLOT( editorContentChanged() ) ); + lin->hide(); + lin2->hide(); +} + +AttributeItem::AttributeItem(EditableTree *listView, const QString& title, const QString& title2, + QListViewItem* after) +: KListViewItem(listView, after, title, title2) +{ + m_listView = listView; + lin = new QLineEdit( m_listView->viewport() ); + lin2 = new QLineEdit( m_listView->viewport() ); + lin2->setText(title); + lin->setText(title2); + QObject::connect( lin, SIGNAL( returnPressed() ), m_listView, SLOT( editorContentChanged() ) ); + lin->hide(); + lin2->hide(); +} + +AttributeItem::~AttributeItem() +{ + delete lin; + delete lin2; +} + +void AttributeItem::paintCell(QPainter *p, const QColorGroup &cg, + int column, int width, int align) +{ + if ( !p ) + return; + KListViewItem::paintCell( p, cg, column, width, align ); + if (column == 0) + { + p->setPen(QPen(QColor(0,0,0))); + p->drawLine( width - 1, 0, width - 1, height()); + } +} + +QString AttributeItem::editorText(int column) +{ + if(column == 1) + return lin->text(); + else + return lin2->text(); +} + +void AttributeItem::replaceCurrentEditor() +{ + if(lin->isVisible()) + { + placeEditor(lin, 1); + } + else if(lin2->isVisible()) + { + placeEditor(lin, 0); + } +} + +void AttributeItem::showEditor(int column) +{ + if(column == 1) + { + placeEditor(lin, column); + lin->show(); + lin->setText(text(1)); + lin->setFocus(); + } + else + { + placeEditor(lin2, column); + lin2->show(); + lin2->setText(text(0)); + lin2->setFocus(); + } +} + +void AttributeItem::hideEditor(int column) +{ + m_listView->editorContentChanged(); + if(column == 1 && lin->isVisible()) + { + setText(1, lin->text()); + lin->hide(); + } + else if(column == 0 && lin2->isVisible()) + { + setText(0, lin2->text()); + lin2->hide(); + } +} + +void AttributeItem::placeEditor( QWidget *w, int column) +{ + QRect r = m_listView->itemRect( this ); + if ( !r.size().isValid() ) + { + m_listView->ensureItemVisible( this ); + r = m_listView->itemRect( this ); + } + if(column == 1) + { + r.setX( m_listView->header()->sectionPos( 1 ) ); + r.setWidth( m_listView->header()->sectionSize( 1 ) - 1 ); + } + else + { + r.setX( m_listView->header()->sectionPos( 0 ) ); + r.setWidth( m_listView->header()->sectionSize( 0 ) - 1 ); + } + r = QRect( m_listView->viewportToContents( r.topLeft() ), r.size() ); + w->resize( r.size() ); + m_listView->moveChild( w, r.x(), r.y() ); +} + +//Boolean attribute item +AttributeBoolItem::AttributeBoolItem(TagAttributeTree* listView, QListViewItem* parent, const QString &title, const QString& title2) +: AttributeItem(parent, title, title2) +{ + m_listView = listView; + combo = new QComboBox( m_listView->viewport() ); + combo->insertItem((static_cast<TagAttributeTree *>(m_listView))->node()->tag->dtd()->booleanTrue); + combo->insertItem((static_cast<TagAttributeTree *>(m_listView))->node()->tag->dtd()->booleanFalse); + combo->hide(); + QObject::connect( combo, SIGNAL( activated(int) ), m_listView, SLOT( editorContentChanged() ) ); + } + +AttributeBoolItem::~AttributeBoolItem() +{ + delete combo; +} + +QString AttributeBoolItem::editorText(int) +{ + return combo->currentText(); +} + +void AttributeBoolItem::showEditor(int) +{ + placeEditor(combo); + combo->show(); + if (text(1) == (static_cast<TagAttributeTree *>(m_listView))->node()->tag->dtd()->booleanTrue) + combo->setCurrentItem(0); + else + combo->setCurrentItem(1); + combo->setFocus(); +} + +void AttributeBoolItem::hideEditor(int) +{ + m_listView->editorContentChanged(); + setText(1, combo->currentText()); + combo->hide(); +} + +//Boolean attribute item +AttributeUrlItem::AttributeUrlItem(TagAttributeTree* listView, QListViewItem* parent, const QString &title, const QString& title2) +: AttributeItem(parent, title, title2) +{ + m_listView = listView; + urlRequester = new KURLRequester( m_listView->viewport() ); + urlRequester->setMode(KFile::File | KFile::ExistingOnly ); + urlRequester->hide(); + QObject::connect( urlRequester, SIGNAL( returnPressed() ), m_listView, SLOT( editorContentChanged() ) ); + } + +AttributeUrlItem::~AttributeUrlItem() +{ + delete urlRequester; +} + +QString AttributeUrlItem::editorText(int) +{ + KURL url, baseURL; + QuantaCommon::setUrl(url, urlRequester->url()); + baseURL = (static_cast<TagAttributeTree *>(m_listView))->node()->tag->write()->url(); + baseURL.setPath(baseURL.directory()); + url = QExtFileInfo::toRelative(url, baseURL); + QString s = url.url(); + if (url.protocol() == (static_cast<TagAttributeTree *>(m_listView))->node()->tag->write()->url().protocol()) + s.remove(0, url.protocol().length() + 3); + return s; +} + +void AttributeUrlItem::showEditor(int) +{ + placeEditor(urlRequester); + urlRequester->show(); + KURL url, baseURL; + baseURL = (static_cast<TagAttributeTree *>(m_listView))->node()->tag->write()->url(); + baseURL.setPath(baseURL.directory()); + QuantaCommon::setUrl(url, text(1)); + url= QExtFileInfo::toAbsolute(url, baseURL); + urlRequester->setURL(url.url()); + urlRequester->setFocus(); +} + +void AttributeUrlItem::hideEditor(int) +{ + m_listView->editorContentChanged(); + setText(1, editorText()); + urlRequester->hide(); +} + + +//editable listbox +//Boolean attribute item +AttributeListItem::AttributeListItem(EditableTree* listView, QListViewItem* parent, const QString &title, const QString& title2, Attribute *attr) +: AttributeItem(parent, title, title2) +{ + m_listView = listView; + combo = new QComboBox( m_listView->viewport() ); + Node *node = (static_cast<TagAttributeTree *>(m_listView))->node(); + QTag *qTag = QuantaCommon::tagFromDTD(node); + if (qTag) + { + if (!attr) + attr = qTag->attribute(title); + if (attr) + { + combo->insertStringList(attr->values); + if (attr->source == "dcop") //fill the list with a result of a DCOP call + { + QString interface = "QuantaIf"; + if (!attr->interface.isEmpty()) + interface = attr->interface; + QString arguments = attr->arguments; + arguments.replace("%tagname%", node->tag->name); + DCOPReply reply = QuantaCommon::callDCOPMethod(interface, attr->method, arguments); + if (reply.isValid()) + { + QStringList list = reply; + combo->insertStringList(list); + } + } + + } + combo->insertItem("", 0); + combo->setEditable(true); + } + combo->hide(); + QObject::connect( combo, SIGNAL( activated(int) ), m_listView, SLOT( editorContentChanged() ) ); + } + +AttributeListItem::~AttributeListItem() +{ + delete combo; +} + +QString AttributeListItem::editorText(int) +{ + return combo->currentText(); +} + +void AttributeListItem::showEditor(int) +{ + placeEditor(combo); + combo->show(); + int index = -1; + Node *node = (static_cast<TagAttributeTree *>(m_listView))->node(); + QTag *qTag = QuantaCommon::tagFromDTD(node); + if (qTag) + { + Attribute *attr = qTag->attribute(text(0)); + if (attr) + { + index = attr->values.findIndex(text(1)); + } + } + if (index != -1) + combo->setCurrentItem(index + 1); + else + { + combo->changeItem(text(1), 0); + combo->setCurrentItem(0); + } + combo->setFocus(); +} + +void AttributeListItem::hideEditor(int) +{ + m_listView->editorContentChanged(); + setText(1, combo->currentText()); + combo->hide(); +} + +//editable color combobox +AttributeColorItem::AttributeColorItem(EditableTree* listView, QListViewItem* parent, const QString &title, const QString& title2) +: AttributeItem(parent, title, title2) +{ + m_listView = listView; + combo = new KColorCombo( m_listView->viewport() ); + combo->setEditable(true); + combo->hide(); + QObject::connect( combo, SIGNAL( activated(int) ), m_listView, SLOT( editorContentChanged() ) ); + } + +AttributeColorItem::~AttributeColorItem() +{ + delete combo; +} + +QString AttributeColorItem::editorText(int) +{ + QString name = combo->color().name(); + if (name == "#000000") + name = ""; + combo->setCurrentText(name); + return name; +} + +void AttributeColorItem::showEditor(int) +{ + placeEditor(combo); + combo->show(); + combo->setColor(text(1)); + combo->setCurrentText(text(1)); + combo->setFocus(); +} + +void AttributeColorItem::hideEditor(int) +{ + m_listView->editorContentChanged(); + QString name = combo->color().name(); + if (name == "#000000") + name = ""; + setText(1, name); + combo->hide(); +} + +//editable style combobox +AttributeStyleItem::AttributeStyleItem(EditableTree* listView, QListViewItem* parent, const QString &title, const QString& title2) +: AttributeItem(parent, title, title2) +{ + m_listView = listView; + m_se = new StyleEditor( m_listView->viewport() ); + m_se->setButtonIcon(4,0); + //combo->setEditable(true); + m_se->hide(); + + QObject::connect( m_se->button(), SIGNAL( clicked() ), m_listView, SLOT( editorContentChanged() ) ); + } + +AttributeStyleItem::~AttributeStyleItem() +{ + delete m_se; +} + +QString AttributeStyleItem::editorText(int) +{ + return m_se->lineEdit()->text(); +} + +void AttributeStyleItem::showEditor(int) +{ + placeEditor(m_se); + m_se->show(); + m_se->lineEdit()->setText(text(1)); + m_se->setFocus(); +} + +void AttributeStyleItem::hideEditor(int) +{ + m_listView->editorContentChanged(); + setText(1, m_se->lineEdit()->text()); + m_se->hide(); +} + diff --git a/quanta/treeviews/tagattributeitems.h b/quanta/treeviews/tagattributeitems.h new file mode 100644 index 00000000..8d603529 --- /dev/null +++ b/quanta/treeviews/tagattributeitems.h @@ -0,0 +1,178 @@ +/*************************************************************************** + tagattributeitems.h + ------------------- + copyright : (C) 2003 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef TAGATTRIBUTEITEM_H +#define TAGATTRIBUTEITEM_H + +#include <qptrlist.h> + +class KColorCombo; +class KURLRequester; +class KListView; +class KListViewItem; +class QListViewItem; +class QLineEdit; +class QComboBox; + +class Attribute; +class EditableTree; +class TagAttributeTree; +class Node; +class StyleEditor; + +class TopLevelItem : public KListViewItem +{ + +public: + TopLevelItem(KListView *parent, const QString& title); + TopLevelItem(KListView *parent, QListViewItem* after, const QString& title); + + virtual ~TopLevelItem(); + +protected: + + void paintCell( QPainter *p, const QColorGroup &cg, + int column, int width, int align ); +}; + +class ParentItem : public KListViewItem +{ + +public: + ParentItem(TagAttributeTree *listView, QListViewItem *parent); + + virtual ~ParentItem(); + Node *node(int index); + void addNode(Node *node); + void showList(bool show); + +protected: + + void paintCell( QPainter *p, const QColorGroup &cg, + int column, int width, int align ); + +private: + QPtrList<Node> m_nodeList; + QComboBox *comboBox; + TagAttributeTree *m_listView; +}; + +class AttributeItem : public KListViewItem +{ +public: + AttributeItem(QListViewItem* parent, const QString& title, const QString& title2); + AttributeItem(EditableTree *listView, QListViewItem* parent, const QString& title, const QString& title2); + AttributeItem(EditableTree *listView, const QString& title, const QString& title2); + AttributeItem(EditableTree *listView, const QString& title, const QString& title2, QListViewItem* after); + + virtual ~AttributeItem(); + virtual void replaceCurrentEditor(); + virtual void showEditor(int column = 1); + virtual void hideEditor(int column = 1); + virtual void placeEditor(QWidget *w, int column = 1); + virtual QString editorText(int column = 1); + + //I'm not sane... lin is the right editor, lin2 is the left one. + QLineEdit *lin, *lin2; + +protected: + + void paintCell( QPainter *p, const QColorGroup &cg, + int column, int width, int align ); + + EditableTree *m_listView; +}; + +class AttributeNameSpaceItem:public AttributeItem +{ +public: + AttributeNameSpaceItem(QListViewItem* parent, const QString& title, const QString& title2): AttributeItem(parent, title, title2){}; + AttributeNameSpaceItem(EditableTree *listView, QListViewItem* parent, const QString& title, const QString& title2):AttributeItem(listView, parent, title, title2){}; + virtual ~AttributeNameSpaceItem(){}; + +}; + +class AttributeBoolItem : public AttributeItem +{ +public: + AttributeBoolItem(TagAttributeTree *listView, QListViewItem* parent, const QString& title, const QString& title2); + + virtual ~AttributeBoolItem(); + virtual void showEditor(int column = 1); + virtual void hideEditor(int column = 1); + virtual QString editorText(int column = 1); + +private: + QComboBox* combo; +}; + +class AttributeUrlItem : public AttributeItem +{ +public: + AttributeUrlItem(TagAttributeTree *listView, QListViewItem* parent, const QString& title, const QString& title2); + + virtual ~AttributeUrlItem(); + virtual void showEditor(int column = 1); + virtual void hideEditor(int column = 1); + virtual QString editorText(int column = 1); + +private: + KURLRequester* urlRequester; +}; + +class AttributeListItem : public AttributeItem +{ +public: + AttributeListItem(EditableTree *listView, QListViewItem* parent, const QString& title, const QString& title2, Attribute *attr = 0L); + + virtual ~AttributeListItem(); + virtual void showEditor(int column = 1); + virtual void hideEditor(int column = 1); + virtual QString editorText(int column = 1); + +private: + QComboBox* combo; +}; + +class AttributeColorItem : public AttributeItem +{ +public: + AttributeColorItem(EditableTree *listView, QListViewItem* parent, const QString& title, const QString& title2); + + virtual ~AttributeColorItem(); + virtual void showEditor(int column = 1); + virtual void hideEditor(int column = 1); + virtual QString editorText(int column = 1); + +private: + KColorCombo* combo; +}; + +class AttributeStyleItem : public AttributeItem +{ +public: + AttributeStyleItem(EditableTree *listView, QListViewItem* parent, const QString& title, const QString& title2); + + virtual ~AttributeStyleItem(); + virtual void showEditor(int column = 1); + virtual void hideEditor(int column = 1); + virtual QString editorText(int column = 1); + +private: + + StyleEditor *m_se; +}; + + +#endif diff --git a/quanta/treeviews/tagattributetree.cpp b/quanta/treeviews/tagattributetree.cpp new file mode 100644 index 00000000..a8e4406b --- /dev/null +++ b/quanta/treeviews/tagattributetree.cpp @@ -0,0 +1,659 @@ +/*************************************************************************** + tagattributetree.cpp + --------------------- + copyright : (C) 2003 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +//qt includes +#include <qfont.h> +#include <qpainter.h> +#include <qtimer.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qtooltip.h> + +//kde includes +#include <kaction.h> +#include <klocale.h> +#include <kpushbutton.h> +#include <kstringhandler.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <khtmlview.h> +#include <ktexteditor/editinterface.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/view.h> +#include <dom/dom_node.h> + +//app includes +#include "tagattributetree.h" +#include "tagattributeitems.h" +#include "qtag.h" +#include "node.h" +#include "parser.h" +#include "quantacommon.h" +#include "document.h" +#include "quantaview.h" +#include "tag.h" +#include "wkafkapart.h" +#include "kafkacommon.h" +#include "undoredo.h" + +#include "viewmanager.h" + +EditableTree::EditableTree(QWidget *parent, const char *name) +: KListView(parent, name) +{ + m_editable = true; +} + +EditableTree::~EditableTree() +{ + +} + +void EditableTree::setCurrentItem( QListViewItem *item) +{ + if ( item && m_editable) + { + QListViewItem *it = currentItem(); + if ( dynamic_cast<AttributeItem*>(it) ) + static_cast<AttributeItem*>(it)->hideEditor(); + + KListView::setCurrentItem(item); + it = currentItem(); + if ( dynamic_cast<AttributeItem*>(it) ) + static_cast<AttributeItem*>(it)->showEditor(); + } +} + +void EditableTree::editorContentChanged() +{ + +} + +void EditableTree::focusInEvent(QFocusEvent *) +{ + /**QListViewItem *it = currentItem(); + if( dynamic_cast<AttributeItem*>(it)) + { + static_cast<AttributeItem *>(it)->showEditor(); + static_cast<AttributeItem *>(it)->lin->setFocus(); + }*/ +} + +void EditableTree::focusOutEvent(QFocusEvent *) +{ + /**QListViewItem *it = currentItem(); + if( dynamic_cast<AttributeItem*>(it)) + { + static_cast<AttributeItem *>(it)->hideEditor(); + }*/ +} + +DualEditableTree::DualEditableTree(QWidget *parent, const char *name) +: EditableTree(parent, name) +{ + curCol = 0; + setFocusPolicy(QWidget::ClickFocus); + this->installEventFilter(this); + connect(this, SIGNAL(clicked(QListViewItem *, const QPoint &, int )), + this, SLOT(itemClicked(QListViewItem *, const QPoint &, int ))); +} + +DualEditableTree::~DualEditableTree() +{ + +} + +bool DualEditableTree::eventFilter(QObject *object, QEvent *event) +{ + AttributeItem *it = dynamic_cast<AttributeItem*>(currentItem()); + AttributeItem *up = 0L, *down = 0L; + if(!it) + return KListView::eventFilter(object, event); + if(currentItem()->itemAbove()) + up = dynamic_cast<AttributeItem*>(currentItem()->itemAbove()); + if(currentItem()->itemBelow()) + down = dynamic_cast<AttributeItem *>(currentItem()->itemBelow()); + + if(event->type() == QEvent::KeyPress && m_editable) + { + QKeyEvent *keyevent = static_cast<QKeyEvent *>(event); + switch(keyevent->key()) + { + case Key_Left: + if(curCol == 1 && it->lin->cursorPosition() == 0 ) + { + it->hideEditor(1); + it->showEditor(0); + it->lin2->setFocus(); + curCol = 0; + } + break; + + case Key_Right: + if(curCol == 0 && (unsigned)it->lin2->cursorPosition() == it->lin2->text().length()) + { + it->hideEditor(0); + it->showEditor(1); + it->lin->setFocus(); + curCol = 1; + } + break; + + case Key_Up: + if(up) + { + it->hideEditor(curCol); + up->showEditor(curCol); + } + break; + + case Key_Down: + if(down) + { + it->hideEditor(curCol); + down->showEditor(curCol); + } + break; + } + } + return KListView::eventFilter(object, event);; +} + +void DualEditableTree::resizeEvent(QResizeEvent *ev) +{ + KListView::resizeEvent(ev); + if(!currentItem()) return; + AttributeItem *item = dynamic_cast<AttributeItem*>(currentItem()); + if(item) + { + item->hideEditor(curCol); + item->showEditor(curCol); + } +} + +void DualEditableTree::setCurrentItem(QListViewItem *item) +{ + if ( item && m_editable) + { + QListViewItem *it = currentItem(); + if ( dynamic_cast<AttributeItem*>(it) ) + { + static_cast<AttributeItem*>(it)->hideEditor(0); + static_cast<AttributeItem*>(it)->hideEditor(1); + } + + KListView::setCurrentItem(item); + it = currentItem(); + if ( dynamic_cast<AttributeItem*>(it) ) + static_cast<AttributeItem*>(it)->showEditor(curCol); + } +} + +void DualEditableTree::editorContentChanged() +{ + emit itemModified(dynamic_cast<AttributeItem*>(currentItem())); +} + +void DualEditableTree::itemClicked(QListViewItem *item, const QPoint &, int column) +{ + if(item) + { + curCol = column; + if(item == currentItem()) + setCurrentItem(item); + } +} + +TagAttributeTree::TagAttributeTree(QWidget *parent, const char *name) +: EditableTree(parent, name) +{ + setRootIsDecorated( true ); + setSorting(-1); + setFrameStyle( Panel | Sunken ); + setLineWidth( 2 ); + setFocusPolicy(QWidget::ClickFocus); + addColumn(i18n("Attribute Name")); + addColumn(i18n("Value")); + setResizeMode(QListView::LastColumn); + m_node = 0L; + m_newNode = 0L; + m_parentItem = 0L; + rebuildEnabled = true; +} + +TagAttributeTree::~TagAttributeTree() +{ +} + +void TagAttributeTree::setCurrentNode(Node *node) +{ + if (m_node == node) + return; + m_node = node; + emit newNodeSelected(node); + if (!rebuildEnabled) + return; + clear(); + m_parentItem = 0L; + //We don't want to be able to edit the text node but it's parent. + if (node && node->tag->type == Tag::Text) + m_node = node = node->parent; + if (!node) + return; +#ifdef HEAVY_DEBUG + kafkaCommon::coutTree(baseNode, 2); + KafkaDocument::ref()->coutLinkTree(baseNode, 2); +#endif + AttributeItem *item = 0L; + TopLevelItem *group = 0L; + QString attrName; + QTag *qTag = QuantaCommon::tagFromDTD(node); + Node *n = node->parent; + while (n) + { + if (n->tag->type == Tag::XmlTag) + { + if (!m_parentItem) + { + group = new TopLevelItem(this, 0L, i18n("Parent tags")); + m_parentItem = new ParentItem(this, group); + } + m_parentItem->addNode(n); + } + n = n->parent; + } + + if (m_parentItem) + m_parentItem->showList(true); + if (group) + group->setOpen(true); +// if (!node->tag->nameSpace.isEmpty()) + + if(node->tag->type == Tag::XmlTag || node->tag->type == Tag::XmlTagEnd) + { + QString nameSpace = node->tag->nameSpace; + if (node->tag->type == Tag::XmlTagEnd) + nameSpace.remove('/'); + group = new TopLevelItem(this, group, i18n("Namespace")); + item = new AttributeNameSpaceItem(this, group, i18n("prefix"), nameSpace); + group->setOpen(true); + } + if (qTag) + { + group = new TopLevelItem(this, group, i18n("Attributes")); + QStringList list; + for (int i = 0; i < qTag->attributeCount(); i++) + { + list += qTag->attributeAt(i)->name; + } + list.sort(); + QStringList::Iterator it = list.end(); + --it; + while (it != list.end()) + { + Attribute *attr = qTag->attribute(*it); + if (attr->type == "check") + { + item = new AttributeBoolItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } else + if (attr->type == "url") + { + item = new AttributeUrlItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } else + if (attr->type == "list") + { + item = new AttributeListItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } else + if (attr->type == "color") + { + item = new AttributeColorItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } else + { + item = new AttributeItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } + item->setRenameEnabled(1, true); + if (it != list.begin()) + --it; + else + break; + } + group->setOpen(true); + for (uint i = 0; i < qTag->commonGroups.count(); i++) + { + group = new TopLevelItem(this, group, i18n(qTag->commonGroups[i].utf8())); + AttributeList *groupAttrs = qTag->parentDTD->commonAttrs->find(qTag->commonGroups[i]); + for (uint j = 0; j < groupAttrs->count(); j++) + { + Attribute *attr = groupAttrs->at(j); + attrName = attr->name; + if (attr->type == "check") + { + item = new AttributeBoolItem(this, group, attrName, node->tag->attributeValue(attrName)); + } else + if (attr->type == "url") + { + item = new AttributeUrlItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } else + if (attr->type == "list") + { + item = new AttributeListItem(this, group, attr->name, node->tag->attributeValue(attr->name), attr); + } else + if (attr->type == "color") + { + item = new AttributeColorItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } else + if (attr->type == "css-style") + { + item = new AttributeStyleItem(this, group, attr->name, node->tag->attributeValue(attr->name)); + } else + { + item = new AttributeItem(this, group, attrName, node->tag->attributeValue(attrName)); + } + item->setRenameEnabled(1, true); + } + group->setOpen(true); + } + + } + connect(this, SIGNAL(collapsed(QListViewItem*)), SLOT(slotCollapsed(QListViewItem*))); + connect(this, SIGNAL(expanded(QListViewItem*)), SLOT(slotExpanded(QListViewItem*))); +} + +void TagAttributeTree::editorContentChanged() +{ + AttributeItem *item = dynamic_cast<AttributeItem*>(currentItem()); + if (m_node && item ) + { + rebuildEnabled = false; + if (dynamic_cast<AttributeNameSpaceItem*>(item)) + { + QString nameSpace = item->editorText(); + m_node->tag->write()->changeTagNamespace(m_node->tag, nameSpace); + } else + { + if(ViewManager::ref()->activeView()->hadLastFocus() == QuantaView::SourceFocus) + { + m_node->tag->write()->changeTagAttribute(m_node->tag, item->text(0), item->editorText()); + } + else + { + //edit the attribute + NodeModifsSet *modifs = new NodeModifsSet(); + kafkaCommon::editNodeAttribute(m_node, item->text(0), item->editorText(), modifs); + ViewManager::ref()->activeDocument()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); + +#ifdef HEAVY_DEBUG + kafkaCommon::coutTree(baseNode, 2); +#endif + } + } + rebuildEnabled = true; + } +} + +/**void TagAttributeTree::setCurrentItem( QListViewItem *item ) +{ + if ( item ) + { + QListViewItem *it = currentItem(); + if ( dynamic_cast<AttributeItem*>(it) ) + static_cast<AttributeItem*>(it)->hideEditor(); + + KListView::setCurrentItem(item); + it = currentItem(); + if ( dynamic_cast<AttributeItem*>(it) ) + static_cast<AttributeItem*>(it)->showEditor(); + } +}*/ + +void TagAttributeTree::slotParentSelected(int index) +{ + if (m_parentItem) + { + m_newNode = m_parentItem->node(index); + QTimer::singleShot(0, this, SLOT(slotDelayedSetCurrentNode())); + } +} + +void TagAttributeTree::slotCollapsed(QListViewItem *item) +{ + if (m_parentItem && item == m_parentItem->parent()) + m_parentItem->showList(false); +} + +void TagAttributeTree::slotExpanded(QListViewItem *item) +{ + if (m_parentItem && item == m_parentItem->parent()) + m_parentItem->showList(true); +} + +void TagAttributeTree::slotDelayedSetCurrentNode() +{ + setCurrentNode(m_newNode); + if (ViewManager::ref()->activeDocument()) + { + if (ViewManager::ref()->activeView()->hadLastFocus() == QuantaView::SourceFocus) + ViewManager::ref()->activeDocument()->view()->setFocus(); + else + KafkaDocument::ref()->getKafkaWidget()->view()->setFocus(); + } +} + +EnhancedTagAttributeTree::EnhancedTagAttributeTree(QWidget *parent, const char *name) +: QWidget(parent, name) +{ + + widgetLayout = new QGridLayout( this, 1, 1, 11, 6, "MainLayout"); + + attrTree = new TagAttributeTree(this, "TagAttributeTree"); + attrTree->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); + widgetLayout->addMultiCellWidget( attrTree, 1, 1, 0, 3 ); + + nodeName = new QLabel(this, i18n( "Node Name" )); + nodeName->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed, 0, 0, nodeName->sizePolicy().hasHeightForWidth() ) ); + + widgetLayout->addWidget( nodeName, 0, 0 ); + deleteTag = new KPushButton(this, i18n( "Delete Tag" )); + deleteTag->setPixmap(SmallIcon("editdelete")); + deleteTag->setMaximumHeight(32); + deleteTag->setMaximumWidth(32); + QToolTip::add(deleteTag, i18n("Delete the current tag only.")); + + deleteAll = new KPushButton(this, i18n( "Delete All" )); + deleteAll->setPixmap(SmallIcon("editdelete")); + deleteAll->setMaximumHeight(32); + deleteAll->setMaximumWidth(32); + QToolTip::add(deleteAll, i18n("Delete the current tag and all its children.")); + + widgetLayout->addWidget( deleteTag, 0, 2 ); + widgetLayout->addWidget( deleteAll, 0, 3 ); + clearWState( WState_Polished ); + + connect(attrTree, SIGNAL(newNodeSelected(Node *)), this, SLOT(NodeSelected(Node *))); + connect(deleteTag, SIGNAL(clicked()), this, SLOT(deleteNode())); + connect(deleteAll, SIGNAL(clicked()), this, SLOT(deleteSubTree())); +} + +EnhancedTagAttributeTree::~EnhancedTagAttributeTree() +{ + +} + +void EnhancedTagAttributeTree::setCurrentNode(Node *node) +{ + curNode = node; + attrTree->setCurrentNode(node); + showCaption(); +} + +void EnhancedTagAttributeTree::NodeSelected(Node *node) +{ + curNode = node; + //We don't want to be able to edit the text node but it's parent. + if (node && node->tag->type == Tag::Text) + curNode = node = node->parent; + showCaption(); + emit newNodeSelected(node); +} + +void EnhancedTagAttributeTree::showCaption() +{ + if(curNode) + { + if(curNode->tag->type == Tag::XmlTag || curNode->tag->type == Tag::XmlTagEnd || + curNode->tag->type == Tag::ScriptTag) + { + QString s = i18n("Current tag: <b>%1</b>").arg(curNode->tag->name); + nodeName->setText(KStringHandler::rPixelSqueeze(s, nodeName->fontMetrics(), attrTree->width()- 50)); + } + else if(curNode->tag->type == Tag::Text) + nodeName->setText(i18n("Current tag: <b>text</b>")); + else if(curNode->tag->type == Tag::Comment) + nodeName->setText(i18n("Current tag: <b>comment</b>")); + else + nodeName->setText(i18n("Current tag:")); + } +} + +void EnhancedTagAttributeTree::deleteSubTree() +{ + QuantaView *view = ViewManager::ref()->activeView(); + if(!curNode || !view->document()) + return; + Node *oldCurNode; + NodeModifsSet *modifs; + int curLine, curCol; + long offset; + DOM::Node domNode; + QValueList<int> loc; + + //Save the cursor position in kafka/quanta + if(view->hadLastFocus() == QuantaView::SourceFocus) + curNode->tag->beginPos(curLine, curCol); + else + { + KafkaDocument::ref()->getKafkaWidget()->getCurrentNode(domNode, offset); + if(!domNode.previousSibling().isNull()) + domNode = domNode.previousSibling(); + else if(!domNode.parentNode().isNull()) + domNode = domNode.parentNode(); + else + domNode = KafkaDocument::ref()->getKafkaWidget()->document(); + if(domNode.nodeType() == DOM::Node::TEXT_NODE) + offset = domNode.nodeValue().length(); + else + offset = 0; + loc = kafkaCommon::getLocation(domNode); + } + + //Remove the Nodes + oldCurNode = curNode; + curNode = 0L; + attrTree->setCurrentNode(curNode); + + modifs = new NodeModifsSet(); + kafkaCommon::extractAndDeleteNode(oldCurNode, modifs); + + view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); + + //set the cursor position in kafka/quanta + if(view->hadLastFocus() == QuantaView::SourceFocus) + view->document()->viewCursorIf->setCursorPositionReal((uint)curLine, (uint)curCol); + else + { + domNode = kafkaCommon::getNodeFromLocation(loc, + KafkaDocument::ref()->getKafkaWidget()->document()); + KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(domNode, offset); + } +} + +void EnhancedTagAttributeTree::deleteNode() +{ + QuantaView *view = ViewManager::ref()->activeView(); + if(!curNode || !view->document()) + return; + + Node *oldCurNode, *oldCurNodeParent, *child; + QTag *oldCurNodeParentQTag; + int curLine, curCol; + long offset; + DOM::Node domNode; + QValueList<int> loc; + NodeModifsSet *modifs; + + //Save the cursor position in kafka/quanta + if(view->hadLastFocus() == QuantaView::SourceFocus) + curNode->tag->beginPos(curLine, curCol); + else + { + KafkaDocument::ref()->getKafkaWidget()->getCurrentNode(domNode, offset); + if(!domNode.previousSibling().isNull()) + domNode = domNode.previousSibling(); + else if(!domNode.parentNode().isNull()) + domNode = domNode.parentNode(); + else + domNode = KafkaDocument::ref()->getKafkaWidget()->document(); + if(domNode.nodeType() == DOM::Node::TEXT_NODE) + offset = domNode.nodeValue().length(); + else + offset = 0; + loc = kafkaCommon::getLocation(domNode); + } + + //remove the Nodes + oldCurNode = curNode; + oldCurNodeParent = curNode->parent; + curNode = 0L; + attrTree->setCurrentNode(curNode); + + modifs = new NodeModifsSet(); + kafkaCommon::extractAndDeleteNode(oldCurNode, modifs, false); + + //Then we see if the new parent - child relationships are valid, and if not, delete the child and restart + if(oldCurNodeParent) + { + oldCurNodeParentQTag = QuantaCommon::tagFromDTD(oldCurNodeParent); + if(oldCurNodeParentQTag) + { + child = oldCurNodeParent->child; + while(child) + { + if(!oldCurNodeParentQTag->isChild(child)) + { + kafkaCommon::extractAndDeleteNode(child, modifs, false); + //too lazy to get the real next node ;-) + child = oldCurNodeParent->child; + } + else + child = child->next; + } + } + } + + view->document()->docUndoRedo->addNewModifsSet(modifs, undoRedo::NodeTreeModif); + + //set the cursor position in kafka/quanta + if(view->hadLastFocus() == QuantaView::SourceFocus) + view->document()->viewCursorIf->setCursorPositionReal((uint)curLine, (uint)curCol); + else + { + domNode = kafkaCommon::getNodeFromLocation(loc, + KafkaDocument::ref()->getKafkaWidget()->document()); + KafkaDocument::ref()->getKafkaWidget()->setCurrentNode(domNode, offset); + } + +} + +#include "tagattributetree.moc" diff --git a/quanta/treeviews/tagattributetree.h b/quanta/treeviews/tagattributetree.h new file mode 100644 index 00000000..bae0f3ff --- /dev/null +++ b/quanta/treeviews/tagattributetree.h @@ -0,0 +1,143 @@ +/*************************************************************************** + tagattributetree.h + ------------------- + copyright : (C) 2003 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef TAGATTRIBUTETREE_H +#define TAGATTRIBUTETREE_H + +//qt includes +#include <qwidget.h> + +//kde includes +#include <klistview.h> + +//app includes + +class KListView; +class QListViewItem; +class ParentItem; +class Node; +class QLabel; +class KPushButton; +class QGridLayout; + +class EditableTree : public KListView { +Q_OBJECT + +public: + EditableTree(QWidget *parent = 0, const char *name = 0); + virtual ~EditableTree(); + + virtual void setCurrentItem( QListViewItem *i); + void setEditable(bool b) {m_editable = b;} + bool isEditable() {return m_editable;} + +public slots: + virtual void editorContentChanged(); + virtual void focusInEvent(QFocusEvent *); + virtual void focusOutEvent(QFocusEvent *); + +protected: + bool m_editable; + +}; + +class DualEditableTree : public EditableTree +{ + Q_OBJECT +public: + DualEditableTree(QWidget *parent = 0, const char *name = 0); + virtual ~DualEditableTree(); + + virtual void setCurrentItem ( QListViewItem *i); + int currentColumn() {return curCol;} + +protected: + virtual bool eventFilter(QObject *object, QEvent *event); + virtual void resizeEvent(QResizeEvent *); + +signals: + void itemModified( QListViewItem *); + +public slots: + virtual void editorContentChanged(); + +private slots: + void itemClicked(QListViewItem *i, const QPoint &point, int col); + +private: + int curCol; +}; + +class TagAttributeTree : public EditableTree { + Q_OBJECT + +public: + TagAttributeTree(QWidget *parent=0, const char *name=0); + virtual ~TagAttributeTree(); + + void setCurrentNode(Node *node); + //virtual void setCurrentItem( QListViewItem *i ); + Node *node() const {return m_node;} + +public slots: + void slotDelayedSetCurrentNode(); + void slotParentSelected(int index); + virtual void editorContentChanged(); + +private slots: + void slotCollapsed(QListViewItem *item); + void slotExpanded(QListViewItem *item); + +signals: + void newNodeSelected(Node *node); + +private: + Node *m_node; + Node *m_newNode; + bool rebuildEnabled; + ParentItem *m_parentItem; +}; + +//An enhanced TagAttributeTree with the tag name and buttons to delete the tag. +class EnhancedTagAttributeTree : public QWidget +{ +Q_OBJECT +public: + EnhancedTagAttributeTree(QWidget *parent = 0, const char *name = 0); + virtual ~EnhancedTagAttributeTree(); + + void setCurrentNode(Node *node); + Node *node() const {return attrTree->node();} + +signals: + void newNodeSelected(Node *node); + +private slots: + void NodeSelected(Node *node); + void deleteNode(); + void deleteSubTree(); + +private: + void showCaption(); + + QLabel *nodeName; + KPushButton* deleteAll; + KPushButton* deleteTag; + TagAttributeTree *attrTree; + QGridLayout *widgetLayout; + Node *curNode; +}; + +#endif + diff --git a/quanta/treeviews/templatedirform.ui b/quanta/treeviews/templatedirform.ui new file mode 100644 index 00000000..4ab6d6c1 --- /dev/null +++ b/quanta/treeviews/templatedirform.ui @@ -0,0 +1,170 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>TemplateDirForm</class> +<comment>/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; version 2 of the License. * + * * + ***************************************************************************/ + +</comment> +<author>(C) 2002 by Andras Mantia <amantia@kde.org></author> +<widget class="QDialog"> + <property name="name"> + <cstring>TemplateDirForm</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>309</width> + <height>157</height> + </rect> + </property> + <property name="caption"> + <string>Create Template Folder</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>TextLabel2</cstring> + </property> + <property name="text"> + <string>Type:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>TextLabel1</cstring> + </property> + <property name="text"> + <string>Name:</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <property name="name"> + <cstring>typesCombo</cstring> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>dirName</cstring> + </property> + </widget> + <widget class="QCheckBox" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>parentAttr</cstring> + </property> + <property name="text"> + <string>&Inherit parent attribute</string> + </property> + </widget> + <widget class="QLayoutWidget" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>38</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonOk</cstring> + </property> + <property name="text"> + <string>&OK</string> + </property> + <property name="default"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>25</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonCancel</cstring> + </property> + <property name="text"> + <string>&Cancel</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>38</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </grid> +</widget> +<connections> + <connection> + <sender>parentAttr</sender> + <signal>toggled(bool)</signal> + <receiver>typesCombo</receiver> + <slot>setDisabled(bool)</slot> + </connection> +</connections> +<tabstops> + <tabstop>dirName</tabstop> + <tabstop>typesCombo</tabstop> + <tabstop>parentAttr</tabstop> + <tabstop>buttonOk</tabstop> + <tabstop>buttonCancel</tabstop> +</tabstops> +<slots> + <slot>okBtn_clicked()</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcombobox.h</includehint> +</includehints> +</UI> diff --git a/quanta/treeviews/templatestreeview.cpp b/quanta/treeviews/templatestreeview.cpp new file mode 100644 index 00000000..e87e2428 --- /dev/null +++ b/quanta/treeviews/templatestreeview.cpp @@ -0,0 +1,1079 @@ +/*************************************************************************** + templatestreeview.cpp - description + ------------------- + begin : Thu Dec 20 2001 + copyright : (C) 2001-2004 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#include <unistd.h> +#include <grp.h> +#include <pwd.h> +#include <sys/types.h> + +// QT includes +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qclipboard.h> +#include <qdir.h> +#include <qpixmap.h> +#include <qheader.h> +#include <qpoint.h> +#include <qlayout.h> +#include <qtextedit.h> +#include <qregexp.h> +#include <qlabel.h> +#include <qmap.h> +#include <qwidgetstack.h> + +// KDE includes +#include <kapplication.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kstandarddirs.h> +#include <kmainwindow.h> +#include <kmimetype.h> +#include <kmessagebox.h> +#include <kcombobox.h> +#include <kpopupmenu.h> +#include <kpropertiesdialog.h> +#include <kurlrequester.h> +#include <kurlrequesterdlg.h> +#include <ktempdir.h> +#include <ktempfile.h> +#include <kio/netaccess.h> +#include <kurldrag.h> +#include <ktar.h> +#include <kdebug.h> +#include <kfile.h> + + +#include "templatestreeview.h" +#include "copyto.h" +#include "newtemplatedirdlg.h" +#include "qextfileinfo.h" +#include "quantanetaccess.h" +#include "quantapropertiespage.h" +#include "resource.h" +#include "tagaction.h" +#include "tagmaildlg.h" + +#define EXCLUDE ".*\\.tmpl$" +#define TMPL ".tmpl" +#define NONE "None" + + +const QString textMenu = I18N_NOOP("Insert as &Text"); +const QString binaryMenu = I18N_NOOP("Insert &Link to File"); +const QString docMenu = I18N_NOOP("&New Document Based on This"); +const QString siteMenu = I18N_NOOP("&Extract Site Template To..."); +QMap<QString, QString> typeToi18n; +QMap<QString, QString> i18nToType; + + +//TemplatesTreeBranch implementation +TemplatesTreeBranch::TemplatesTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden, + KFileTreeViewItem *branchRoot) + : BaseTreeBranch(parent, url, name, pix, showHidden, branchRoot) +{ +} + +KFileTreeViewItem* TemplatesTreeBranch::createTreeViewItem(KFileTreeViewItem *parent, + KFileItem *fileItem ) +{ + BaseTreeViewItem *tvi = 0; + if( parent && fileItem ) + { + KURL url = fileItem->url(); + tvi = new BaseTreeViewItem( parent, fileItem, this ); + if (tvi && fileItem->isDir()) + { + if (url.isLocalFile()) + { + QDir dir (url.path(), "", QDir::All); + tvi->setExpandable(dir.count() != 2); // . and .. are always there + } else { + tvi->setExpandable(true); // we assume there is something + } + } else + { + url = static_cast<BaseTreeViewItem*>(parent)->url(); + } + QFileInfo dotFileInfo(url.path() + "/.dirinfo"); + while ((!dotFileInfo.exists()) && (dotFileInfo.dirPath() != "/")) + { + dotFileInfo.setFile(QFileInfo(dotFileInfo.dirPath()).dirPath()+"/.dirinfo"); + } + if (dotFileInfo.exists()) + { + KConfig *config = new KConfig(dotFileInfo.filePath()); + QString s = config->readEntry("Type"); + tvi->setText(1, typeToi18n[s]); + delete config; + } + + } + else + kdDebug(24000) << "TemplatesTreeBranch::createTreeViewItem: Have no parent" << endl; + return tvi; +} + + + +TemplatesTreeView::TemplatesTreeView(KMainWindow *parent, const char *name ) + : BaseTreeView(parent,name), m_projectDir(0), m_mainWindow(parent) +{ + typeToi18n["text/all"] = i18n("Text Snippet"); + typeToi18n["file/all"] = i18n("Binary File"); + typeToi18n["template/all"] = i18n("Document Template"); + typeToi18n["site/all"] = i18n("Site Template"); + i18nToType[i18n("Text Snippet")] = "text/all"; + i18nToType[i18n("Binary File")] = "file/all"; + i18nToType[i18n("Document Template")] = "template/all"; + i18nToType[i18n("Site Template")] = "site/all"; + + m_fileMenu = new KPopupMenu(this); + + m_openId = m_fileMenu->insertItem(i18n("Open"), this ,SLOT(slotInsert())); + m_fileMenu->insertItem(SmallIcon("fileopen"), i18n("&Open"), this ,SLOT(slotOpen())); + m_fileMenu->insertItem(SmallIcon("mail_send"), i18n("Send in E&mail..."), this, SLOT(slotSendInMail())); + m_fileMenu->insertItem(SmallIcon("network"), i18n("&Upload Template..."), this, SLOT(slotUploadTemplate())); + m_insertFileInProject = m_fileMenu->insertItem(i18n("&Insert in Project..."), this, SLOT(slotInsertInProject())); + m_menuClose = m_fileMenu->insertItem(SmallIcon("fileclose"), i18n("Clos&e"), this, SLOT(slotClose())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(SmallIcon("editcopy"), i18n("&Copy"), this, SLOT(slotCopy())); + m_fileMenu->insertItem(SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_fileMenu->insertSeparator(); + m_fileMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + + m_folderMenu = new KPopupMenu(this); + + m_folderMenu->insertItem(SmallIcon("folder_new"), i18n("&New Folder..."), this, SLOT(slotNewDir())); + m_folderMenu->insertItem(SmallIcon("mail_send"), i18n("Send in E&mail..."), this, SLOT(slotSendInMail())); + m_folderMenu->insertItem(SmallIcon("network"), i18n("&Upload Template..."), this, SLOT(slotUploadTemplate())); + m_downloadMenuId = m_folderMenu->insertItem(SmallIcon("network"), i18n("&Download Template..."), this, SIGNAL(downloadTemplate())); + m_insertFolderInProject = m_folderMenu->insertItem(i18n("&Insert in Project..."), this, SLOT(slotInsertDirInProject())); + m_folderMenu->insertSeparator(); + m_folderMenu->insertItem(SmallIcon("editcopy"), i18n("&Copy"), this, SLOT(slotCopy())); + m_menuPasteFolder = m_folderMenu->insertItem(SmallIcon("editpaste"), i18n("&Paste"), this, SLOT(slotPaste())); + m_deleteMenuId = m_folderMenu->insertItem(SmallIcon("editdelete"), i18n("&Delete"), this, SLOT(slotDelete())); + m_folderMenu->insertSeparator(); + m_folderMenu->insertItem(SmallIcon("info"), i18n("&Properties"), this, SLOT(slotProperties())); + m_reloadMenuId = m_folderMenu->insertItem(SmallIcon("revert"), i18n("&Reload"), this, SLOT(slotReload())); + + m_emptyAreaMenu = new KPopupMenu(this); + m_emptyAreaMenu->insertItem(SmallIcon("network"), i18n("&Download Template..."), this, SIGNAL(downloadTemplate())); + + addColumn(i18n("Templates"), -1); + addColumn(i18n("Group"), -1); + + globalURL.setPath(qConfig.globalDataDir + resourceDir + "templates/"); + newBranch(globalURL); + + localURL.setPath(locateLocal("data", resourceDir + "templates/")); + newBranch(localURL); + + connect(this, SIGNAL(contextMenu(KListView*, QListViewItem*, const QPoint&)), + this, SLOT(slotMenu(KListView*, QListViewItem*, const QPoint&))); + + connect(this, SIGNAL(open(QListViewItem *)), + this, SLOT(slotSelectFile(QListViewItem *))); + + setAcceptDrops(true); + setSelectionMode(QListView::Single); + setDragEnabled(true); + setSaveOpenFolder(true); + restoreLayout( kapp->config(), className() ); + // the restored size of the first column might be too large for the current content + // we set it to 10 and the listview will adjust it to the size of the largest entry + setColumnWidth(0, 10); +} + +TemplatesTreeView::~TemplatesTreeView() +{ +} + + +KFileTreeBranch* TemplatesTreeView::newBranch(const KURL& url) +{ + BaseTreeBranch *newBrnch; + if (url == globalURL) + { + newBrnch = new TemplatesTreeBranch(this, url, i18n("Global Templates"), SmallIcon("ttab")); + } else + { + if (url == localURL) + newBrnch = new TemplatesTreeBranch(this, url, i18n("Local Templates"), SmallIcon("ttab")); + else + { + newBrnch = new TemplatesTreeBranch(this, url, i18n("Project Templates"), SmallIcon("ptab")); + m_projectDir = newBrnch; + } + } + newBrnch->excludeFilterRx.setPattern(EXCLUDE); + addBranch(newBrnch); + if (url.isLocalFile()) + { + QDir dir (url.path(), "", QDir::All); + newBrnch->root()->setExpandable(dir.count() != 2); // . and .. are always there + } else { + newBrnch->root()->setExpandable(true); // we assume there is something + } + + return newBrnch; +} + + +/** No descriptions */ +void TemplatesTreeView::slotInsertInDocument() +{ + + KURL url = filterTemplate(); + if (QuantaCommon::checkMimeGroup(url, "text")) + { + emit insertFile(url); + } else + { + if (QuantaCommon::denyBinaryInsert(this) == KMessageBox::Yes) + { + emit insertFile(url); + } + } + +} + +void TemplatesTreeView::slotMenu(KListView*, QListViewItem *item, const QPoint &point) +{ + if (!item) + { + m_emptyAreaMenu->popup(point); + return; + } + setSelected(item, true); + bool hasProject = m_projectName; + m_folderMenu->setItemVisible(m_insertFolderInProject, hasProject); + m_fileMenu->setItemVisible(m_insertFileInProject, hasProject); + + KFileTreeViewItem *curItem = currentKFileTreeViewItem(); + if ( curItem->isDir() ) + { + m_folderMenu->setItemVisible(m_menuPasteFolder, isPathInClipboard()); + if ( curItem == curItem->branch()->root()) + { + m_folderMenu ->setItemVisible(m_deleteMenuId, false); + m_folderMenu ->setItemVisible(m_reloadMenuId, true); + m_folderMenu ->setItemVisible(m_downloadMenuId, true); + } else + { + m_folderMenu ->setItemVisible(m_deleteMenuId, true); + m_folderMenu ->setItemVisible(m_reloadMenuId, false); + m_folderMenu ->setItemVisible(m_downloadMenuId, false); + } + m_folderMenu ->popup(point); + } else + { + m_dirInfo = readDirInfo(); + + QString menuText = ""; + + if (m_dirInfo.mimeType.upper().contains("TEXT")) + menuText = i18n(textMenu.utf8()); + else if (m_dirInfo.mimeType.upper().contains("FILE")) + menuText = i18n(binaryMenu.utf8()); + else if (m_dirInfo.mimeType.upper().contains("TEMPLATE")) + menuText = i18n(docMenu.utf8()); + else if (m_dirInfo.mimeType.upper().contains("SITE")) + menuText = i18n(siteMenu.utf8()); + + if (menuText.isEmpty()) + { + m_fileMenu->setItemVisible(m_openId, false); + } else + { + m_fileMenu->setItemVisible(m_openId, true); + m_fileMenu->changeItem(m_openId, menuText); + } + m_fileMenu->setItemVisible(m_menuClose, isFileOpen(currentURL())); + + m_fileMenu->popup( point); + } +} +/** No descriptions */ +void TemplatesTreeView::slotNewDocument() +{ + KURL url = filterTemplate(); + if (QuantaCommon::checkMimeGroup(url, "text") || QuantaCommon::denyBinaryInsert(this) == KMessageBox::Yes) + { + QListViewItem *item = currentItem(); + if (item ) + { + if ( currentKFileTreeViewItem() != currentKFileTreeViewItem()->branch()->root()) + { + emit openFile(KURL()); + emit insertFile(url); + } + } + } +} + +/** Insert the template as text, image, new document. */ +void TemplatesTreeView::slotInsert() +{ + QString menuText = m_fileMenu->text(m_openId); + + if (menuText == i18n(textMenu.utf8())) + slotInsertInDocument(); + else if (menuText == i18n(binaryMenu.utf8())) + slotInsertTag(); + else if (menuText == i18n(docMenu.utf8())) + slotNewDocument(); + if (menuText == i18n(siteMenu.utf8())) + slotExtractSiteTemplate(); +} + +void TemplatesTreeView::slotSelectFile(QListViewItem *item) +{ + if ( !item ) return; + + KFileTreeViewItem *kftvItem = currentKFileTreeViewItem(); + if ( !kftvItem ) return; + + if ( !kftvItem->isDir() ) + { + m_dirInfo = readDirInfo(); +/* if (m_dirInfo.mimeType.upper().contains("SITE")) + { + slotExtractSiteTemplate(); + return; + }*/ + if (expandArchiv(kftvItem)) return; + if (m_dirInfo.mimeType.upper().contains("TEXT")) + slotInsertInDocument(); + else if (m_dirInfo.mimeType.upper().contains("FILE")) + slotInsertTag(); + else if (m_dirInfo.mimeType.upper().contains("TEMPLATE")) + slotNewDocument(); + } +} + +void TemplatesTreeView::slotOpen() +{ + BaseTreeView::slotSelectFile(currentItem()); +} + +/** No descriptions */ +void TemplatesTreeView::slotNewDir() +{ + NewTemplateDirDlg *createDirDlg = new NewTemplateDirDlg(this,i18n("Create New Template Folder")); + createDirDlg->typesCombo->insertItem(typeToi18n["text/all"]); + createDirDlg->typesCombo->insertItem(typeToi18n["file/all"]); + createDirDlg->typesCombo->insertItem(typeToi18n["template/all"]); + createDirDlg->typesCombo->insertItem(typeToi18n["site/all"]); + + m_dirInfo = readDirInfo(); + + if (m_dirInfo.mimeType.isEmpty()) + { + createDirDlg->parentAttr->setText(i18n("&Inherit parent attribute (nothing)")); + } else + { + createDirDlg->parentAttr->setText(i18n("&Inherit parent attribute (%1)").arg(typeToi18n[m_dirInfo.mimeType])); + } + if (createDirDlg->exec()) + { + QDir dir; + + QString startDir = ""; + if ( !currentKFileTreeViewItem()->isDir() ) + { + startDir = currentURL().path(); + } else + { + startDir = currentURL().path() + "/dummy_file"; + } + startDir = QFileInfo(startDir).dirPath(); + if (!dir.mkdir(startDir+"/"+createDirDlg->dirName->text())) + { + KMessageBox::error(this,i18n("Error while creating the new folder.\n \ + Maybe you do not have permission to write in the %1 folder.").arg(startDir)); + return; + } + if (! createDirDlg->parentAttr->isChecked()) + { + m_dirInfo.mimeType = i18nToType[createDirDlg->typesCombo->currentText()]; + m_dirInfo.preText = ""; + m_dirInfo.postText = ""; + writeDirInfo(startDir+"/"+createDirDlg->dirName->text()+"/.dirinfo"); + } + } +} +/** No descriptions */ + +QDragObject * TemplatesTreeView::dragObject () +{ + // don't drag folders + if ( ! currentKFileTreeViewItem() || currentKFileTreeViewItem()->isDir() ) return 0; + + m_dirInfo = readDirInfo(); + if(!m_dirInfo.mimeType.isEmpty()) // only drag when the template type is specified + { + KURLDrag *drag = new KURLDrag(KURL::List(currentURL()), this); + return drag; + } + return 0; +} + +/** No descriptions */ +void TemplatesTreeView::contentsDropEvent(QDropEvent *e) +{ + if (KURLDrag::canDecode(e)) + { + // handles url drops + BaseTreeView::contentsDropEvent(e); + return; + } + if (QTextDrag::canDecode(e)) + { + QListViewItem *item = itemAt(contentsToViewport(e->pos())); + if (item) + { + KURL dest; + if ( currentKFileTreeViewItem()->isDir() ) + dest = currentURL(); + else + dest = currentURL().directory(false); + dest.adjustPath(+1); + QString content; + QTextDrag::decode(e, content); + KURL url =KURLRequesterDlg::getURL( dest.path() + "template.txt", + this, i18n("Save selection as template file:")); + if ( !url.isEmpty() ) + { + //now save the file + KTempFile* tempFile = new KTempFile(tmpDir); + tempFile->setAutoDelete(true); + tempFile->textStream()->setEncoding(QTextStream::UnicodeUTF8); + *(tempFile->textStream()) << content; + tempFile->close(); + bool proceed = true; + if (QExtFileInfo::exists(url, false, this)) + { + proceed = KMessageBox::warningContinueCancel(this, i18n("<qt>The file <b>%1</b> already exists.<br>Do you want to overwrite it?</qt>").arg(url.prettyURL(0, KURL::StripFileProtocol)),i18n("Overwrite"), i18n("Overwrite")) == KMessageBox::Continue; + } + if (proceed) + { + if (!QuantaNetAccess::upload(tempFile->name(), url, m_parent, false)) + { + KMessageBox::error(this,i18n("<qt>Could not write to file <b>%1</b>.<br>Check if you have rights to write there or that your connection is working.</qt>").arg(url.prettyURL(0, KURL::StripFileProtocol))); + } + } + delete tempFile; + } + } + } + // must be done to reset timer etc. + BaseTreeView::contentsDropEvent(e); +} + +/** Reads a .dirinfo file from the selected item's path */ +DirInfo TemplatesTreeView::readDirInfo(const QString& dir) +{ + DirInfo dirInfo; + QString startDir = dir; + + if (startDir.isEmpty()) + { + if (!currentKFileTreeViewItem()->isDir()) + { + startDir = currentURL().path(); + } else + { + startDir = currentURL().path() + "/dummy_file"; + } + } + + QFileInfo dotFileInfo(QFileInfo(startDir).dirPath()+"/.dirinfo"); + + while ((!dotFileInfo.exists()) && (dotFileInfo.dirPath() != "/")) + { + dotFileInfo.setFile(QFileInfo(dotFileInfo.dirPath()).dirPath()+"/.dirinfo"); + } + + KConfig *config = new KConfig(dotFileInfo.filePath()); + dirInfo.mimeType = config->readEntry("Type"); + dirInfo.preText = config->readEntry("PreText"); + dirInfo.postText = config->readEntry("PostText"); + dirInfo.usePrePostText = config->readBoolEntry("UsePrePostText", false); + + delete config; + return dirInfo; +} + +/** Writes a .dirinfo file from the selected item's path */ +bool TemplatesTreeView::writeDirInfo(const QString& m_dirInfoFile) +{ + QString startDir = ""; + + if (m_dirInfoFile.isEmpty()) + { + if ( !currentKFileTreeViewItem()->isDir() ) + { + startDir = currentURL().path(); + } else + { + startDir = currentURL().path() + "/dummy_file"; + } + } else + { + startDir = m_dirInfoFile; + } + + QFileInfo dotFileInfo(QFileInfo(startDir).dirPath()+"/.dirinfo"); + + bool success = false; + KConfig *config = new KConfig(dotFileInfo.filePath()); + if (!config->isReadOnly()) + { + config->writeEntry("Type", m_dirInfo.mimeType); + config->writeEntry("PreText", m_dirInfo.preText); + config->writeEntry("PostText", m_dirInfo.postText); + config->writeEntry("UsePrePostText", m_dirInfo.usePrePostText); + config->sync(); + success = true; + } + delete config; + return success; +} + +void TemplatesTreeView::slotProperties() +{ + if ( !currentItem() ) return; + KURL url = currentURL(); + + KPropertiesDialog *propDlg = new KPropertiesDialog( url, this, 0L, false, false); //autodeletes itself + +//Always add the Quanta directory page + QFrame *quantaDirPage = propDlg->addPage(i18n("Quanta Template")); + QVBoxLayout *topLayout = new QVBoxLayout( quantaDirPage); + m_quantaProperties = new QuantaPropertiesPage( quantaDirPage, i18n("Quanta") ); + + m_quantaProperties->typesCombo->insertItem(typeToi18n["text/all"]); + m_quantaProperties->typesCombo->insertItem(typeToi18n["file/all"]); + m_quantaProperties->typesCombo->insertItem(typeToi18n["template/all"]); + m_quantaProperties->typesCombo->insertItem(typeToi18n["site/all"]); + + m_dirInfo = readDirInfo(); + + m_quantaProperties->typesCombo->setCurrentItem(typeToi18n[m_dirInfo.mimeType]); + + KIO::UDSEntry entry; + KIO::NetAccess::stat(url, entry, this); + KFileItem fItem(entry, url); + QString permissions = fItem.permissionsString(); + QString userName; + struct passwd *user = getpwuid(getuid()); + if (user) + userName = QString::fromLocal8Bit(user->pw_name); + QString groupName; + gid_t gid = getgid(); + struct group *ge = getgrgid(gid); + if (ge) + { + groupName = QString::fromLocal8Bit(ge->gr_name); + if (groupName.isEmpty()) + groupName.sprintf("%d", ge->gr_gid); + } else + groupName.sprintf("%d", gid); + bool writable = false; + if (permissions[8] == 'w' || (permissions[2] == 'w' && userName == fItem.user()) || (permissions[5] == 'w' && groupName == fItem.group())) + writable = true; + + QString startDir = ""; + if (!currentKFileTreeViewItem()->isDir()) + { + startDir = url.path(); + m_quantaProperties->typeStack->raiseWidget(1); + } else + { + startDir = url.path() + "/dummy_file"; + m_quantaProperties->typeStack->raiseWidget(0); + } + m_quantaProperties->setEnabled(writable); + QFileInfo dotFileInfo(QFileInfo(startDir).dirPath()+"/.dirinfo"); + m_parentDirInfo = readDirInfo(dotFileInfo.dirPath()); + if (!dotFileInfo.exists() || m_dirInfo.mimeType == m_parentDirInfo.mimeType) + { + m_quantaProperties->parentAttr->setChecked(true); + } + if (m_parentDirInfo.mimeType.isEmpty()) + { + m_quantaProperties->parentAttr->setText(i18n("&Inherit parent attribute (nothing)")); + } else + { + m_quantaProperties->parentAttr->setText(i18n("&Inherit parent attribute (%1)").arg(typeToi18n[m_parentDirInfo.mimeType])); + } + m_quantaProperties->preTextEdit->setText(m_dirInfo.preText); + m_quantaProperties->postTextEdit->setText(m_dirInfo.postText); + if (m_dirInfo.usePrePostText) + { + m_quantaProperties->usePrePostText->setChecked(true); + } + + topLayout->addWidget( m_quantaProperties ); + connect( propDlg, SIGNAL( applied() ), this , SLOT( slotPropertiesApplied()) ); + + QString name = url.path() + TMPL; + KConfig config(name); + config.setGroup("Filtering"); + name = config.readEntry("Action", NONE); + if ( name == NONE ) + name = i18n(NONE); + uint pos = 0; + uint j = 1; + m_quantaProperties->actionCombo->insertItem(i18n(NONE)); + QString tmpStr; + KActionCollection *ac = m_mainWindow->actionCollection(); + uint acCount = ac->count(); + for (uint i = 0; i < acCount; i++) + { + TagAction *action = dynamic_cast<TagAction*>(ac->action(i)); + if (action) + { + QDomElement el = action->data(); + QString type = el.attribute("type", "tag"); + if (type == "script") + { + tmpStr = action->text().replace(QRegExp("\\&(?!\\&)"),""); + m_quantaProperties->actionCombo->insertItem(tmpStr); + if (tmpStr == name) + pos = j; + j++; + } + } + } + m_quantaProperties->actionCombo->setCurrentItem(pos); + +//If the item is a file, add the Quanta file info page + addFileInfoPage(propDlg); + if (propDlg->exec() == QDialog::Accepted) + { +//TODO: move to slotPropertiesApplied + if (url != propDlg->kurl()) + { + itemRenamed(url, propDlg->kurl()); + } + } +} + + +/** No descriptions */ +void TemplatesTreeView::slotPropertiesApplied() +{ + DirInfo m_localDirInfo; + QString typeString = ""; + + if (!m_quantaProperties->parentAttr->isChecked()) + { + m_localDirInfo.mimeType = m_quantaProperties->typesCombo->currentText(); + typeString = m_localDirInfo.mimeType; + m_localDirInfo.mimeType = i18nToType[m_localDirInfo.mimeType]; + + } else + { + if (m_dirInfo.mimeType != m_parentDirInfo.mimeType) + typeString = typeToi18n[m_parentDirInfo.mimeType]; + m_localDirInfo.mimeType = m_parentDirInfo.mimeType; + } + + m_localDirInfo.usePrePostText = m_quantaProperties->usePrePostText->isChecked(); + m_localDirInfo.preText = m_quantaProperties->preTextEdit->text(); + m_localDirInfo.postText = m_quantaProperties->postTextEdit->text(); + + if ( (m_dirInfo.mimeType != m_localDirInfo.mimeType) || + (m_dirInfo.preText != m_localDirInfo.preText) || + (m_dirInfo.postText != m_localDirInfo.postText)) + { + m_dirInfo.mimeType = m_localDirInfo.mimeType; + m_dirInfo.preText = m_localDirInfo.preText; + m_dirInfo.postText = m_localDirInfo.postText; + m_dirInfo.usePrePostText = m_localDirInfo.usePrePostText; + bool result = writeDirInfo(); + KFileTreeViewItem *item = currentKFileTreeViewItem(); + if (item && !item->isDir()) + item = static_cast<KFileTreeViewItem *>(item->parent()); + if (result && item && !typeString.isEmpty()) + { + if (item->parent() && item->isDir()) + item->setText(1, typeString); + updateTypeDescription(item, typeString); + } + } + + writeTemplateInfo(); +} + +void TemplatesTreeView::updateTypeDescription(KFileTreeViewItem *item, const QString &typeString) +{ + if (item->parent() && item->isDir()) + item->setText(1, typeString); + KFileTreeViewItem *curItem = static_cast<KFileTreeViewItem *>(item->firstChild()); + while (curItem && curItem != static_cast<KFileTreeViewItem *>(item->nextSibling())) + { + if (!curItem->isDir()) + { + curItem->setText(1, typeString); + } else + { + QFileInfo dotFileInfo(curItem->url().path() + "/.dirinfo"); + if (!dotFileInfo.exists()) + updateTypeDescription(curItem, typeString); + } + curItem = static_cast<KFileTreeViewItem *>(curItem->nextSibling()); + } +} + +/** No descriptions */ +void TemplatesTreeView::slotInsertTag() +{ + if (currentItem()) + { + m_dirInfo = readDirInfo(); + KURL url = currentURL(); + emit insertTag( url, m_dirInfo); + } +} +/* + Attention, this is called whenever a drop on a kate window happens! +*/ +void TemplatesTreeView::slotDragInsert(QDropEvent *e) +{ + if (KURLDrag::canDecode(e)) + { + KURL::List fileList; + KURLDrag::decode(e, fileList); + + if(fileList.empty()) + return; + + KURL url = fileList.front(); + + QString localFileName; + if (url.isLocalFile()) + { + localFileName = url.path(); + m_dirInfo = readDirInfo(localFileName); + } + QString mimeType = KMimeType::findByURL(url)->name(); + + /* First, see if the type of the file is specified in the .dirinfo file */ + if(m_dirInfo.mimeType.isEmpty()) + { + // no .dirinfo file present, so we insert it as tag + emit insertTag(url, m_dirInfo); + } else + { + if(m_dirInfo.mimeType == "text/all") // default to inserting in document + { + if(!mimeType.contains("text", false) && QuantaCommon::denyBinaryInsert(this) != KMessageBox::Yes) + { + return; + } + emit insertFile(KURL::fromPathOrURL( localFileName )); + } + + if(m_dirInfo.mimeType == "file/all") + { + // whatever this is, insert it with a tag (image or link or prefix/postfix) + emit insertTag(KURL::fromPathOrURL( localFileName ), m_dirInfo); + } + else + if(m_dirInfo.mimeType == "template/all") + { + if(!mimeType.contains("text", false) && QuantaCommon::denyBinaryInsert(this) != KMessageBox::Yes) + { + return; + } + emit openFile(KURL()); + emit insertFile(KURL::fromPathOrURL( localFileName )); + } + } + } else + if (QTextDrag::canDecode(e)) + { + QString s; + QTextDrag::decode(e, s); + KMessageBox::information(this,s, "Decode"); + } +} + +void TemplatesTreeView::slotNewProjectLoaded(const QString &projectName, const KURL &baseURL, const KURL &templateURL) +{ + BaseTreeView::slotNewProjectLoaded(projectName, baseURL, templateURL); // set m_projectName and m_projectBaseURL + if (m_projectDir) + removeBranch(m_projectDir); + if (!templateURL.isEmpty()) + { + newBranch(templateURL); + } +} + + +/*! + \fn TemplatesTreeView::writeTemplateInfo() + */ +void TemplatesTreeView::writeTemplateInfo() +{ + QString fileName = currentURL().path() + TMPL; + KConfig config(fileName); + config.setGroup("Filtering"); + if ( m_quantaProperties->actionCombo->currentText() == i18n(NONE) ) + config.writeEntry("Action", NONE); + else + config.writeEntry("Action", m_quantaProperties->actionCombo->currentText()); + config.sync(); +} + +void TemplatesTreeView::slotPaste() +{ + if (currentItem()) + { + QClipboard *cb = QApplication::clipboard(); + KURL::List list( QStringList::split( QChar('\n'), cb->text() ) ); + + KURL url; + uint j = list.count(); + for (uint i = 0; i < j; i++) + { + url = list[i]; + url.setFileName(url.fileName() + TMPL); + if (url.isLocalFile() && QFileInfo(url.path()).exists()) + list += url; + } + url = currentURL(); + if ( ! currentKFileTreeViewItem()->isDir() ) + url.setFileName(""); // don't paste on files but in dirs + KIO::Job *job = KIO::copy( list, url); + connect( job, SIGNAL( result( KIO::Job *) ), this , SLOT( slotJobFinished( KIO::Job *) ) ); + } +} + +void TemplatesTreeView::slotDelete() +{ + if (currentItem()) + { + KURL url = currentURL(); + QString msg; + if ( currentKFileTreeViewItem()->isDir() ) + msg = i18n("Do you really want to delete folder \n%1 ?\n").arg(url.path()); + else + msg = i18n("Do you really want to delete file \n%1 ?\n").arg(url.path()); + + if ( KMessageBox::warningContinueCancel(this, msg, QString::null, KStdGuiItem::del()) == KMessageBox::Continue ) + { + KIO::Job *job = KIO::del(url); + connect( job, SIGNAL( result( KIO::Job *) ), this , SLOT( slotJobFinished( KIO::Job *) ) ); + url.setFileName(url.fileName()+ TMPL); + if ( QFileInfo(url.path()).exists() ) { + KIO::Job *job2 = KIO::del(url); + connect( job2, SIGNAL( result( KIO::Job *) ), this , SLOT( slotJobFinished( KIO::Job *) ) ); + }; + } + } +} + +/** Filters the template through and action, and returns the modified/filtered +template file */ +KURL TemplatesTreeView::filterTemplate() +{ + KURL url = currentURL(); + QString name = url.path() + TMPL; + KConfig config(name); + config.setGroup("Filtering"); + name = config.readEntry("Action", NONE); + TagAction *filterAction = 0L; + KActionCollection *ac = m_mainWindow->actionCollection(); + uint acCount = ac->count(); + QString tmpStr; + for (uint i = 0; i < acCount; i++) + { + TagAction *action = dynamic_cast<TagAction*>(ac->action(i)); + if (action) + { + QDomElement el = action->data(); + QString type = el.attribute("type", "tag"); + tmpStr = action->text(); + tmpStr.replace(QRegExp("\\&(?!\\&)"),""); + if (type == "script" && tmpStr == name) + { + filterAction = action; + } + } + } + if (filterAction) + { + KTempFile* tempFile = new KTempFile(tmpDir); + filterAction->setOutputFile(tempFile->file()); + filterAction->setInputFileName(url.path()); + filterAction->execute(true); + filterAction->setOutputFile(0L); + filterAction->setInputFileName(QString::null); + tempFile->close(); + tempFileList.append(tempFile); + url.setPath(tempFile->name()); + } + return url; +} + +QString TemplatesTreeView::createTemplateTarball() +{ + KURL url = currentURL(); + KURL dirURL (url); + if (!currentKFileTreeViewItem()->isDir()) + dirURL.setPath(dirURL.directory(false)); + + KTempDir* tempDir = new KTempDir(tmpDir); + tempDir->setAutoDelete(true); + tempDirList.append(tempDir); + QString tempFileName=tempDir->name() + url.fileName() + ".tgz"; + //pack the files into a .tgz file + KTar tar(tempFileName, "application/x-gzip"); + tar.open(IO_WriteOnly); +// tar.setOrigFileName(""); + + KURL::List files; + if ( ! currentKFileTreeViewItem()->isDir() ) + files.append(url); + else { + files = QExtFileInfo::allFiles(dirURL, "*", this) ; + dirURL = dirURL.upURL(); + } + + for ( KURL::List::Iterator it_f = files.begin(); it_f != files.end(); ++it_f ) + { + if (!(*it_f).fileName(false).isEmpty()) { + url = QExtFileInfo::toRelative( (*it_f), dirURL) ; + + QFile file((*it_f).path()); + file.open(IO_ReadOnly); + QByteArray bArray = file.readAll(); + tar.writeFile(url.path(), "user", "group", bArray.size(), bArray.data()); + file.close(); + }; + } + tar.close(); + + return tempFileName; +} + +void TemplatesTreeView::slotSendInMail() +{ + if ( ! currentKFileTreeViewItem() ) return; + + + QStringList attachmentFile; + attachmentFile += createTemplateTarball(); + + TagMailDlg *mailDlg = new TagMailDlg( this, i18n("Send template in email")); + QString toStr; + QString message = i18n("Hi,\n This is a Quanta Plus [http://quanta.kdewebdev.org] template tarball.\n\nHave fun.\n"); + QString titleStr; + QString subjectStr; + + mailDlg->TitleLabel->setText(i18n("Content:")); +/* mailDlg->titleEdit->setFixedHeight(60); + mailDlg->titleEdit->setVScrollBarMode(QTextEdit::Auto); + mailDlg->titleEdit->setHScrollBarMode(QTextEdit::Auto);*/ + if ( mailDlg->exec() ) + { + if ( !mailDlg->lineEmail->text().isEmpty()) + { + toStr = mailDlg->lineEmail->text(); + subjectStr = (mailDlg->lineSubject->text().isEmpty())?i18n("Quanta Plus Template"):mailDlg->lineSubject->text(); + if ( !mailDlg->titleEdit->text().isEmpty()) + message = mailDlg->titleEdit->text(); + } else + { + KMessageBox::error(this,i18n("No destination address was specified.\n Sending is aborted."),i18n("Error Sending Email")); + delete mailDlg; + return; + } + kapp->invokeMailer(toStr, QString::null, QString::null, subjectStr, message, QString::null, attachmentFile); + } + delete mailDlg; +} + +void TemplatesTreeView::slotUploadTemplate() +{ + if ( ! currentKFileTreeViewItem() ) return; + emit uploadTemplate(createTemplateTarball()); +} + +bool TemplatesTreeView::acceptDrag(QDropEvent* e ) const +{ + return (BaseTreeView::acceptDrag(e) || QTextDrag::canDecode(e)); +} + +void TemplatesTreeView::slotExtractSiteTemplate() +{ + QString startDir = m_projectBaseURL.url(); + if (startDir.isEmpty()) + startDir = QDir::homeDirPath(); + bool error = false; + KURLRequesterDlg urlRequester(startDir, i18n("Target folder"), this, "req", true); + urlRequester.urlRequester()->setMode(KFile::Directory); + if (urlRequester.exec()) + { + KURL targetURL = urlRequester.selectedURL(); + KURL url = currentURL(); + QString tempFile; + if (KIO::NetAccess::download(url, tempFile, this)) + { + KTar tar(tempFile); + if (tar.open(IO_ReadOnly)) + { + const KArchiveDirectory *directory = tar.directory(); + if (targetURL.protocol() == "file") + directory->copyTo(targetURL.path(), true); + else + { + KTempDir* tempDir = new KTempDir(tmpDir); + tempDir->setAutoDelete(true); + QString tempDirName = tempDir->name(); + directory->copyTo(tempDirName, true); + QStringList entries = directory->entries(); + KURL::List fileList; + for (QStringList::Iterator it = entries.begin(); it != entries.end(); ++it) + fileList.append(KURL::fromPathOrURL(tempDirName + "/" + *it)); + if (!KIO::NetAccess::dircopy(fileList, targetURL, this)) + error = true; + KIO::NetAccess::del(KURL().fromPathOrURL(tempDirName), this); + delete tempDir; + } + tar.close(); + } else + error = true; + KIO::NetAccess::removeTempFile(tempFile); + if (!m_projectBaseURL.isEmpty() && !QExtFileInfo::toRelative(targetURL, m_projectBaseURL).url().startsWith(".")) + { + if (KMessageBox::questionYesNo(this, i18n("You have extracted the site template to a folder which is not under your main project folder.\nDo you want to copy the folder into the main project folder?"), QString::null, i18n("Copy Folder"), i18n("Do Not Copy")) == KMessageBox::Yes) + { + emit insertDirInProject(targetURL); + } + } + } else + error = true; + if (error) + KMessageBox::error(this, i18n("<qt>Some error happened while extracting the <i>%1</i> site template file.<br>Check that you have write permission for <i>%2</i> and that there is enough free space in your temporary folder.</qt>").arg(url.prettyURL(0, KURL::StripFileProtocol)).arg(targetURL.prettyURL(0, KURL::StripFileProtocol))); + } +} + +#include "templatestreeview.moc" diff --git a/quanta/treeviews/templatestreeview.h b/quanta/treeviews/templatestreeview.h new file mode 100644 index 00000000..c0df69e5 --- /dev/null +++ b/quanta/treeviews/templatestreeview.h @@ -0,0 +1,162 @@ +/*************************************************************************** + templatestreeview.h - description + ------------------- + begin : Thu Dec 20 2001 + copyright : (C) 2001-2004 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef TEMPLATESTREEVIEW_H +#define TEMPLATESTREEVIEW_H + +//own includes +#include "basetreeview.h" +#include "quantacommon.h" + +//forward declarations +class QuantaPropertiesPage; +class KMainWindow; + +class TemplatesTreeBranch : public BaseTreeBranch { + +public: + TemplatesTreeBranch(KFileTreeView *parent, const KURL& url, + const QString& name, const QPixmap& pix, + bool showHidden = false, KFileTreeViewItem *branchRoot = 0L); + + /** read the mimetype */ + virtual KFileTreeViewItem* createTreeViewItem(KFileTreeViewItem *parent, + KFileItem *fileItem ); +}; + + +class TemplatesTreeView : public BaseTreeView { + Q_OBJECT + +public: + + /** + * since this class is a singleton you must use this function to access it + * + * the parameter are only used at the first call to create the class + * + */ + static TemplatesTreeView* const ref(KMainWindow *parent = 0L, const char *name = 0L) + { + static TemplatesTreeView *m_ref; + if (!m_ref) m_ref = new TemplatesTreeView (parent, name); + return m_ref; + } + + ~TemplatesTreeView(); + /** Writes a .dirinfo file from the selected item's path */ + bool writeDirInfo(const QString& dirInfoFile = QString::null); + /** Reads a .dirinfo file from the selected item's path */ + DirInfo readDirInfo(const QString& dir = QString::null); + + +public slots: + + /** Inserts the content of the selected template into the + * activ document + */ + void slotInsertInDocument(); + + /** + * displays the RBM + * + * + * @param listView KListView where the event comes from + * + * @param item QListViewItem where the mousepointer is hovering + * + * @param point QPoint coordinates of the event + * + */ + void slotMenu(KListView *listView, QListViewItem *item, const QPoint &point); + /** Creates a new document based in the selected template. */ + void slotNewDocument(); + /** Insert the template as text, image, new document. */ + void slotInsert(); + /** Extracts the site template to an user specified directory */ + void slotExtractSiteTemplate(); + /** No descriptions */ + void slotNewDir(); + /** Handles dropping on the document from the template tree */ + void slotDragInsert(QDropEvent *); + + /** + * slot for the RBM + * + * packs and sends files or folders as attachment to an email + */ + void slotSendInMail(); + void slotUploadTemplate(); + virtual void slotSelectFile(QListViewItem *item); + void slotOpen(); + void slotPaste(); + void slotDelete(); + /** Properties dialog for template view */ + virtual void slotProperties(); + /** Property application for template view */ + virtual void slotPropertiesApplied(); + void slotInsertTag(); + + /** Sets the project template directory */ + void slotNewProjectLoaded(const QString &, const KURL &, const KURL &); + +private: + + /** The constructor is privat because we use singleton pattern. + * If you need the class use TemplatesTreeView::ref() for + * construction and reference + */ + TemplatesTreeView(KMainWindow *parent, const char *name = 0L); + /** Filters the template through and action, and returns the modified/filtered + template file */ + KURL filterTemplate(); + void writeTemplateInfo(); + void updateTypeDescription(KFileTreeViewItem *item, const QString &typeString); + + BaseTreeBranch *m_projectDir; + int m_deleteMenuId; + int m_openId; + int m_reloadMenuId; + int m_downloadMenuId; + QuantaPropertiesPage *m_quantaProperties; + QString m_projectName; + KURL localURL; + KURL globalURL; + KPopupMenu *m_fileMenu; + KPopupMenu *m_folderMenu; + KPopupMenu *m_emptyAreaMenu; + KMainWindow *m_mainWindow; + DirInfo m_dirInfo; + DirInfo m_parentDirInfo; + int m_insertFileInProject; + int m_insertFolderInProject; + int m_menuClose; ///< remembers the menu entry + int m_menuPasteFolder; ///< remembers the menu entry + +signals: // Signals + void insertFile(const KURL &); + void downloadTemplate(); + void uploadTemplate(const QString&); + +protected: // Protected methods + KFileTreeBranch* newBranch(const KURL& url); + virtual QDragObject * dragObject(); +// virtual void startDrag(); + void contentsDropEvent(QDropEvent *event); + bool acceptDrag(QDropEvent* e ) const; + QString createTemplateTarball(); +}; + +#endif diff --git a/quanta/treeviews/uploadtreefile.cpp b/quanta/treeviews/uploadtreefile.cpp new file mode 100644 index 00000000..2df61f3f --- /dev/null +++ b/quanta/treeviews/uploadtreefile.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** + uploadtreefile.cpp - description + ------------------- + begin : Sun Aug 25 2002 + copyright : (C) 2002, 2003 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +// QT includes +#include <qdir.h> +#include <qpixmap.h> +#include <qfileinfo.h> + +// KDE includes +#include <kfileitem.h> +#include <kiconloader.h> +#include <kurl.h> + +// app includes +#include "uploadtreefile.h" +#include "resource.h" + +UploadTreeFile::UploadTreeFile( UploadTreeFolder *parent, const KURL &a_url, const KFileItem &a_fileItem) + : KListViewItem( parent, a_url.fileName(), "", QString("%1").arg( (long int)a_fileItem.size() ), a_fileItem.timeString()) +{ + m_url = a_url; + isDir = false; + parentFolder = parent; + m_fileItem = new KFileItem(a_fileItem); + m_confirm = false; + + setWhichPixmap("check_clear"); + setText(0, m_url.fileName()); +} + +UploadTreeFile::UploadTreeFile( QListView *parent, const KURL &a_url, const KFileItem &a_fileItem) + : KListViewItem( parent, a_url.fileName(), "", QString("%1").arg( (long int)a_fileItem.size() ), a_fileItem.timeString()) +{ + m_url = a_url; + isDir = false; + parentFolder = 0L; + m_fileItem = new KFileItem(a_fileItem); + m_confirm = false; + + //setPixmap( 1, SmallIcon("check") ); + setWhichPixmap("check_clear"); + setText(0, m_url.fileName()); +} + + +UploadTreeFile::~UploadTreeFile() +{ + delete m_fileItem; +} + +int UploadTreeFile::permissions() +{ + if (m_fileItem) + return m_fileItem->permissions(); + else + return -1; +} + +/** used for sorting */ +QString UploadTreeFile::key ( int, bool ) const +{ + static QString key; + key = QString( "1" + text(0) ); + return key; +// return QFileInfo(key).extension()+key; +} + +void UploadTreeFile::setWhichPixmap(const QString& pixmap ) +{ + setPixmap( 1, SmallIcon(pixmap) ); +} + +/** No descriptions */ +KURL UploadTreeFile::url() +{ + return m_url; +} diff --git a/quanta/treeviews/uploadtreefile.h b/quanta/treeviews/uploadtreefile.h new file mode 100644 index 00000000..54c8ce01 --- /dev/null +++ b/quanta/treeviews/uploadtreefile.h @@ -0,0 +1,53 @@ +/*************************************************************************** + uploadtreefile.h - description + ------------------- + begin : Sun Aug 25 2002 + copyright : (C) 2002, 2003 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef UPLOADTREEFILE_H +#define UPLOADTREEFILE_H + +#include <klistview.h> + +#include "uploadtreefolder.h" + +/** + *@author George Vilches & Andras Mantia + */ + +class KFileItem; + +class UploadTreeFile : public KListViewItem { +public: + UploadTreeFile( UploadTreeFolder *parent, const KURL &a_url, const KFileItem &a_fileItem); + UploadTreeFile( QListView *parent, const KURL &a_url, const KFileItem &a_fileItem); + ~UploadTreeFile(); + + void setWhichPixmap(const QString& pixmap); + int permissions(); + + /** used for sorting */ + virtual QString key ( int column, bool ascending ) const; + /** No descriptions */ + KURL url(); + void setConfirmUpload(bool confirm) {m_confirm = confirm;} + bool confirmUpload() {return m_confirm;} + +public: + UploadTreeFolder * parentFolder; + KURL m_url; + bool isDir; + bool m_confirm; + KFileItem *m_fileItem; +}; + +#endif diff --git a/quanta/treeviews/uploadtreefolder.cpp b/quanta/treeviews/uploadtreefolder.cpp new file mode 100644 index 00000000..f38e648c --- /dev/null +++ b/quanta/treeviews/uploadtreefolder.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + uploadtreefolder.cpp - description + ------------------- + begin : Sun Aug 25 2002 + copyright : (C) 2002 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +// QT includes +#include <qdir.h> +#include <qdragobject.h> +#include <qevent.h> +#include <qpixmap.h> + +// KDE includes +#include <kiconloader.h> + +// app includes +#include "uploadtreefolder.h" +#include "uploadtreefile.h" +#include "resource.h" + +UploadTreeFolder::UploadTreeFolder(const KURL &a_url, UploadTreeFolder * parent, const char * name ) + : KListViewItem( parent, name, "", "", "" ) +{ + parentFolder = parent; + m_url = a_url; + m_url.adjustPath(1); + + setPixmap( 0, SmallIcon("folder") ); + setPixmap( 1, SmallIcon("check") ); + setText(0, m_url.fileName()); + +} + +UploadTreeFolder::UploadTreeFolder(const KURL &a_url, QListView * parent, const char * name ) + : KListViewItem( parent, name, "", "", "" ) +{ + parentFolder = 0L; + m_url = a_url; + m_url.adjustPath(1); + + setPixmap( 0, SmallIcon("folder") ); + setPixmap( 1, SmallIcon("check") ); + setText(0, m_url.fileName()); +} + + +void UploadTreeFolder::setOpen( bool open ) +{ + QListViewItem::setOpen( open ); +} + +/** retun full name of the folder */ +//TODO: This should go away. Use url() instead. +QString UploadTreeFolder::fullName() +{ + QString s=""; + + if ( parentFolder ) + { + s = parentFolder->fullName(); + s += m_url.fileName()+"/"; + } + else { + s = m_url.fileName(); + } + + return s; +} + +/** setup */ +void UploadTreeFolder::setup() +{ + setExpandable( true ); + QListViewItem::setup(); +} + +/** reload file list */ +void UploadTreeFolder::reloadList() +{ + setOpen( false ); + + QListViewItem *child; + while ( (child = firstChild()) ) + removeItem( child ); + + setOpen( true ); +} + +/** need for sorting */ +QString UploadTreeFolder::key ( int, bool ) const +{ + static QString key; + + key = QString("0") + text(0); + + return key; +} + +UploadTreeFolder::~UploadTreeFolder() +{ +} + +void UploadTreeFolder::setWhichPixmap(const QString& pixmap ) +{ + setPixmap( 1, SmallIcon(pixmap) ); +} + diff --git a/quanta/treeviews/uploadtreefolder.h b/quanta/treeviews/uploadtreefolder.h new file mode 100644 index 00000000..1ef77279 --- /dev/null +++ b/quanta/treeviews/uploadtreefolder.h @@ -0,0 +1,57 @@ +/*************************************************************************** + uploadtreefolder.h - description + ------------------- + begin : Sun Aug 25 2002 + copyright : (C) 2002 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef UPLOADTREEFOLDER_H +#define UPLOADTREEFOLDER_H + +#include <qfile.h> +#include <qfileinfo.h> +#include <qstring.h> +#include <qstringlist.h> + +#include <klistview.h> +#include <kurl.h> + +/** + *@author Andras Mantia + */ + +class KURL; + +class UploadTreeFolder : public KListViewItem { +public: + UploadTreeFolder( const KURL &a_url, QListView * parent, const char * name); + UploadTreeFolder( const KURL &a_url, UploadTreeFolder * parent, const char * name ); + virtual ~UploadTreeFolder(); + + /** used for sorting */ + virtual QString key ( int column, bool ascending ) const; + QString fullName(); + KURL url() {return m_url;} + + virtual void setOpen( bool ); + void setup(); + void setWhichPixmap(const QString& pixmap ); + +public: + UploadTreeFolder * parentFolder; + KURL m_url; + +public slots: // Public slots + void reloadList(); + +}; + +#endif diff --git a/quanta/treeviews/uploadtreeview.cpp b/quanta/treeviews/uploadtreeview.cpp new file mode 100644 index 00000000..75d0fa0c --- /dev/null +++ b/quanta/treeviews/uploadtreeview.cpp @@ -0,0 +1,451 @@ +/*************************************************************************** + uploadtreeview.cpp - description + ------------------- + begin : Sun Aug 25 2002 + copyright : (C) 2002 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#include <qregexp.h> + +#include <kcursor.h> +#include <klocale.h> +#include <kurl.h> +#include <kfileitem.h> + +#include "uploadtreeview.h" +#include "quantacommon.h" + +UploadTreeView::UploadTreeView( QWidget *parent, const char *name ) : + KListView(parent, name) +{ + setRootIsDecorated( true ); + setSorting( 0 ); + setMultiSelection(true); + + setFrameStyle( Panel | Sunken ); + setLineWidth( 2 ); + addColumn( i18n("Name") ); + addColumn( i18n("Upload") ); + addColumn( i18n("Size") ); + addColumn( i18n("Date") ); + + setFocusPolicy(QWidget::ClickFocus); + + connect( this, SIGNAL(selectionChanged()), SLOT(slotSelectFile())); + connect( this, SIGNAL(selectionChanged(QListViewItem *)), + this, SLOT(slotSelectFile(QListViewItem *))); + + connect(this, SIGNAL(doubleClicked(QListViewItem *, const QPoint &, int )), SLOT(slotDoubleClicked(QListViewItem *, const QPoint &, int ))); +} + +UploadTreeView::~UploadTreeView() +{ +} + +int UploadTreeView::checkboxTree( QListViewItem *it ) +{ + parentWidget()->setCursor(KCursor::workingCursor()); + + QListViewItem *itIter = it ? it->firstChild() : firstChild(); + + // bitFlag structure: (0/1)all children exist (0/1)no children exist. + // We don't need some children as a bit flag, because that's implied if the bits are "00". + + int bitFlags = 3; + int retVal = 1; + + if ( itIter != 0 ) + { + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { + if ( dynamic_cast<UploadTreeFolder *>(itIter) ) + { + int hadCheckFlags = checkboxTree( itIter ); + bitFlags &= hadCheckFlags; + UploadTreeFolder *itF = static_cast<UploadTreeFolder *>(itIter); + + if (hadCheckFlags == 2) { + // All children exist. + itF->setWhichPixmap( "check" ); + itF->setSelected( true ); + } + else if (hadCheckFlags == 1) { + // No children exist. + itF->setWhichPixmap( "check_clear" ); + itF->setSelected( false ); + } + else { + // Some children exist. + itF->setWhichPixmap( "check_grey" ); + itF->setSelected( true ); + } + + } + else if ( dynamic_cast<UploadTreeFile *>(itIter) ) + { + UploadTreeFile *itF = static_cast<UploadTreeFile *>(itIter); + if ( itF->isSelected() ) + { + itF->setWhichPixmap("check"); + // Turn off "no children" + if ( bitFlags % 2 == 1 ) bitFlags -= 1; + } + else + { + itF->setWhichPixmap("check_clear"); + // Turn off "all children". + if (bitFlags >> 1 == 1) bitFlags -= 2; + } + + } + } + retVal = bitFlags; + } else + { + if ( dynamic_cast<UploadTreeFolder *>(it) ) + { + UploadTreeFolder *itF = static_cast<UploadTreeFolder *>(it); + if ( itF->isSelected() ) + { + itF->setWhichPixmap("check"); + retVal = 2; + } + else + { + itF->setWhichPixmap("check_clear"); + retVal = 1; + } + + } + } + + parentWidget()->setCursor(KCursor::arrowCursor()); + + return retVal; +} + +void UploadTreeView::selectAllUnderNode( QListViewItem* it, bool select ) +{ + QListViewItem *itIter = 0; + if (it == 0) itIter = firstChild(); + else itIter = it->firstChild(); + + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { + itIter->setSelected(select); + selectAllUnderNode(itIter, select); + if (itIter->isSelected() != select) + itIter->setSelected(select); + } +} + +void UploadTreeView::slotSelectFile( QListViewItem *it ) +{ + UploadTreeFolder *itF = dynamic_cast<UploadTreeFolder *>(it); + // This need a bit of special behavior for clicking on directories. + if ( itF ) + { + itF->setSelected(it->isSelected()); + selectAllUnderNode( it, it->isSelected() ); + } + +//set the correct checkbox for this item, if it was a folder + int hadCheckFlags = checkboxTree(it); + if ( itF ) + { + if (hadCheckFlags == 2) { + // All children exist. + itF->setWhichPixmap( "check" ); + itF->setSelected( true ); + } + else if (hadCheckFlags == 1) { + // No children exist. + itF->setWhichPixmap( "check_clear" ); + itF->setSelected( false ); + } + else { + // Some children exist. + itF->setWhichPixmap( "check_grey" ); + itF->setSelected( true ); + } + + itF = itF->parentFolder; + } + else + { + UploadTreeFile *itFile = static_cast<UploadTreeFile*>(it); + if (it->isSelected()) + { + itFile->setWhichPixmap("check"); + itFile->setSelected(true); + } else + { + itFile->setWhichPixmap("check_clear"); + itFile->setSelected(false); + } + itF = itFile->parentFolder; + } + + //iterate through the item's parents and set the correct checkboxes for them + while (itF) + { + bool hasSelected = false; + bool allSelected = true; + //check if the item has any children's selected + QListViewItemIterator iter(itF->firstChild()); + while ( iter.current() && iter.current() != itF->nextSibling()) + { + if ( iter.current()->isSelected() ) + { + hasSelected = true; + } else + { + allSelected = false; + } + ++iter; + } + if (hasSelected) + { + if (allSelected) + { + itF->setWhichPixmap( "check" ); + } else + { + itF->setWhichPixmap( "check_grey" ); + } + itF->setSelected( true ); + } else + { + itF->setWhichPixmap( "check_clear" ); + itF->setSelected( false ); + } + itF = itF->parentFolder; + } +} + +void UploadTreeView::slotSelectFile( ) +{ + slotSelectFile(currentItem()); +} + +//TODO: This should search based on url's rather than on text(0) +UploadTreeFolder* UploadTreeView::findFolder( UploadTreeFolder *it, const QString& folderName ) +{ + QListViewItem *itIter = 0; + if (it == 0) itIter = firstChild(); + else itIter = it->firstChild(); + + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { + if ( itIter->text(0) == folderName ) + { + return (UploadTreeFolder *)itIter; + } + } + return 0; +} + +UploadTreeFolder* UploadTreeView::printTree( UploadTreeFolder *it = 0,const QString& indent = QString::null ) +{ + QListViewItem *itIter = 0; + if (it == 0) itIter = firstChild(); + else itIter = it->firstChild(); + + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { +// cout << indent << itIter->text(0) << endl; + if ( dynamic_cast<UploadTreeFolder *>(itIter) ) + printTree( (UploadTreeFolder *)itIter, indent + " " ); + } + return 0; +} + +// :NOTE: AFAIK, safe to use only if you are sure the item searched for +// is already in here. It might be safe otherwise, but use at your own +// peril. +QListViewItem* UploadTreeView::findItem(const QString& path ) +{ + QString item = path; + UploadTreeFolder *it = 0; + int i; + while ( ( i = item.find('/') ) >= 0 ) + { + it = findFolder( it, item.left(i) ); + if ( it == 0 ) + return 0; + item.remove(0,i+1); + } + + QListViewItem *itIter = 0; + if ( it == 0 ) itIter = firstChild(); + else itIter = it->firstChild(); + + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { + if ( itIter->text(0) == item ) + { + return itIter; + } + } + return 0; +} + +UploadTreeFile* UploadTreeView::addItem(const KURL &a_url, const KFileItem& a_fileItem) +{ + QString item = a_url.path(); //TODO: do with real KURL's + QString fname = item; + int i; + uint col = 0; + UploadTreeFolder *it = 0; + KURL u; + while ( ( i = item.find('/', col) ) >= 0 ) + { + if ( i!=0 ) + { + UploadTreeFolder *itTemp = findFolder(it, item.mid(col, i - col)); + if ( itTemp == 0 ) + { + u = a_url; + QuantaCommon::setUrl(u,item.left(i)+"/"); + if ( it == 0 ) + { + it = new UploadTreeFolder(u, this, ""); + } + else { + it = new UploadTreeFolder(u, it, ""); + } + } + else + { + it = itTemp; + } + } + col = i + 1; + } + UploadTreeFile *file = 0; + if ( col < item.length() ) + { + if (it == 0) + { + file = new UploadTreeFile(this, a_url, a_fileItem); + } + else + { + file = new UploadTreeFile(it, a_url, a_fileItem); + } + } + return file; +} + +void UploadTreeView::expandAll( QListViewItem *it ) +{ + QListViewItem *itIter = it; + if (it == 0) itIter = firstChild(); + else itIter = it->firstChild(); + + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { + if ( dynamic_cast<UploadTreeFolder *>(itIter) ) + { + itIter->setOpen( true ); + expandAll( itIter ); + } + } +} + +void UploadTreeView::collapseAll( QListViewItem *it ) +{ + QListViewItem *itIter = it; + if (it == 0) itIter = firstChild(); + else itIter = it->firstChild(); + + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { + if ( dynamic_cast<UploadTreeFolder *>(itIter) ) + { + itIter->setOpen( false ); + expandAll( itIter ); + } + } +} + +void UploadTreeView::invertAll( QListViewItem *it ) +{ + QListViewItem *itIter = it; + if (it == 0) itIter = firstChild(); + else itIter = it->firstChild(); + + for( ; itIter != 0; itIter = itIter->nextSibling() ) + { + if ( dynamic_cast<UploadTreeFile *>(itIter) || + ( dynamic_cast<UploadTreeFolder *>(itIter) && + !itIter->firstChild()) ) + { + itIter->setSelected( !itIter->isSelected() ); + } + else + { + invertAll( itIter ); + } + } +} + +void UploadTreeView::selectAll( bool select ) +{ + QListViewItemIterator it(this); + + for ( ; it.current(); ++it ) + { + if ( dynamic_cast<UploadTreeFile *>(it.current()) ) + { + it.current()->setSelected( select); + } else + if ( dynamic_cast<UploadTreeFolder *>(it.current()) && + !it.current()->firstChild() ) + { + it.current()->setSelected( select); + } + } +} + + +/** No descriptions */ +QListViewItem* UploadTreeView::itemByUrl(const KURL& a_url) +{ + QListViewItemIterator it(this); + UploadTreeFile *fileItem; + UploadTreeFolder *folderItem; + KURL url; + for ( ; it.current(); ++it ) + { + if ( (fileItem = dynamic_cast<UploadTreeFile *>(it.current()) ) !=0) + { + url = fileItem->m_url; + } else + { + folderItem = static_cast<UploadTreeFolder*>(it.current()); + url = folderItem->m_url; + } + if (url == a_url) + { + return it.current(); + } + } + + return 0L; +} + +void UploadTreeView::slotDoubleClicked(QListViewItem *item, const QPoint &, int ) +{ + item->setOpen(!item->isOpen()); +} + +#include "uploadtreeview.moc" diff --git a/quanta/treeviews/uploadtreeview.h b/quanta/treeviews/uploadtreeview.h new file mode 100644 index 00000000..85676e41 --- /dev/null +++ b/quanta/treeviews/uploadtreeview.h @@ -0,0 +1,60 @@ +/*************************************************************************** + uploadtreeview.h - description + ------------------- + begin : Sun Aug 25 2002 + copyright : (C) 2002, 2003 by 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; version 2 of the License. * + * * + ***************************************************************************/ + +#ifndef UPLOADTREEVIEW_H +#define UPLOADTREEVIEW_H + +#include <qdir.h> +#include <qpixmap.h> +#include <qheader.h> + +#include "uploadtreefolder.h" +#include "uploadtreefile.h" + +class KFileItem; + +/** + *@author George Vilches & Andras Mantia + */ + +class UploadTreeView : public KListView { + Q_OBJECT +public: + UploadTreeView( QWidget *parent, const char *name=0L ); + ~UploadTreeView(); + UploadTreeFile* addItem( const KURL &a_url, const KFileItem &a_fileItem); + QListViewItem* findItem( const QString& ); + int checkboxTree( QListViewItem *it = 0); + void expandAll( QListViewItem * = 0 ); + void collapseAll( QListViewItem * = 0 ); + void invertAll( QListViewItem * = 0 ); + virtual void selectAll( bool select); + /** No descriptions */ + QListViewItem* itemByUrl(const KURL& a_url); + +public slots: + void slotSelectFile( QListViewItem * ); + void slotSelectFile( ); + void selectAllUnderNode( QListViewItem *it, bool select ); + +private slots: + void slotDoubleClicked(QListViewItem *, const QPoint &, int ); + +private: + UploadTreeFolder* findFolder( UploadTreeFolder *, const QString&); + UploadTreeFolder* printTree( UploadTreeFolder *, const QString&); +}; + +#endif |