diff options
Diffstat (limited to 'kbabel/catalogmanager')
87 files changed, 11253 insertions, 0 deletions
diff --git a/kbabel/catalogmanager/Makefile.am b/kbabel/catalogmanager/Makefile.am new file mode 100644 index 00000000..2d8d1836 --- /dev/null +++ b/kbabel/catalogmanager/Makefile.am @@ -0,0 +1,64 @@ +## Makefile.am for KBabel catalogmanager + +# this has all of the subdirectories that make will recurse into. If +# there are none, comment this out +SUBDIRS = libcvs libsvn icons + +# this is the program that gets installed. Its name is used for all +# of the other Makefile.am variables +noinst_LTLIBRARIES = libcatalogmanager.la +bin_PROGRAMS = catalogmanager + +# set the include path for X, qt and KDE. Let $(all_includes) be always last. +INCLUDES = -I$(srcdir)/../common -I../common -I$(srcdir)/../kbabeldict \ +-I$(srcdir)/../commonui -I../commonui -I./libsvn -I./libcvs \ +-I$(srcdir)/libsvn -I$(srcdir)/libcvs $(all_includes) + + +# which sources should be compiled for kbabel +libcatalogmanager_la_SOURCES = catalogmanageriface.skel \ + validationoptions.ui \ + catalogmanagerview.cpp \ + catalogmanager.cpp findinfilesdialog.cpp \ + catmanlistitem.cpp multiroughtransdlg.cpp validateprogresswidget.ui \ + validateprogress.cpp markpatternwidget.ui markpatterndialog.cpp + + +libcatalogmanager_la_LIBADD = ../commonui/libkbabelcommonui.la \ +../kbabeldict/libkbabeldict.la ./libcvs/libcatalogmanagercvs.la \ +./libsvn/libcatalogmanagersvn.la $(LIB_KIO) +libcatalogmanager_la_LDFLAGS = $(all_libraries) -no-undefined + + +catalogmanager_SOURCES = main.cpp + +# the libraries to link against. +catalogmanager_LDADD = libcatalogmanager.la +catalogmanager_LDFLAGS = $(all_libraries) $(KDE_RPATH) + +# these are the headers for your project +noinst_HEADERS = catalogmanageriface.h catalogmanager.h \ + catalogmanagerview.h catalogmanagerapp.h findinfilesdialog.h \ + catmanlistitem.h catmanresource.h multiroughtransdlg.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO + +rcdir = $(kde_datadir)/catalogmanager +rc_DATA = catalogmanagerui.rc + + +api: + mkdir -p API && kdoc -d API -u $$PWD/API -p -lkdeui -lkdecore -lqt -ldcop $(noinst_HEADERS) + +distclean-local: + rm -r -f API + +KDE_ICON = AUTO + +# this is where the kdelnk file will go +xdg_apps_DATA = catalogmanager.desktop + +catalogmanager.lo: ../common/version.h +main.o: ../common/version.h + diff --git a/kbabel/catalogmanager/catalogmanager.cpp b/kbabel/catalogmanager/catalogmanager.cpp new file mode 100644 index 00000000..6cbe964d --- /dev/null +++ b/kbabel/catalogmanager/catalogmanager.cpp @@ -0,0 +1,1371 @@ +/***************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2004 by Stanislav Visnovsky <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + +#include "catmanresource.h" +#include "catalogmanager.h" +#include "catalog.h" +#include "catalogmanagerapp.h" +#include "findinfilesdialog.h" +#include "kbabeldictbox.h" +#include "resources.h" +#include "projectpref.h" +#include "kbprojectmanager.h" +#include "projectwizard.h" +#include "msgfmt.h" +#include "toolaction.h" + +#include <qlabel.h> +#include <qpainter.h> + +#include <dcopclient.h> +#include <kapplication.h> +#include <kaction.h> +#include <kcmenumngr.h> +#include <kconfig.h> +#include <kcursor.h> +#include <kdatatool.h> +#include <kdialogbase.h> +//#include <kedittoolbar.h> +#include <kfiledialog.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <klocale.h> +#include <kpopupmenu.h> +#include <kprogress.h> +#include <kstdaccel.h> +#include <kstdaction.h> +#include <kstandarddirs.h> +#include <kstatusbar.h> +#include <ktoolbar.h> +#include <kwin.h> + +#include <qfileinfo.h> +#include <qdir.h> +#include <qtimer.h> +#include <qbitmap.h> +#include <qwhatsthis.h> +#include <qheader.h> +#include <qdragobject.h> +#include <qlayout.h> +#include <qhbox.h> + +using namespace KBabel; + +WId CatalogManagerApp::_preferredWindow = 0; + +QStringList CatalogManager::_foundFilesList; +QStringList CatalogManager::_toBeSearched; + +CatalogManager::CatalogManager(QString configFile ) + :KMainWindow(0,0) +{ + if ( configFile.isEmpty() ) + configFile = KBabel::ProjectManager::defaultProjectName(); + _configFile = configFile; + + init(); + restoreSettings(); + updateSettings(); +} + +CatalogManager::~CatalogManager() +{ + saveView(); + saveSettings(_configFile); + delete config; +} + +void CatalogManager::init() +{ + _foundToBeSent = 0; + _totalFound = 0; + _foundFilesList.clear(); + _toBeSearched.clear(); + _timerFind = new QTimer( this ); + connect(_timerFind, SIGNAL( timeout() ), this, SLOT(findNextFile()) ); + _searchStopped = false; + + _prefDialog=0; + _findDialog=0; + _replaceDialog=0; + + _project = KBabel::ProjectManager::open(_configFile); + + if ( _project == NULL ) + { + KMessageBox::error( this, i18n("Cannot open project file\n%1").arg(_configFile) + , i18n("Project File Error")); + + _project = KBabel::ProjectManager::open(KBabel::ProjectManager::defaultProjectName()); + } + + connect( _project, SIGNAL (signalCatManSettingsChanged()) + , this, SLOT (updateSettings())); + + QWidget *view = new QWidget(this); + QVBoxLayout* layout= new QVBoxLayout(view); + layout->setMargin(0); + layout->setSpacing(KDialog::spacingHint()); + + _catalogManager=new CatalogManagerView(_project, view,"catalog manager"); + layout->addWidget(_catalogManager); + layout->setStretchFactor(_catalogManager,1); + + connect(this,SIGNAL(settingsChanged(KBabel::CatManSettings)) + ,_catalogManager,SLOT(setSettings(KBabel::CatManSettings))); + connect(_catalogManager,SIGNAL(openFile(QString,QString)) + ,this,SLOT(openFile(QString,QString))); + connect(_catalogManager,SIGNAL(openFileInNewWindow(QString,QString)) + ,this,SLOT(openFileInNewWindow(QString,QString))); + connect(_catalogManager,SIGNAL(openTemplate(QString,QString,QString)) + ,this,SLOT(openTemplate(QString,QString,QString))); + connect(_catalogManager,SIGNAL(openTemplateInNewWindow(QString,QString,QString)) + ,this,SLOT(openTemplateInNewWindow(QString,QString,QString))); + connect(_catalogManager,SIGNAL(gotoFileEntry(QString,QString,int)) + ,this,SLOT(openFile(QString,QString,int))); + connect(_catalogManager, SIGNAL(selectedChanged(uint)), + this, SLOT(selectedChanged(uint))); + + KWin::setIcons(winId(),BarIcon("catalogmanager",32) + ,SmallIcon("catalogmanager")); + + QHBoxLayout* hBoxL = new QHBoxLayout(layout); + _progressLabel = new QLabel(view); + hBoxL->addWidget(_progressLabel); + _progressBar=new KProgress(view); + hBoxL->addWidget(_progressBar); + hBoxL->setStretchFactor(_progressBar,1); + + _progressLabel->hide(); + _progressBar->hide(); + + connect(_catalogManager,SIGNAL(prepareProgressBar(QString,int)) + , this, SLOT(prepareProgressBar(QString,int))); + connect(_catalogManager,SIGNAL(clearProgressBar()) + , this, SLOT(clearProgressBar())); + connect(_catalogManager,SIGNAL(progress(int)) + , _progressBar, SLOT(setProgress(int))); +// connect(_catalogManager, SIGNAL(signalBuildTree(bool)) +// , this, SLOT(enableMenuForFiles(bool))); + connect(_catalogManager, SIGNAL(signalBuildTree(bool)) + , this, SLOT(enableActions(bool))); + connect(this, SIGNAL(searchStopped()) + , _catalogManager, SLOT(stopSearch())); + connect(_catalogManager, SIGNAL(prepareFindProgressBar(int)) + , this, SLOT(prepareStatusProgressBar(int))); + + setCentralWidget(view); + resize( 600,300); + + setupStatusBar(); + setupActions(); + + + QPopupMenu* popup; + popup = (QPopupMenu*)(factory()->container("rmb_file", this)); + if(popup) + { + _catalogManager->setRMBMenuFile(popup); + } + popup = (QPopupMenu*)(factory()->container("rmb_dir", this)); + if(popup) + { + _catalogManager->setRMBMenuDir(popup); + } + + connect(_catalogManager, SIGNAL(signalSearchedFile(int)) + , _statusProgressBar, SLOT(advance(int))); + + restoreView(); +} + +void CatalogManager::setupActions() +{ + KGlobal::iconLoader()->addAppDir("kbabel"); + + KAction *action; + + // the file menu + action = new KAction( i18n("&Open"), CTRL+Key_O, _catalogManager, + SLOT(slotOpenFile()),actionCollection(), "open"); + action->setEnabled(false); + action = new KAction(i18n("&Open Template"),Key_Space,_catalogManager, + SLOT(slotOpenTemplate()),actionCollection(), "open_template"); + action->setEnabled(false); + action = new KAction(i18n("Open in &New Window"),CTRL+SHIFT+Key_O,_catalogManager, + SLOT(slotOpenFileInNewWindow()),actionCollection(), "open_new_window"); + action->setEnabled(false); + + action = KStdAction::quit(kapp, SLOT (closeAllWindows()), actionCollection()); + + actionMap["open_template"] = NEEDS_POT; + + // the edit menu + action = new KAction( i18n("Fi&nd in Files..."), CTRL+Key_F, this, + SLOT(find()), actionCollection(), "find_in_files"); + action->setEnabled(false); + action = new KAction( i18n("Re&place in Files..."), CTRL+Key_R, this, + SLOT(replace()), actionCollection(), "replace_in_files"); + action->setEnabled(false); + action = new KAction( i18n("&Stop Searching"), "stop", Key_Escape, this, + SLOT(stopSearching()), actionCollection(), "stop_search"); + action->setEnabled(false); + action = new KAction( i18n("&Reload"), "reload", KStdAccel::reload(), _catalogManager, + SLOT(updateCurrent()), actionCollection(), "reload"); + action->setEnabled(false); + + // the marking menu + action = new KAction( i18n("&Toggle Marking"), CTRL+Key_M, _catalogManager, + SLOT(toggleMark()), actionCollection(), "toggle_marking"); + action->setEnabled(false); + action = new KAction( i18n("Remove Marking"), 0, _catalogManager, + SLOT(slotClearMarksInDir()), actionCollection(), "remove_marking"); + action->setEnabled(false); + action = new KAction( i18n("Toggle All Markings"), 0, _catalogManager, + SLOT(toggleAllMarks()), actionCollection(), "toggle_all_marking"); + action->setEnabled(false); + action = new KAction( i18n("Remove All Markings"), 0, _catalogManager, + SLOT(clearAllMarks()), actionCollection(), "remove_all_marking"); + action->setEnabled(false); + action = new KAction( i18n("Mark Modified Files"), 0, _catalogManager, + SLOT(markModifiedFiles()), actionCollection(), "mark_modified_files"); + // fixme to enabling this when loading is done using updateFinished() signal + action->setEnabled(true); + action = new KAction( i18n("&Load Markings..."), 0, _catalogManager, + SLOT(loadMarks()), actionCollection(), "load_marking"); + action->setEnabled(false); + action = new KAction( i18n("&Save Markings..."), 0, _catalogManager, + SLOT(saveMarks()), actionCollection(), "save_marking"); + action->setEnabled(false); + (void)new KAction(i18n("&Mark Files..."), 0, _catalogManager, + SLOT(slotMarkPattern()), actionCollection(), "mark_pattern"); + (void)new KAction(i18n("&Unmark Files..."), 0, _catalogManager, + SLOT(slotUnmarkPattern()), actionCollection(), "unmark_pattern"); + + actionMap["remove_marking"] = NEEDS_MARK; + actionMap["remove_all_marking"] = NEEDS_MARK; + actionMap["mark_pattern"] = NEEDS_DIR; + actionMap["unmark_pattern"] = NEEDS_DIR | NEEDS_MARK; + + // go menu + action = new KAction(i18n("Nex&t Untranslated"), "nextuntranslated", ALT+Key_Next, + _catalogManager, SLOT(gotoNextUntranslated()),actionCollection(), "go_next_untrans"); + action->setEnabled(false); + action = new KAction(i18n("Prev&ious Untranslated"), "prevuntranslated", ALT+Key_Prior, + _catalogManager, SLOT(gotoPreviousUntranslated()),actionCollection(), "go_prev_untrans"); + action->setEnabled(false); + action = new KAction(i18n("Ne&xt Fuzzy"), "nextfuzzy", CTRL+Key_Next, + _catalogManager, SLOT(gotoNextFuzzy()),actionCollection(), "go_next_fuzzy"); + action->setEnabled(false); + action = new KAction(i18n("Pre&vious Fuzzy"), "prevfuzzy", CTRL+Key_Prior, + _catalogManager, SLOT(gotoPreviousFuzzy()),actionCollection(), "go_prev_fuzzy"); + action->setEnabled(false); + action = new KAction(i18n("N&ext Fuzzy or Untranslated"), "nextfuzzyuntrans", CTRL+SHIFT+Key_Next, + _catalogManager, SLOT(gotoNextFuzzyOrUntranslated()),actionCollection(), "go_next_fuzzyUntr"); + action->setEnabled(false); + action = new KAction(i18n("P&revious Fuzzy or Untranslated"), "prevfuzzyuntrans", CTRL+SHIFT+Key_Prior, + _catalogManager, SLOT(gotoPreviousFuzzyOrUntranslated()),actionCollection(), "go_prev_fuzzyUntr"); + action->setEnabled(false); + + action = new KAction(i18n("Next Err&or"), "nexterror", ALT+SHIFT+Key_Next, + _catalogManager, SLOT(gotoNextError()),actionCollection(), "go_next_error"); + action->setEnabled(false); + action = new KAction(i18n("Previo&us Error"), "preverror", ALT+SHIFT+Key_Prior, + _catalogManager, SLOT(gotoPreviousError()),actionCollection(), "go_prev_error"); + action->setEnabled(false); + action = new KAction(i18n("Next Te&mplate Only"), "nexttemplate", CTRL+Key_Down, + _catalogManager, SLOT(gotoNextTemplate()),actionCollection(), "go_next_template"); + action->setEnabled(false); + action = new KAction(i18n("Previous Temp&late Only"), "prevtemplate", CTRL+Key_Up, + _catalogManager, SLOT(gotoPreviousTemplate()),actionCollection(), "go_prev_template"); + action->setEnabled(false); + action = new KAction(i18n("Next Tran&slation Exists"), "nextpo", ALT+Key_Down, + _catalogManager, SLOT(gotoNextPo()),actionCollection(), "go_next_po"); + action->setEnabled(false); + action = new KAction(i18n("Previous Transl&ation Exists"), "prevpo", ALT+Key_Up, + _catalogManager, SLOT(gotoPreviousPo()),actionCollection(), "go_prev_po"); + action->setEnabled(false); + + action = new KAction(i18n("Previous Marke&d"), "prevmarked", SHIFT+Key_Up, + _catalogManager, SLOT(gotoPreviousMarked()),actionCollection(), "go_prev_marked"); + action->setEnabled(false); + action = new KAction(i18n("Next &Marked"), "nextmarked", SHIFT+Key_Down, + _catalogManager, SLOT(gotoNextMarked()),actionCollection(), "go_next_marked"); + action->setEnabled(false); + + // project menu + // the project menu + action = new KAction(i18n("&New..."), "filenew" + , this, SLOT(projectNew()),actionCollection() + ,"project_new"); + + action = new KAction(i18n("&Open..."), "fileopen" + , this, SLOT(projectOpen()),actionCollection() + ,"project_open"); + + action = new KAction(i18n("C&lose"), "fileclose" + , this, SLOT(projectClose()),actionCollection() + ,"project_close"); + + action->setEnabled (_project->filename() != KBabel::ProjectManager::defaultProjectName() ); + + action = new KAction(i18n("&Configure..."), "configure" + , this, SLOT(projectConfigure()),actionCollection() + ,"project_settings"); + + // tools menu + action = new KAction( i18n("&Statistics"), "statistics", CTRL+Key_S, + _catalogManager, SLOT(statistics()), actionCollection(), "statistics"); + action->setEnabled(false); + action = new KAction( i18n("S&tatistics in Marked"), "statistics", CTRL+ALT+Key_S, + _catalogManager, SLOT(markedStatistics()), actionCollection(), "statistics_marked"); + action->setEnabled(false); + action = new KAction( i18n("Check S&yntax"), "syntax", CTRL+Key_Y, + _catalogManager, SLOT(checkSyntax()), actionCollection(), "syntax"); + action->setEnabled(false); + action = new KAction( i18n("S&pell Check"), "spellcheck", CTRL+Key_I, + this, SLOT(spellcheck()), actionCollection(), "spellcheck"); + action->setEnabled(false); + action = new KAction( i18n("Spell Check in &Marked"), "spellcheck", CTRL+ALT+Key_I, + this, SLOT(markedSpellcheck()), actionCollection(), "spellcheck_marked"); + action->setEnabled(false); + action = new KAction( i18n("&Rough Translation"), CTRL+Key_T, + _catalogManager, SLOT(roughTranslation()), actionCollection(), "rough_translation"); + action->setEnabled(false); + action = new KAction( i18n("Rough Translation in M&arked"), CTRL+ALT+Key_T, + _catalogManager, SLOT(markedRoughTranslation()), actionCollection(), "rough_translation_marked"); + action->setEnabled(false); + action = new KAction( i18n("Mai&l"), "mail_send", CTRL+Key_A, + _catalogManager, SLOT(mailFiles()), actionCollection(), "mail_file"); + action->setEnabled(false); + action = new KAction( i18n("Mail Mar&ked"), "mail_send", CTRL+ALT+Key_A, + _catalogManager, SLOT(mailMarkedFiles()), actionCollection(), "mail_file_marked"); + action->setEnabled(false); + + action = new KAction( i18n("&Pack"), "tar", CTRL+Key_B, + _catalogManager, SLOT(packageFiles()), actionCollection(), "package_file"); + action = new KAction( i18n("Pack &Marked"), "tar", CTRL+ALT+Key_B, _catalogManager, SLOT(packageMarkedFiles()), actionCollection(), "package_file_marked"); + action->setEnabled(false); + + actionMap["statistics_marked"] = NEEDS_DIR | NEEDS_MARK; + actionMap["syntax"] = NEEDS_PO; + actionMap["spellcheck"] = NEEDS_PO; + actionMap["spellcheck_marked"] = NEEDS_PO | NEEDS_MARK; + actionMap["rough_translation_marked"] = NEEDS_MARK; + actionMap["mail_file"] = NEEDS_PO; + actionMap["mail_file_marked"] = NEEDS_PO | NEEDS_MARK; + actionMap["package_file_marked"] = NEEDS_PO | NEEDS_MARK; + + // dynamic tools + QValueList<KDataToolInfo> tools = ToolAction::validationTools(); + + QPtrList<KAction> actions = ToolAction::dataToolActionList( + tools, _catalogManager, SLOT(validateUsingTool( const KDataToolInfo &, const QString& )) + ,"validate", false, actionCollection() ); + + KActionMenu* m_menu = new KActionMenu(i18n("&Validation"), actionCollection(), + "dynamic_validation"); + + KAction*ac; + + for(ac = actions.first(); ac ; ac = actions.next() ) + { + m_menu->insert(ac); + } + + actions = ToolAction::dataToolActionList( + tools, _catalogManager, SLOT(validateMarkedUsingTool( const KDataToolInfo &, const QString& )) + ,"validate", false, actionCollection(), "marked_" ); + m_menu = new KActionMenu(i18n("V&alidation Marked"), actionCollection(), + "dynamic_validation_marked"); + + for( ac = actions.first(); ac ; ac = actions.next() ) + { + m_menu->insert(ac); + } + + actionMap["dynamic_validation"] = NEEDS_PO; + actionMap["dynamic_validation_marked"] = NEEDS_PO | NEEDS_MARK; + + // CVS submenu + // Actions for PO files + (void)new KAction( i18n( "Update" ), "down", 0, _catalogManager, + SLOT( cvsUpdate( ) ), actionCollection( ), "cvs_update" ); + (void)new KAction( i18n( "Update Marked" ), 0, _catalogManager, + SLOT( cvsUpdateMarked( ) ), actionCollection( ), "cvs_update_marked" ); + (void)new KAction( i18n( "Commit" ), "up", 0, _catalogManager, + SLOT( cvsCommit( ) ), actionCollection( ), "cvs_commit" ); + (void)new KAction( i18n( "Commit Marked" ), 0, _catalogManager, + SLOT( cvsCommitMarked( ) ), actionCollection( ), "cvs_commit_marked" ); + (void)new KAction( i18n( "Status" ), 0, _catalogManager, + SLOT( cvsStatus( ) ), actionCollection( ), "cvs_status" ); + (void)new KAction( i18n( "Status for Marked" ), 0, _catalogManager, + SLOT( cvsStatusMarked( ) ), actionCollection( ), "cvs_status_marked" ); + (void)new KAction( i18n( "Show Diff" ), 0, _catalogManager, + SLOT( cvsDiff( ) ), actionCollection( ), "cvs_diff" ); + + // CVS + actionMap["cvs_update"] = NEEDS_PO | NEEDS_PO_CVS; + actionMap["cvs_update_marked"] = NEEDS_PO | NEEDS_PO_CVS | NEEDS_MARK; + actionMap["cvs_commit"] = NEEDS_PO | NEEDS_PO_CVS; + actionMap["cvs_commit_marked"] = NEEDS_PO | NEEDS_PO_CVS | NEEDS_MARK; + actionMap["cvs_status"] = NEEDS_PO | NEEDS_PO_CVS; + actionMap["cvs_status_marked"] = NEEDS_PO | NEEDS_PO_CVS | NEEDS_MARK; + actionMap["cvs_diff"] = NEEDS_PO | NEEDS_PO_CVS; + + // SVN submenu + // Actions for PO files + (void)new KAction( i18n( "Update" ), "down", 0, _catalogManager, + SLOT( svnUpdate( ) ), actionCollection( ), "svn_update" ); + (void)new KAction( i18n( "Update Marked" ), 0, _catalogManager, + SLOT( svnUpdateMarked( ) ), actionCollection( ), "svn_update_marked" ); + (void)new KAction( i18n( "Commit" ), "up", 0, _catalogManager, + SLOT( svnCommit( ) ), actionCollection( ), "svn_commit" ); + (void)new KAction( i18n( "Commit Marked" ), 0, _catalogManager, + SLOT( svnCommitMarked( ) ), actionCollection( ), "svn_commit_marked" ); + (void)new KAction( i18n( "Status (Local)" ), 0, _catalogManager, + SLOT( svnStatusLocal() ), actionCollection( ), "svn_status_local" ); + (void)new KAction( i18n( "Status (Local) for Marked" ), 0, _catalogManager, + SLOT( svnStatusLocalMarked() ), actionCollection( ), "svn_status_local_marked" ); + (void)new KAction( i18n( "Status (Remote)" ), 0, _catalogManager, + SLOT( svnStatusRemote() ), actionCollection( ), "svn_status_remote" ); + (void)new KAction( i18n( "Status (Remote) for Marked" ), 0, _catalogManager, + SLOT( svnStatusRemoteMarked() ), actionCollection( ), "svn_status_remote_marked" ); + (void)new KAction( i18n( "Show Diff" ), 0, _catalogManager, + SLOT( svnDiff( ) ), actionCollection( ), "svn_diff" ); + (void)new KAction( i18n( "Show Information" ), 0, _catalogManager, + SLOT( svnInfo() ), actionCollection( ), "svn_info" ); + (void)new KAction( i18n( "Show Information for Marked" ), 0, _catalogManager, + SLOT( svnInfoMarked() ), actionCollection( ), "svn_info_marked" ); + + // SVN + actionMap["svn_update"] = NEEDS_PO | NEEDS_PO_SVN; + actionMap["svn_update_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK; + actionMap["svn_commit"] = NEEDS_PO | NEEDS_PO_SVN; + actionMap["svn_commit_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK; + actionMap["svn_status_local"] = NEEDS_PO | NEEDS_PO_SVN; + actionMap["svn_status_local_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK; + actionMap["svn_status_remote"] = NEEDS_PO | NEEDS_PO_SVN; + actionMap["svn_status_remote_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK; + actionMap["svn_diff"] = NEEDS_PO | NEEDS_PO_SVN; + actionMap["svn_info"] = NEEDS_PO | NEEDS_PO_SVN; + actionMap["svn_info_marked"] = NEEDS_PO | NEEDS_PO_SVN | NEEDS_MARK; + + // CVS Actions for POT files + (void)new KAction( i18n( "Update Templates" ), 0, _catalogManager, + SLOT( cvsUpdateTemplate( ) ), actionCollection( ), "cvs_update_template" ); + (void)new KAction( i18n( "Update Marked Templates" ), 0, _catalogManager, + SLOT( cvsUpdateMarkedTemplate( ) ), actionCollection( ), "cvs_update_marked_template" ); + (void)new KAction( i18n( "Commit Templates" ), 0, _catalogManager, + SLOT( cvsCommitTemplate( ) ), actionCollection( ), "cvs_commit_template" ); + (void)new KAction( i18n( "Commit Marked Templates" ), 0, _catalogManager, + SLOT( cvsCommitMarkedTemplate( ) ), actionCollection( ), "cvs_commit_marked_template" ); + + actionMap["cvs_update_template"] = NEEDS_POT | NEEDS_POT_CVS; + actionMap["cvs_update_marked_template"] = NEEDS_POT | NEEDS_POT_CVS | NEEDS_MARK; + actionMap["cvs_commit_template"] = NEEDS_POT | NEEDS_POT_CVS; + actionMap["cvs_commit_marked_template"] = NEEDS_POT | NEEDS_POT_CVS | NEEDS_MARK; + + // SVN Actions for POT files + (void)new KAction( i18n( "Update Templates" ), 0, _catalogManager, + SLOT( svnUpdateTemplate( ) ), actionCollection( ), "svn_update_template" ); + (void)new KAction( i18n( "Update Marked Templates" ), 0, _catalogManager, + SLOT( svnUpdateMarkedTemplate( ) ), actionCollection( ), "svn_update_marked_template" ); + (void)new KAction( i18n( "Commit Templates" ), 0, _catalogManager, + SLOT( svnCommitTemplate( ) ), actionCollection( ), "svn_commit_template" ); + (void)new KAction( i18n( "Commit Marked Templates" ), 0, _catalogManager, + SLOT( svnCommitMarkedTemplate( ) ), actionCollection( ), "svn_commit_marked_template" ); + + actionMap["svn_update_template"] = NEEDS_POT | NEEDS_POT_SVN; + actionMap["svn_update_marked_template"] = NEEDS_POT | NEEDS_POT_SVN | NEEDS_MARK; + actionMap["svn_commit_template"] = NEEDS_POT | NEEDS_POT_SVN; + actionMap["svn_commit_marked_template"] = NEEDS_POT | NEEDS_POT_SVN | NEEDS_MARK; + + // settings menu + // FIXME: KStdAction::preferences(this, SLOT( optionsPreferences()), actionCollection()); + + createStandardStatusBarAction(); + + setStandardToolBarMenuEnabled ( true ); + + // commands menus + KActionMenu* actionMenu=new KActionMenu(i18n("Commands"), 0, + actionCollection(), "dir_commands"); + _catalogManager->setDirCommandsMenu( actionMenu->popupMenu()); + + actionMenu=new KActionMenu(i18n("Commands"), 0, + actionCollection(), "file_commands"); + _catalogManager->setFileCommandsMenu( actionMenu->popupMenu()); + + action = new KAction(i18n("&Delete"),Key_Delete,_catalogManager,SLOT(slotDeleteFile()),actionCollection(), "delete"); + action->setEnabled(false); + +#if KDE_IS_VERSION( 3, 2, 90 ) + setupGUI(); +#else + createGUI(); +#endif +} + +void CatalogManager::setupStatusBar() +{ + _foundLabel = new QLabel( " ", statusBar()); + statusBar()->addWidget(_foundLabel,0); + + QHBox* progressBox = new QHBox(statusBar(), "progressBox" ); + progressBox->setSpacing(2); + _statusProgressLabel = new QLabel( "", progressBox ); + _statusProgressBar = new KProgress( progressBox, "progressBar"); + _statusProgressBar->hide(); + + statusBar()->addWidget(progressBox,1); + statusBar()->setMinimumHeight(_statusProgressBar->sizeHint().height()); + + QWhatsThis::add(statusBar(), + i18n("<qt><p><b>Statusbar</b></p>\n" + "<p>The statusbar displays information about progress of" + " the current find or replace operation. The first number in <b>Found:</b>" + " displays the number of files with an occurrence of the searched text not" + " yet shown in the KBabel window. The second shows the total number of files" + " containing the searched text found so far.</p></qt>")); +} + +void CatalogManager::enableMenuForFiles(bool enable) +{ + stateChanged( "treeBuilt", enable ? StateNoReverse: StateReverse ); +} + +void CatalogManager::selectedChanged(uint actionValue) +{ + QMap<QString,uint>::Iterator it; + for (it = actionMap.begin( ); it != actionMap.end( ); ++it) { + KAction * action = actionCollection()->action(it.key( ).latin1( )); + if (action) action->setEnabled((actionValue & it.data( )) == it.data( )); + } +} + +CatManSettings CatalogManager::settings() const +{ + return _catalogManager->settings(); +} + +void CatalogManager::updateSettings() +{ + _settings = _project->catManSettings(); + _catalogManager->setSettings(_settings); + _openNewWindow=_settings.openWindow; +} + +void CatalogManager::saveSettings( QString configFile ) +{ + _settings = _catalogManager->settings(); // restore settings from the view + + _project->setSettings( _settings ); + + config = new KConfig(configFile); + + _catalogManager->saveView(config); + + config->sync(); +} + +void CatalogManager::restoreSettings() +{ + _settings = _project->catManSettings(); + _openNewWindow=_settings.openWindow; + _catalogManager->restoreView(_project->config()); +} + +void CatalogManager::setPreferredWindow(WId window) +{ + _preferredWindow = window; + kdDebug(KBABEL_CATMAN) << "setPrefereedWindow set to :" << _preferredWindow << endl; +} + +void CatalogManager::updateFile(QString fileWithPath) +{ + _catalogManager->updateFile(fileWithPath,true); //force update +} + +void CatalogManager::updateAfterSave(QString fileWithPath, PoInfo &info) +{ + _catalogManager->updateAfterSave(fileWithPath, info); +} + +CatalogManagerView *CatalogManager::view() +{ + return _catalogManager; +} + +void CatalogManager::openFile(QString filename, QString package) +{ + DCOPClient * client = kapp->dcopClient(); + + if( startKBabel() ) + { + + QByteArray data; + QCString url = filename.local8Bit(); + QDataStream arg(data, IO_WriteOnly); + arg << url; + arg << package.utf8(); + arg << CatalogManagerApp::_preferredWindow; + arg << ( _openNewWindow ? 1 : 0 ); + + kdDebug(KBABEL_CATMAN) << "Open file with project " << _configFile << endl; + + QCString callfunc="openURL(QCString, QCString, WId,int)"; + if(_configFile != "kbabelrc" ) + { + arg << _configFile.utf8(); + callfunc="openURL(QCString, QCString, WId,int,QCString)"; + } + + kdDebug(KBABEL_CATMAN) << callfunc << endl; + + // update the user timestamp for KBabel to get it a focus + kapp->updateRemoteUserTimestamp ("kbabel"); + + if( !client->send("kbabel","KBabelIFace", callfunc, data) ) + KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n" + "Please check your installation of KDE.")); + } +} + +void CatalogManager::openFile(QString filename, QString package, int msgid) +{ + DCOPClient * client = kapp->dcopClient(); + + if( startKBabel() ) + { + QByteArray data; + QCString url = filename.local8Bit(); + QDataStream arg(data, IO_WriteOnly); + arg << url; + arg << package.utf8(); + arg << msgid; + + kdDebug(KBABEL_CATMAN) << "Open file with project " << _configFile << endl; + + QCString callfunc="gotoFileEntry(QCString, QCString, int)"; + if(_configFile != "kbabelrc" ) + { + arg << _configFile.utf8(); + callfunc="gotoFileEntry(QCString, QCString,int,QCString)"; + } + + kdDebug(KBABEL_CATMAN) << callfunc << endl; + + // update the user timestamp for KBabel to get it a focus + kapp->updateRemoteUserTimestamp ("kbabel"); + + if( !client->send("kbabel","KBabelIFace", callfunc, data) ) + KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n" + "Please check your installation of KDE.")); + } +} + +void CatalogManager::openFileInNewWindow(QString filename, QString package) +{ + DCOPClient * client = kapp->dcopClient(); + + if( startKBabel() ) + { + + QByteArray data; + QCString url = filename.local8Bit(); + QDataStream arg(data, IO_WriteOnly); + arg << url; + arg << package.utf8(); + arg << CatalogManagerApp::_preferredWindow; + arg << ((int)1); + + QCString callfunc="openURL(QCString, QCString, WId,int)"; + if(_configFile != "kbabelrc" ) + { + arg << _configFile.utf8(); + callfunc="openURL(QCString, QCString, WId,int,QCString)"; + } + + // update the user timestamp for KBabel to get it a focus + kapp->updateRemoteUserTimestamp ("kbabel"); + + if( !client->send("kbabel","KBabelIFace", callfunc, data) ) + KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n" + "Please check your installation of KDE.")); + } +} + +void CatalogManager::openTemplate(QString openFilename,QString saveFilename,QString package) +{ + DCOPClient * client = kapp->dcopClient(); + + if( startKBabel() ) { + QByteArray data; + QCString url = openFilename.local8Bit(); + QDataStream arg(data, IO_WriteOnly); + arg << url; + url = saveFilename.utf8(); + arg << url; + arg << package.utf8(); + arg << (_openNewWindow ? 1 : 0 ); + + QCString callfunc="openTemplate(QCString,QCString,QCString,int)"; + if(_configFile != "kbabelrc" ) + { + arg << _configFile.utf8(); + callfunc="openTemplate(QCString,QCString,QCString,int,QCString)"; + } + + // update the user timestamp for KBabel to get it a focus + kapp->updateRemoteUserTimestamp ("kbabel"); + + if( !client->send("kbabel","KBabelIFace", callfunc, data) ) + KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n" + "Please check your installation of KDE.")); + } +} + +void CatalogManager::openTemplateInNewWindow(QString openFilename,QString saveFilename,QString package) +{ + DCOPClient * client = kapp->dcopClient(); + + if( startKBabel() ) { + QByteArray data; + QCString url = openFilename.local8Bit(); + QDataStream arg(data, IO_WriteOnly); + arg << url; + url = saveFilename.utf8(); + arg << url; + arg << package.utf8(); + arg << ((int)1); + + QCString callfunc="openTemplate(QCString,QCString,QCString,int)"; + if(_configFile != "kbabelrc" ) + { + arg << _configFile.utf8(); + callfunc="openTemplate(QCString,QCString,QCString,int,QCString)"; + } + + // update the user timestamp for KBabel to get it a focus + kapp->updateRemoteUserTimestamp ("kbabel"); + + if( !client->send("kbabel","KBabelIFace", callfunc, data) ) + KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n" + "Please check your installation of KDE.")); + } +} + +void CatalogManager::spellcheck() +{ + DCOPClient * client = kapp->dcopClient(); + + QStringList fileList = _catalogManager->current(); + + if( startKBabel() ) { + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << fileList; + + // update the user timestamp for KBabel to get it a focus + kapp->updateRemoteUserTimestamp ("kbabel"); + + if( !client->send("kbabel","KBabelIFace", "spellcheck(QStringList)", data) ) + KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n" + "Please check your installation of KDE.")); + } +} + +void CatalogManager::markedSpellcheck() +{ + DCOPClient * client = kapp->dcopClient(); + + QStringList fileList = _catalogManager->marked(); + + if( startKBabel() ) { + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << fileList; + + // update the user timestamp for KBabel to get it a focus + kapp->updateRemoteUserTimestamp ("kbabel"); + + if( !client->send("kbabel","KBabelIFace", "spellcheck(QStringList)", data) ) + KMessageBox::error(this, i18n("Cannot send a message to KBabel.\n" + "Please check your installation of KDE.")); + } +} + +bool CatalogManager::startKBabel() +{ + QCString service; + QString result; + + DCOPClient * client = kapp->dcopClient(); + + // find out, if there is a running kbabel + QCStringList apps = client->registeredApplications(); + for( QCStringList::Iterator it = apps.begin() ; it != apps.end() ; ++it ) + { + QString clientID = *it; + if( clientID=="kbabel" ) + { + service = *it; + break; + } + } + + // if there is no running kbabel, start one + if( service.isEmpty() ) + { + QString app = "kbabel"; + QString url = ""; + if( kapp->startServiceByDesktopName(app,url, &result, &service)) + { + KMessageBox::error( this, i18n("Unable to use KLauncher to start KBabel.\n" + "You should check the installation of KDE.\n" + "Please start KBabel manually.")); + return false; + } else sleep(1); + } + + return true; +} + + +void CatalogManager::prepareProgressBar(QString msg, int max) +{ + _progressBar->setTotalSteps(max); + _progressBar->setProgress(0); + _progressLabel->setText(msg); + + _progressBar->show(); + _progressLabel->show(); +} + +void CatalogManager::clearProgressBar() +{ + _progressBar->setProgress(0); + + _progressBar->hide(); + _progressLabel->hide(); +} + +void CatalogManager::prepareStatusProgressBar(QString msg, int max) +{ + _totalFound = 0; + _foundToBeSent = 0; + _statusProgressBar->setTotalSteps(max); + _statusProgressLabel->setText(msg); + _foundLabel->setText( i18n("Found: 0/0") ); + + _statusProgressBar->show(); + _statusProgressLabel->show(); +} + +void CatalogManager::prepareStatusProgressBar(int max) +{ + _statusProgressBar->setTotalSteps(max); +} + +void CatalogManager::clearStatusProgressBar() +{ + _statusProgressBar->setValue(0); + + _statusProgressBar->hide(); + _statusProgressLabel->hide(); + _foundLabel->setText(" "); +} + +void CatalogManager::setNumberOfFound(int toBeSent, int total) +{ + _foundLabel->setText(i18n("Found: %1/%2").arg(toBeSent).arg(total)); +} + +void CatalogManager::decreaseNumberOfFound() +{ + if( _foundToBeSent > 0 ) { + _foundToBeSent--; + setNumberOfFound( _foundToBeSent, _totalFound ); + } +} + +void CatalogManager::slotHelp() +{ + kapp->invokeHelp("CATALOGMANAGER","kbabel"); +} + +void CatalogManager::find() +{ + if( !_findDialog ) _findDialog = new FindInFilesDialog(false,this); + + if( _findDialog->exec("") == QDialog::Accepted ) + { + _timerFind->stop(); + _searchStopped = false; + _catalogManager->stop(false); // surely we are not in process of quitting, since there is no window and user cannot invoke Find + prepareStatusProgressBar(i18n("Searching"),1); // just show the progress bar + + // enable stop action to stop searching + KAction *action = (KAction*)actionCollection()->action("stop_search"); + action->setEnabled(true); + + _findOptions = _findDialog->findOpts(); + + // get from options the information for ignoring text parts + _findOptions.contextInfo = QRegExp( _project->miscSettings().contextInfo ); + _findOptions.accelMarker = _project->miscSettings().accelMarker; + + _foundFilesList.clear(); + kdDebug(KBABEL_CATMAN) << "Calling catalogmanagerview::find" << endl; + QString url = _catalogManager->find(_findOptions, _toBeSearched ); + + if( _catalogManager->isStopped() ) return; + if( !url.isEmpty() ) + { + if( startKBabel() ) + { + QCString funcCall("findInFile(QCString,QCString,QString,int,int,int,int,int,int,int,int,int,int)"); + DCOPClient *client = kapp->dcopClient(); + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + arg << client->appId(); + arg << url.utf8(); + arg << _findOptions.findStr; + arg << (_findOptions.caseSensitive ? 1 : 0); + arg << (_findOptions.wholeWords ? 1 : 0); + arg << (_findOptions.isRegExp ? 1 : 0); + arg << (_findOptions.inMsgid ? 1 : 0); + arg << (_findOptions.inMsgstr ? 1 : 0); + arg << (_findOptions.inComment ? 1 : 0); + arg << (_findOptions.ignoreAccelMarker ? 1 : 0); + arg << (_findOptions.ignoreContextInfo ? 1 : 0); + arg << (_findOptions.askForNextFile ? 1 : 0); + arg << (_findOptions.askForSave ? 1 : 0); + if(_configFile != "kbabelrc" ) { + arg << _configFile.utf8(); + funcCall="findInFile(QCString,QCString,QString,int,int,int,int,int,int,int,int,int,int,QCString)"; + } + kdDebug(KBABEL) << "DCOP: " << QString(data.data()) << endl; + if( !client->send("kbabel","KBabelIFace", + funcCall, data) + ) { + KMessageBox::error( this, i18n("DCOP communication with KBabel failed."), i18n("DCOP Communication Error")); + stopSearching(); + return; + } + + if( !_toBeSearched.isEmpty() ) + { + _totalFound = 1; + _foundToBeSent = 0; + setNumberOfFound( 0, 1 ); // one found, but already sent + _timerFind->start(100,true); + } else stopSearching(); + } + else + { + KMessageBox::error( this, i18n("KBabel cannot be started."), i18n("Cannot Start KBabel")); + stopSearching(); + } + + } + else + { + if( !_searchStopped) KMessageBox::information(this, i18n("Search string not found!")); + stopSearching(); + } + } +} + +void CatalogManager::replace() +{ + if( !_replaceDialog ) _replaceDialog = new FindInFilesDialog(true,this); + + + if( _replaceDialog->exec("") == QDialog::Accepted ) + { + _timerFind->stop(); + _searchStopped = false; + _catalogManager->stop(false); // surely we are not in process of quitting, since there is no window and user cannot invoke Find + prepareStatusProgressBar(i18n("Searching"),1); // just show the progress bar + + // enable stop action to stop searching + KAction *action = (KAction*)actionCollection()->action("stop_search"); + action->setEnabled(true); + + ReplaceOptions options = _replaceDialog->replaceOpts(); + + _findOptions = options; + + // get from options the information for ignoring text parts + options.contextInfo = QRegExp( _project->miscSettings().contextInfo ); + options.accelMarker = _project->miscSettings().accelMarker; + + _foundFilesList.clear(); + QString url = _catalogManager->find(options, _toBeSearched ); + + if( _catalogManager->isStopped() ) return; + if( !url.isEmpty() ) + { + if( startKBabel() ) + { + QCString funcCall("replaceInFile(QCString,QCString,QString,QString,int,int,int,int,int,int,int,int,int,int,int)"); + DCOPClient *client = kapp->dcopClient(); + QByteArray data; + QDataStream arg(data, IO_WriteOnly); + + arg << client->appId(); + arg << url.utf8(); + arg << options.findStr; + arg << options.replaceStr; + arg << (options.caseSensitive ? 1 : 0); + arg << (options.wholeWords ? 1 : 0); + arg << (options.isRegExp ? 1 : 0); + arg << (options.inMsgid ? 1 : 0); + arg << (options.inMsgstr ? 1 : 0); + arg << (options.inComment ? 1 : 0); + arg << (options.ignoreAccelMarker ? 1 : 0); + arg << (options.ignoreContextInfo ? 1 : 0); + arg << (options.ask ? 1 : 0); + arg << (options.askForNextFile ? 1 : 0); + arg << (options.askForSave ? 1 : 0); + if(_configFile != "kbabelrc" ) { + arg << _configFile.utf8(); + funcCall="replaceInFile(QCString,QCString,QString,QString,int,int,int,int,int,int,int,int,int,int,int,QCString)"; + } + if( !client->send("kbabel","KBabelIFace", + funcCall, data) + ) { + KMessageBox::error( this, i18n("DCOP communication with KBabel failed."), i18n("DCOP Communication Error")); + stopSearching(); + return; + } + + if( !_toBeSearched.isEmpty() ) + { + _totalFound = 1; + setNumberOfFound( 0, 1 ); + _timerFind->start(100,true); + } else stopSearching(); + } + else + { + KMessageBox::error( this, i18n("KBabel cannot be started."), i18n("Cannot Start KBabel")); + stopSearching(); // update window + } + + } + else + { + if( !_searchStopped ) KMessageBox::information(this, i18n("Search string not found!")); + stopSearching(); // update window + } + } +} + +void CatalogManager::findNextFile() +{ + _timerFind->stop(); // stop the timer for lookup time + if(_toBeSearched.empty() ) + { + stopSearching(); + return; + } + QString file = _toBeSearched.first(); + _toBeSearched.pop_front(); + if( PoInfo::findInFile( file, _findOptions ) ) + { + _foundFilesList.append(file); + _totalFound++; + _foundToBeSent++; + setNumberOfFound(_foundToBeSent,_totalFound); + } + _statusProgressBar->advance(1); + if( !_toBeSearched.empty() ) + _timerFind->start(100,true); // if there is more files to be searched, start the timer again + else + stopSearching(); +} + +void CatalogManager::stopSearching() +{ + _searchStopped = true; + emit searchStopped(); + // clear the list of files to be searched + _toBeSearched.clear(); + + // fake that we are over (fake, because findNextFile can still be running for the last file + clearStatusProgressBar(); // clear the status bar, we are finished + // disable stop action as well + KAction *action = (KAction*)actionCollection()->action("stop_search"); + action->setEnabled(false); +} + +void CatalogManager::optionsPreferences() +{ + if(!_prefDialog) + { + _prefDialog = new KBabel::ProjectDialog(_project); + } + + _prefDialog->exec(); +} + +void CatalogManager::newToolbarConfig() +{ + createGUI(); + restoreView(); +} + +void CatalogManager::optionsShowStatusbar(bool on) +{ + if( on ) + statusBar()->show(); + else + statusBar()->hide(); +} + +bool CatalogManager::queryClose() +{ + _catalogManager->stop(); + saveView(); + saveSettings(_configFile); + return true; +} + +void CatalogManager::saveView() +{ + saveMainWindowSettings( KGlobal::config(), "View"); +} + + +void CatalogManager::restoreView() +{ + applyMainWindowSettings( KGlobal::config(), "View"); + + KToggleAction * toggle = (KToggleAction*)actionCollection()-> + action(KStdAction::stdName(KStdAction::ShowStatusbar)); + toggle->setChecked(!statusBar()->isHidden() ); +} + + +void CatalogManager::projectNew() +{ + KBabel::Project::Ptr p = KBabel::ProjectWizard::newProject(); + if( p ) + { + disconnect( _project, SIGNAL (signalCatManSettingsChanged()) + , this, SLOT (updateSettings())); + _project = p; + connect( _project, SIGNAL (signalCatManSettingsChanged()) + , this, SLOT (updateSettings())); + + _configFile = _project->filename(); + restoreSettings(); + updateSettings(); + changeProjectActions(p->filename()); + emit settingsChanged(_settings); + } +} + +void CatalogManager::projectOpen() +{ + QString oldproject = _project->filename(); + if( oldproject == KBabel::ProjectManager::defaultProjectName() ) + { + oldproject = QString(); + } + const QString file = KFileDialog::getOpenFileName(oldproject, QString::null, this); + if (file.isEmpty()) + { + return; + } + KBabel::Project::Ptr p = KBabel::ProjectManager::open(file); + if( p ) + { + disconnect( _project, SIGNAL (signalCatManSettingsChanged()) + , this, SLOT (updateSettings())); + _project = p; + connect( _project, SIGNAL (signalCatManSettingsChanged()) + , this, SLOT (updateSettings())); + + _configFile = p->filename(); + restoreSettings(); + updateSettings(); + changeProjectActions(file); + emit settingsChanged(_settings); + + } + else + { + KMessageBox::error (this, i18n("Cannot open project file %1").arg(file)); + } +} + +void CatalogManager::projectClose() +{ + disconnect( _project, SIGNAL (signalCatManSettingsChanged()) + , this, SLOT (updateSettings())); + _project = KBabel::ProjectManager::open(KBabel::ProjectManager::defaultProjectName()); + connect( _project, SIGNAL (signalCatManSettingsChanged()) + , this, SLOT (updateSettings())); + _configFile = _project->filename(); + restoreSettings(); + updateSettings(); + changeProjectActions(KBabel::ProjectManager::defaultProjectName()); + emit settingsChanged(_settings); +} + +void CatalogManager::changeProjectActions(const QString& project) +{ + bool def = ( project == KBabel::ProjectManager::defaultProjectName() ) ; + + KAction* saveAction=(KAction*)actionCollection()->action( "project_close" ); + saveAction->setEnabled( ! def ); +} + +void CatalogManager::projectConfigure() +{ + KBabel::ProjectDialog* _projectDialog = new ProjectDialog(_project); + + connect (_projectDialog, SIGNAL (settingsChanged()) + , this, SLOT (updateSettings())); + + // settings are updated via signals + _projectDialog->exec(); + + delete _projectDialog; +} + +void CatalogManager::enableActions() +{ + enableActions(true); +} + +void CatalogManager::disableActions() +{ + enableActions(false); +} + +void CatalogManager::enableActions(bool enable) +{ + KAction* action; + // the file menu + + action = (KAction*)actionCollection()->action( "open" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "open_new_window" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "find_in_files" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "replace_in_files" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "reload" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "toggle_marking" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "toggle_all_marking" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "mark_modified_files" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "load_marking" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "save_marking" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_next_untrans" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_prev_untrans" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_next_fuzzy" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_prev_fuzzy" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_next_fuzzyUntr" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_prev_fuzzyUntr" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_next_error" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_prev_error" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_next_template" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_prev_template" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_next_po" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_prev_po" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_next_marked" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "go_prev_marked" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "statistics" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "package_file" ); + action->setEnabled(enable); + + action = (KAction*)actionCollection()->action( "rough_translation" ); + action->setEnabled(enable); +} + +#include "catalogmanager.moc" diff --git a/kbabel/catalogmanager/catalogmanager.desktop b/kbabel/catalogmanager/catalogmanager.desktop new file mode 100644 index 00000000..3c470b1c --- /dev/null +++ b/kbabel/catalogmanager/catalogmanager.desktop @@ -0,0 +1,98 @@ +[Desktop Entry] +Name=KBabel Catalog Manager +Name[bg]=Управление на каталога - KBabel +Name[br]=Merour katalogoù KBabel +Name[ca]=Gestor de catàlegs de KBabel +Name[cs]=Správce katalogů +Name[da]=KBabel kataloghåndtering +Name[de]=KBabel-Katalogmanager +Name[el]=Διαχειριστής καταλόγων του KBabel +Name[en_GB]=KBabel Catalogue Manager +Name[eo]=Babelo-katalogadministrilo +Name[es]=Administrador de catálogos de KBabel +Name[et]=Kataloogihaldur +Name[eu]=KBabel katalogo kudeatzailea +Name[fa]= مدیر فهرست KBabel +Name[fi]=KBabel - käännöspakettien hallinta +Name[fr]=Gestionnaire de catalogues de KBabel +Name[ga]=KBabel - Bainisteoir na gCatalóg +Name[gl]=Xestor de Catálogos de KBabel +Name[he]=KBabel - מנהל הקטלוגים +Name[hu]=KBabel listakezelő +Name[is]=KBabel Þýðingarstjóri +Name[it]=Gestore dei cataloghi di KBabel +Name[ja]=KBabel カタログマネージャ +Name[ka]=KBabel-ის კატალოგის მმართველი +Name[kk]=KBabel каталог менеджері +Name[lt]=KBabel katalogo tvarkytuvė +Name[nb]=KBabel-katalogbehandler +Name[nds]=KBabel-Kataloogpleger +Name[ne]=केब्याबल विवरणिका प्रबन्धक +Name[nl]=KBabel catalogusbeheer +Name[nn]=KBabel Kataloghandsamar +Name[pa]=KBabel ਸੂਚੀ ਪ੍ਰਬੰਧਕ +Name[pl]=KBabel - Menedżer tłumaczeń +Name[pt]=Gestor de Catálogos do KBabel +Name[pt_BR]=Gerenciador de Catálogos do KBabel +Name[ru]=Менеджер сообщений Gettext +Name[sk]=KBabel - správca katalógov +Name[sl]=Upravitelj katalogov KBabel +Name[sr]=KBabel-ов Менаџер каталога +Name[sr@Latn]=KBabel-ov Menadžer kataloga +Name[sv]=Kbabel kataloghanterare +Name[tr]=KBabel Katalog Yöneticisi +Name[uk]=Менеджер каталогів KBabel +Name[zh_CN]=KBabel 目录管理器 +Name[zh_TW]=KBabel - 目錄管理員 +GenericName=Translation Tool Catalog Manager +GenericName[bg]=Инструмент за превод +GenericName[ca]=Gestor de catàlegs de l'eina de traducció +GenericName[cs]=Správce katalogů překladů +GenericName[da]=Oversættelsesværktøjs kataloghåndtering +GenericName[de]=Katalogmanager für Übersetzungsprogramm +GenericName[el]=Διαχειριστής καταλόγων εργαλείου μετάφρασης +GenericName[en_GB]=Translation Tool Catalogue Manager +GenericName[eo]=Katalogadministrilo por Tradukiloj +GenericName[es]=Administrador de catálogos de la herramienta de traducción +GenericName[et]=KBabel'i kataloogihaldur +GenericName[eu]=Itzulpen tresnen katalogo kudeatzailea +GenericName[fa]=مدیر فهرست ابزار ترجمه +GenericName[fi]=Käännöstyökalun käännöspakettien hallinta +GenericName[fr]=Gestionnaire de catalogues de traduction +GenericName[ga]=Uirlis Aistriúcháin - Bainisteoir na gCatalóg +GenericName[gl]=Xestor de Catálogos de Tradución +GenericName[he]=מנהל הקטלוגים של כלי התרגום +GenericName[hu]=Fordítássegítő +GenericName[is]=Þýðingarforrit - Þýðingarstjóri +GenericName[it]=Gestore dei cataloghi di uno strumento di traduzione +GenericName[ja]=翻訳ツール カタログマネージャ +GenericName[ka]=კატალოგის მმართველის სათარგმნი ხელსაწყო +GenericName[kk]=Аудару құралының Каталог менеджері +GenericName[lt]=Vertimo įrankio katalogo tvarkytuvė +GenericName[nb]=Verktøy for håndtering av oversettelseskataloger +GenericName[nds]=Översettenwarktüüch-Kataloogpleger +GenericName[ne]=अनुबाद उपकरण विवरणिका प्रबन्धक +GenericName[nl]=Vertaalhulpmiddel catalogusbeheer +GenericName[nn]=Verktøy for handtering av omsetjingskatalogar +GenericName[pa]=ਅਨੁਵਾਦ ਸੰਦ ਲਈ ਸੂਚੀ ਪ੍ਰਬੰਧਕ +GenericName[pl]=Menedżer tłumaczeń +GenericName[pt]=Gestor de Catálogos de Ferramenta de Tradução +GenericName[pt_BR]=Gerenciador de Catálogo da Ferramenta de Tradução +GenericName[ru]=Локализация приложений +GenericName[sk]=Správca katalógov pre prekladací nástroj +GenericName[sl]=Upravitelj katalogov orodja za prevajanje +GenericName[sr]=Менаџер каталога преводилачких алата +GenericName[sr@Latn]=Menadžer kataloga prevodilačkih alata +GenericName[sv]=Översättningsverktyg kataloghanterare +GenericName[tr]=Çeviri Aracı Katalog Yöneticisi +GenericName[uk]=Менеджер каталогів засобу для перекладів +GenericName[zh_CN]=翻译工具目录管理器 +GenericName[zh_TW]=翻譯工具目錄管理員 +Exec=catalogmanager %i %m -caption "%c" %U +Icon=catalogmanager +Type=Application +DocPath=kbabel/index.html +Terminal=false +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Development;Translation; diff --git a/kbabel/catalogmanager/catalogmanager.h b/kbabel/catalogmanager/catalogmanager.h new file mode 100644 index 00000000..67f871fa --- /dev/null +++ b/kbabel/catalogmanager/catalogmanager.h @@ -0,0 +1,218 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2004 by Stanislav Visnovsky <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef CATALOGMANAGER_H +#define CATALOGMANAGER_H + +#include <qdict.h> +#include <qlistview.h> +#include <qdatetime.h> +#include <qfileinfo.h> +#include <qguardedptr.h> +#include <qmap.h> + +#include <kdeversion.h> +#include <kmainwindow.h> +#include <kdirwatch.h> +#include <kprocess.h> +#include <qptrlist.h> + +#include "projectsettings.h" +#include "kbproject.h" +#include "catalog.h" +#include "catalogmanagerview.h" + +class CatManListItem; +class QPixmap; +class QPopupMenu; +class QTimer; +class KProgress; +class KAction; +class KConfig; +class FindInFilesDialog; + +namespace KBabel +{ + class PoInfo; + class ProjectDialog; +} + +class CatalogManager : public KMainWindow +{ + Q_OBJECT +public: + CatalogManager(QString configfile = QString() ); + ~CatalogManager(); + + KBabel::CatManSettings settings() const; + /** + * Sets the window, in which the files should be opened. + * This is set by KBabel::openCatalogManager + */ + void setPreferredWindow(WId id); + + /** updates the file fileWithPath in the @ref CatalogManagerView */ + void updateFile(QString fileWithPath); + void updateAfterSave(QString fileWithPath, KBabel::PoInfo &info); + + CatalogManagerView *view(); + + void pause(bool flag) { if( _catalogManager ) _catalogManager->pause (flag); } + + static QStringList _foundFilesList; + static QStringList _toBeSearched; + +public slots: + /** updates the settings from the project */ + void updateSettings(); + void enableMenuForFiles(bool enable); + void selectedChanged(uint actionValue); + virtual void slotHelp(); + + virtual void find(); + virtual void replace(); + virtual void stopSearching(); + virtual void optionsPreferences(); + virtual void optionsShowStatusbar(bool on); + virtual void dummySlot() {} + + void projectNew(); + void projectOpen(); + void projectClose(); + void projectConfigure(); + void changeProjectActions(const QString& project); + + virtual void clearProgressBar(); + virtual void prepareProgressBar(QString msg, int max); + + virtual void clearStatusProgressBar(); + virtual void prepareStatusProgressBar(QString msg, int max); + virtual void prepareStatusProgressBar(int max); + + virtual void setNumberOfFound( int toBeSent, int total ); + virtual void decreaseNumberOfFound(); + +protected slots: + virtual void findNextFile(); + virtual bool queryClose(); + +signals: + void settingsChanged(KBabel::CatManSettings); + void signalQuit(); + void searchStopped(); + +private: + void init(); + + void restoreView(); + void saveView(); + + void saveSettings( QString configFile = QString::null ); + + void setupActions(); + void setupStatusBar(); + + bool startKBabel(); + +private slots: + /** + * calls @ref KBabel::open where as preferred windos _preferredWindow + * is used. If this is deleted meanwhile, the first window in + * @ref KMainWindow::memberList is used. + */ + void openFile(QString filename,QString package); + void openFile(QString filename,QString package, int msgid); + void openFileInNewWindow(QString filename,QString package); + /** + * calls @ref KBabel::openTemplate where as preferred windos _preferredWindow + * is used. If this is deleted meanwhile, the first window in + * @ref KMainWindow::memberList is used. + */ + void openTemplate(QString openFilename,QString saveFileName,QString package); + void openTemplateInNewWindow(QString openFilename,QString saveFileName,QString package); + + void markedSpellcheck(); + void spellcheck(); + + void newToolbarConfig(); + + /** updates views and _settings variable */ + void restoreSettings(); + + void enableActions(); + void disableActions(); + + void enableActions(bool enable); + +private: + CatalogManagerView* _catalogManager; + + WId _preferredWindow; + + bool _openNewWindow; + + FindInFilesDialog* _findDialog; + FindInFilesDialog* _replaceDialog; + KBabel::ProjectDialog* _prefDialog; + + /// update progress bar + KProgress* _progressBar; + QLabel* _progressLabel; + + /// statusbar progress bar + KProgress* _statusProgressBar; + QLabel* _statusProgressLabel; + QLabel* _foundLabel; + int _foundToBeSent; + int _totalFound; + + QTimer* _timerFind; + bool _searchStopped; + + KBabel::CatManSettings _settings; + KBabel::MiscSettings _miscSettings; + + /// options used in findNextFile + KBabel::FindOptions _findOptions; + + + /// project configuration file + QString _configFile; + KBabel::Project::Ptr _project; + + KConfig* config; + + QMap<QString,uint> actionMap; +}; + +#endif // CATALOGMANAGER_H diff --git a/kbabel/catalogmanager/catalogmanagerapp.h b/kbabel/catalogmanager/catalogmanagerapp.h new file mode 100644 index 00000000..e0762e5b --- /dev/null +++ b/kbabel/catalogmanager/catalogmanagerapp.h @@ -0,0 +1,73 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2001 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef CATALOGMANAGERAPP_H +#define CATALOGMANAGERAPP_H + +#include "catalogmanager.h" +#include "catalogmanageriface.h" + +#include "version.h" + +#include <kapplication.h> +#include <kwin.h> + +class CatalogManagerInterface : public CatalogManagerIface +{ +public: + CatalogManagerInterface(); + + virtual void setPreferredWindow( WId id ); + virtual QCString findNextFile(); + virtual void updatedFile( QCString url ); +}; + +class CatalogManagerApp : public KApplication +{ +public: + CatalogManagerApp(); + virtual ~CatalogManagerApp(); + + virtual int newInstance(); + + static void setPreferredWindow( WId id ); + static QCString findNextFile(); + static void updatedFile( QCString url ); + static WId _preferredWindow; +private: + CatalogManagerInterface *kbInterface; + static CatalogManager * _view; +}; + +#endif diff --git a/kbabel/catalogmanager/catalogmanageriface.h b/kbabel/catalogmanager/catalogmanageriface.h new file mode 100644 index 00000000..232a694c --- /dev/null +++ b/kbabel/catalogmanager/catalogmanageriface.h @@ -0,0 +1,67 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2001 by Stanislav Visnovsky <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef CATALOGMANAGERIFACE_H +#define CATALOGMANAGERIFACE_H + +#include <dcopobject.h> + +class CatalogManagerIface : virtual public DCOPObject +{ + K_DCOP +public: + +k_dcop: + + /** + * Sets the WId of the preferred window. The window will get + * calls to open files or templates when requested in catalog manager. + * @param id is the WId of the window to be used + */ + virtual void setPreferredWindow( WId id ) { id = 0; } + + /** + * Returns a next file containing the searched string. Invoked from + * KBabel in case the FindNext() finishes a file and wants to continue in + * the next one. + * @returns a URL to the next file, QString:null if there is no more + * files to be searched or empty string if the search string + * is not found yet, but there is more files to be searched in. + */ + virtual QCString findNextFile() = 0; + + /** + * If you care about this file, you should update information shown. + */ + virtual void updatedFile( QCString url) = 0; +}; + +#endif // CATALOGMANAGERIFACE_H diff --git a/kbabel/catalogmanager/catalogmanagerui.rc b/kbabel/catalogmanager/catalogmanagerui.rc new file mode 100644 index 00000000..498a4bc7 --- /dev/null +++ b/kbabel/catalogmanager/catalogmanagerui.rc @@ -0,0 +1,262 @@ +<!DOCTYPE kpartgui> +<kpartgui name="catalogmanager" version="26"> + <MenuBar> + <Menu name="edit"><text>&Edit</text> + <Action name="find_in_files"/> + <Action name="replace_in_files"/> + <Action name="stop_search"/> + <Separator/> + <Action name="reload"/> + </Menu> + <Menu name="go"><text>&Go</text> + <Action name="go_next_fuzzyUntr"/> + <Action name="go_prev_fuzzyUntr"/> + <Action name="go_next_fuzzy"/> + <Action name="go_prev_fuzzy"/> + <Action name="go_next_untrans"/> + <Action name="go_prev_untrans"/> + <Separator/> + <Action name="go_next_error"/> + <Action name="go_prev_error"/> + <Separator/> + <Action name="go_next_marked"/> + <Action name="go_prev_marked"/> + <Separator/> + <Action name="go_next_template"/> + <Action name="go_prev_template"/> + <Action name="go_next_po"/> + <Action name="go_prev_po"/> + </Menu> + <Menu name="markings"><text>&Markings</text> + <Action name="toggle_marking"/> + <Action name="remove_marking"/> + <Action name="toggle_all_marking"/> + <Action name="remove_all_marking"/> + <Action name="mark_modified_files"/> + <Separator/> + <Action name="mark_pattern"/> + <Action name="unmark_pattern"/> + <Separator/> + <Action name="load_marking"/> + <Action name="save_marking"/> + </Menu> + <Menu name="projects"><text>&Project</text> + <Action name="project_new"/> + <Action name="project_open"/> + <Action name="project_close"/> + <Action name="project_settings"/> + </Menu> + <Menu name="tools"><text>&Tools</text> + <Action name="statistics"/> + <Action name="statistics_marked"/> + <Action name="syntax"/> + <Separator/> + <Action name="spellcheck"/> + <Action name="spellcheck_marked"/> + <Separator/> + <Action name="rough_translation"/> + <Action name="rough_translation_marked"/> + <Separator/> + <Menu name="cvs_menu"><text>CVS</text> + <Action name="cvs_update"/> + <Action name="cvs_update_marked"/> + <Separator/> + <Action name="cvs_commit"/> + <Action name="cvs_commit_marked"/> + <Separator/> + <Action name="cvs_status"/> + <Action name="cvs_status_marked"/> + <Separator/> + <Action name="cvs_update_template"/> + <Action name="cvs_update_marked_template"/> + <Separator/> + <Action name="cvs_commit_template"/> + <Action name="cvs_commit_marked_template"/> + <Separator/> + <Action name="cvs_diff"/> + </Menu> + <Menu name="svn_menu"><text>SVN</text> + <Action name="svn_update"/> + <Action name="svn_update_marked"/> + <Separator/> + <Action name="svn_commit"/> + <Action name="svn_commit_marked"/> + <Separator/> + <Action name="svn_status_local"/> + <Action name="svn_status_local_marked"/> + <Separator/> + <Action name="svn_status_remote"/> + <Action name="svn_status_remote_marked"/> + <Separator/> + <Action name="svn_update_template"/> + <Action name="svn_update_marked_template"/> + <Separator/> + <Action name="svn_commit_template"/> + <Action name="svn_commit_marked_template"/> + <Separator/> + <Action name="svn_diff"/> + <Separator/> + <Action name="svn_info"/> + <Action name="svn_info_marked"/> + </Menu> + <Separator/> + <Action name="mail_file"/> + <Action name="mail_file_marked"/> + <Separaator/> + <Action name="package_file"/> + <Action name="package_file_marked"/> + <Separator/> + <Action name="dynamic_validation"/> + <Action name="dynamic_validation_marked"/> + </Menu> + <Menu name="settings"><text>&Settings</text> + <Action name="settings_show_navbar" append="show_merge"/> + <Action name="settings_show_comments" append="show_merge"/> + <Action name="settings_show_tools" append="show_merge"/> + </Menu> + <Menu name="help"><text>&Help</text> + <Action name="help_gettext"/> + <Action name="dict_about" append="about_merge"/> + </Menu> + </MenuBar> + <ToolBar name="mainToolBar"><text>Main</text> + <Action name="reload"/> + <Action name="statistics"/> + <Action name="syntax"/> + <Action name="stop_search"/> + </ToolBar> + <ToolBar name="navigationbar"><text>Navigationbar</text> + <Action name="go_prev_entry"/> + <Action name="go_next_entry"/> + <Separator/> + <Action name="go_first"/> + <Action name="go_last"/> + <Action name="go_prev_fuzzyUntr"/> + <Action name="go_next_fuzzyUntr"/> + <Action name="go_prev_fuzzy"/> + <Action name="go_next_fuzzy"/> + <Action name="go_prev_untrans"/> + <Action name="go_next_untrans"/> + <Separator/> + <Action name="go_prev_error"/> + <Action name="go_next_error"/> + <Separator/> + <Action name="go_prev_marked"/> + <Action name="go_next_marked"/> + <Separator/> + <Action name="go_prev_template"/> + <Action name="go_next_template"/> + <Action name="go_prev_po"/> + <Action name="go_next_po"/> + </ToolBar> + <Menu name="rmb_file"> + <Action name="open"/> + <Action name="open_new_window"/> + <Action name="open_template"/> + <Action name="toggle_marking"/> + <Separator/> + <Action name="reload"/> + <Separator/> + <Action name="syntax"/> + <Action name="statistics"/> + <Action name="dynamic_validation"/> + <Action name="file_commands"/> + <Separator/> + <Menu name="rmb_file_cvs"><text>CVS</text> + <Action name="cvs_update"/> + <Action name="cvs_commit"/> + <Action name="cvs_status"/> + <Separator/> + <Action name="cvs_update_template"/> + <Action name="cvs_commit_template"/> + <Separator/> + <Action name="cvs_diff"/> + </Menu> + <Menu name="rmb_file_svn"><text>SVN</text> + <Action name="svn_update"/> + <Action name="svn_commit"/> + <Action name="svn_status_local"/> + <Action name="svn_status_remote"/> + <Separator/> + <Action name="svn_update_template"/> + <Action name="svn_commit_template"/> + <Separator/> + <Action name="svn_diff"/> + </Menu> + <Separator/> + <Action name="delete"/> + </Menu> + <Menu name="rmb_dir"> + <Action name="toggle_marking"/> + <Action name="remove_marking"/> + <Action name="toggle_all_marking"/> + <Action name="remove_all_marking"/> + <Separator/> + <Action name="reload"/> + <Separator/> + <Action name="syntax"/> + <Action name="statistics"/> + <Action name="dynamic_validation"/> + <Action name="dir_commands"/> + <Separator/> + <Menu name="rmb_dir_cvs"><text>CVS</text> + <Action name="cvs_update"/> + <Action name="cvs_commit"/> + <Action name="cvs_status"/> + <Separator/> + <Action name="cvs_update_template"/> + <Action name="cvs_commit_template"/> + <Separator/> + <Action name="cvs_diff"/> + </Menu> + <Menu name="rmb_dir_svn"><text>SVN</text> + <Action name="svn_update"/> + <Action name="svn_commit"/> + <Action name="svn_status_local"/> + <Action name="svn_status_remote"/> + <Separator/> + <Action name="svn_update_template"/> + <Action name="svn_commit_template"/> + <Separator/> + <Action name="svn_diff"/> + </Menu> + </Menu> + +<State name="treeBuilt"> + <Enable> + <Action name="open"/> + <Action name="open_new_window"/> + <Action name="find_in_files"/> + <Action name="replace_in_files"/> + <Action name="reload"/> + + <Action name="go_next_fuzzyUntr"/> + <Action name="go_prev_fuzzyUntr"/> + <Action name="go_next_fuzzy"/> + <Action name="go_prev_fuzzy"/> + <Action name="go_next_untrans"/> + <Action name="go_prev_untrans"/> + <Action name="go_next_error"/> + <Action name="go_prev_error"/> + <Action name="go_next_marked"/> + <Action name="go_prev_marked"/> + <Action name="go_next_template"/> + <Action name="go_prev_template"/> + <Action name="go_next_po"/> + <Action name="go_prev_po"/> + <Action name="load_marking"/> + <Action name="save_marking"/> + <Action name="toggle_marking"/> + <Action name="toggle_all_marking"/> + <Action name="statistics"/> + <Action name="rough_translation"/> + <Action name="reload"/> + <Action name="dynamic_validation"/> + <Action name="dynamic_validation_marked"/> + <Action name="mail_file"/> + <Action name="mark_pattern"/> + <Action name="unmark_pattern"/> + </Enable> +</State> + +</kpartgui> diff --git a/kbabel/catalogmanager/catalogmanagerview.cpp b/kbabel/catalogmanager/catalogmanagerview.cpp new file mode 100644 index 00000000..6bb4c88f --- /dev/null +++ b/kbabel/catalogmanager/catalogmanagerview.cpp @@ -0,0 +1,3132 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2004 by Stanislav Visnovsky + <visnovsky@kde.org> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + +#include "catmanresource.h" +#include "catalogmanager.h" +#include "catmanlistitem.h" +#include "catalog.h" +#include "kbabeldictbox.h" + +#include "resources.h" +#include "multiroughtransdlg.h" +#include "msgfmt.h" +#include "kbmailer.h" +#include "validateprogress.h" +#include "cvshandler.h" +#include "svnhandler.h" +#include "markpatterndialog.h" +#include "validationoptions.h" + +#include <qcheckbox.h> +#include <qpopupmenu.h> +#include <qlabel.h> +#include <qpainter.h> + +#include <kcmenumngr.h> +#include <kcursor.h> +#include <klocale.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kconfig.h> +#include <kdatatool.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kaction.h> +#include <kfiledialog.h> +#include <kio/netaccess.h> +#include <kprogress.h> +#include <kwin.h> +#include <kdeversion.h> +#include <ktempfile.h> + +#include <qfileinfo.h> +#include <qdir.h> +#include <qtimer.h> +#include <qbitmap.h> +#include <qwhatsthis.h> +#include <qheader.h> +#include <qdragobject.h> +#include <qlayout.h> +#include <qtextedit.h> + +using namespace KBabel; + +const char* columnNames[] = { + I18N_NOOP("Name"), + I18N_NOOP("M"), + I18N_NOOP("Fuzzy"), + I18N_NOOP("Untranslated"), + I18N_NOOP("Total"), + I18N_NOOP("CVS/SVN Status"), + I18N_NOOP("Last Revision"), + I18N_NOOP("Last Translator") +}; + +#define COLTEXT(a) (i18n(columnNames[a])) + +CatalogManagerView::CatalogManagerView(KBabel::Project::Ptr project, QWidget* parent,const char* name) + : QListView(parent,name) + , _dirWatch(0) + , _readInfoCount(0) + , _active(false) + , _stop(false) + , _stopSearch(false) + , _updateNesting(0) + , _logView(0) + , _logWindow(0) + , m_validPOCVSRepository( false ) + , m_validPOTCVSRepository( false ) + , m_validPOSVNRepository( false ) + , m_validPOTSVNRepository( false ) + , markPatternDialog(0) + , _validateDialog(0) + , _validateOptions(0) + , _validateOptionsDlg(0) + , _markAsFuzzy(false) + , _ignoreFuzzy(false) + , _project(project) +{ + _dirList.resize(200); + _fileList.resize(500); + _readInfoFileList.clear(); + + _pendingProcesses.setAutoDelete(true); + + setSelectionMode(Single); + + _dictBox = new KBabelDictBox(this, "dictbox"); + _dictBox->hide(); + + _updateTimer = new QTimer(this); + connect(_updateTimer,SIGNAL(timeout()),this,SLOT(checkUpdate())); + + addColumn(COLTEXT(COL_NAME)); + addColumn(COLTEXT(COL_MARKER),25); + setColumnAlignment(1,AlignCenter); + addColumn(COLTEXT(COL_FUZZY)); + setColumnAlignment(1,AlignCenter); + addColumn(COLTEXT(COL_UNTRANS)); + setColumnAlignment(2,AlignCenter); + addColumn(COLTEXT(COL_TOTAL)); + setColumnAlignment(3,AlignCenter); + addColumn(QString::null); // CVS/SVN column, header is set later + addColumn(COLTEXT(COL_REVISION)); + addColumn(COLTEXT(COL_TRANSLATOR)); + + + header()->setMovingEnabled(false); + setAllColumnsShowFocus(true); + setSorting(0); + + if(KContextMenuManager::showOnButtonPress()) + { + connect(this,SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &, int)) + ,this, SLOT(showContentsMenu(QListViewItem*,const QPoint &, int))); + } + else + { + connect(this,SIGNAL(rightButtonClicked(QListViewItem*,const QPoint &, int)) + ,this, SLOT(showContentsMenu(QListViewItem*,const QPoint &, int))); + } + connect(this, SIGNAL(returnPressed(QListViewItem*)) + ,this, SLOT(activateItem(QListViewItem*))); + connect(this, SIGNAL(doubleClicked(QListViewItem*)) + ,this, SLOT(activateItem(QListViewItem*))); + connect(this,SIGNAL(selectionChanged()),this,SLOT(checkSelected())); + connect( this, SIGNAL( clicked(QListViewItem *, const QPoint &, int)), + this, SLOT( columnClicked(QListViewItem *, const QPoint &, int))); + + _dirCommandsMenu = 0; + _fileCommandsMenu = 0; + _dirContentsMenu = 0; + _fileContentsMenu = 0; + + _logWindow = new KDialogBase(0,"log window",false,i18n("Log Window") + ,KDialogBase::Close | KDialogBase::User1,KDialogBase::Close); + _logWindow->setButtonText(KDialogBase::User1,i18n("C&lear")); + _logWindow->setInitialSize(QSize(300,200)); + + QWhatsThis::add(_logWindow,i18n("<qt><p><b>Log window</b></p>\n" + "<p>In this window the output of " + "the executed commands are shown.</p></qt>")); + + _logView = new QTextEdit(_logWindow); + _logView->setReadOnly(true); + + _logWindow->setMainWidget(_logView); + + connect(_logWindow,SIGNAL(user1Clicked()),_logView,SLOT(clear())); + + QWhatsThis::add(this,i18n("<qt><p><b>Catalog Manager</b></p>\n" +"<p>The Catalog Manager merges two folders into one tree and displays all\n" +"PO and POT files in these folders. This way you can easily see if a\n" +"template has been added or removed. Also some information about the files\n" +"is displayed.</p>" +"<p>For more information see section <b>The Catalog Manager</b>" +" in the online help.</p></qt>")); + + setAcceptDrops(true); // just to get the drag displayed immediately + + mailer = new KBabelMailer( this, _project ); + + // CVS + cvshandler = new CVSHandler( ); + connect( cvshandler, SIGNAL( signalIsPORepository( bool ) ), + this, SLOT( slotValidPOCVSRepository( bool ) ) ); + connect( cvshandler, SIGNAL( signalIsPOTRepository( bool ) ), + this, SLOT( slotValidPOTCVSRepository( bool ) ) ); + connect( cvshandler, SIGNAL( signalFilesCommitted( const QStringList& ) ), + this, SLOT( updateFiles( const QStringList& ) ) ); + + // SVN + svnhandler = new SVNHandler( ); + connect( svnhandler, SIGNAL( signalIsPORepository( bool ) ), + this, SLOT( slotValidPOSVNRepository( bool ) ) ); + connect( svnhandler, SIGNAL( signalIsPOTRepository( bool ) ), + this, SLOT( slotValidPOTSVNRepository( bool ) ) ); + connect( svnhandler, SIGNAL( signalFilesCommitted( const QStringList& ) ), + this, SLOT( updateFiles( const QStringList& ) ) ); + + KConfig *config = KGlobal::config(); + restoreView(config); + + _dictBox->readSettings(_project->config()); +} + +CatalogManagerView::~CatalogManagerView() +{ + if(_active) + stop(); + + if(_dirWatch) + delete _dirWatch; + + if(_settings.killCmdOnExit) + { + KProcess* proc; + for ( proc=_pendingProcesses.first(); proc != 0; proc=_pendingProcesses.next() ) + { + proc->kill(SIGKILL); + } + } + + delete _logWindow; + delete mailer; + delete cvshandler; + delete svnhandler; + if (markPatternDialog) delete markPatternDialog; +} + + +void CatalogManagerView::saveView( KConfig *config) const +{ + saveMarker(config); + + KConfigGroupSaver( config, "CatalogManager" ); + + config->writeEntry( "ValidateMarkAsFuzzy", _markAsFuzzy ); + config->writeEntry( "ValidateIgnoreFuzzy", _ignoreFuzzy ); +} + + +void CatalogManagerView::restoreView( KConfig *config) +{ + readMarker(config); + + _markAsFuzzy = config->readBoolEntry( "ValidateMarkAsFuzzy", false ); + _ignoreFuzzy = config->readBoolEntry( "ValidateIgnoreFuzzy", false ); +} + +void CatalogManagerView::setRMBMenuFile( QPopupMenu *m ) +{ + _fileContentsMenu = m; +} + +void CatalogManagerView::setRMBMenuDir( QPopupMenu *m ) +{ + _dirContentsMenu = m; +} + +void CatalogManagerView::setDirCommandsMenu( QPopupMenu *m ) +{ + _dirCommandsMenu = m; + connect(_dirCommandsMenu,SIGNAL(activated(int)),this,SLOT(slotDirCommand(int))); +} + +void CatalogManagerView::setFileCommandsMenu( QPopupMenu *m ) +{ + _fileCommandsMenu = m; + connect(_fileCommandsMenu,SIGNAL(activated(int)),this,SLOT(slotFileCommand(int))); +} + +void CatalogManagerView::checkUpdate() +{ + _updateNesting++; + pause(true); + + QDictIterator<CatManListItem> it( _fileList ); // iterator for dict + + while ( it.current() && !_stop) + { + CatManListItem* item=it.current(); + + item->checkUpdate(); + ++it; + } + + pause(false); + --_updateNesting; + if( _updateNesting == 0 ) + { + emit updateFinished(); + } +} + + + +void CatalogManagerView::pause(bool flag) +{ + if(flag) + { + _updateTimer->stop(); + } + else + { + _updateTimer->start(10000); + } +} + + +void CatalogManagerView::stop(bool s) +{ + kdDebug(KBABEL_CATMAN) << "Stopping " << s << endl; + pause(s); + _stop=s; + PoInfo::stopStaticRead = true; +} + +void CatalogManagerView::stopSearch() +{ + _stopSearch = true; +} + +void CatalogManagerView::clear() +{ + pause(true); + + // first clear up + if(_dirWatch) + delete _dirWatch; + + _dirWatch= new KDirWatch(); + connect(_dirWatch,SIGNAL(deleted(const QString&)),this + ,SLOT(directoryDeleted(const QString&))); + connect(_dirWatch,SIGNAL(dirty(const QString&)),this + ,SLOT(directoryChanged(const QString&))); + connect(_dirWatch,SIGNAL(created(const QString&)),this + ,SLOT(directoryChanged(const QString&))); + + _dirList.clear(); + _fileList.clear(); + + QListView::clear(); +} + +void CatalogManagerView::toggleAllMarks() +{ + _markerList.clear(); + + QListViewItemIterator it( this ); + CatManListItem* item; + + for ( ; it.current(); ++it ) + { + item = (CatManListItem*) it.current(); + if(item->isFile()) + { + bool wasMarked=item->marked(); + item->setMarked(!wasMarked); + if(!wasMarked) + { + _markerList.append(item->package()); + } + else + { + _markerList.remove(item->package()); + } + } + } + + checkSelected(); +} + +void CatalogManagerView::clearAllMarks() +{ + _markerList.clear(); + QDictIterator<CatManListItem> it( _fileList ); // iterator for dict + + while ( it.current() ) + { + CatManListItem* item=it.current(); + + if(item->marked()) + _markerList.remove(item->package()); + + item->setMarked(false); + ++it; + } + + checkSelected(); +} + +void CatalogManagerView::markModifiedFiles() +{ + QDictIterator<CatManListItem> it( _fileList ); + while ( it.current() ) + { + CatManListItem* item=it.current(); + /*if(item->marked()) + _markerList.remove(item->package()); + */ + if(item->isModified() && ! item->marked() ) { + item->setMarked(true); + _markerList.append(item->package( )); + } + ++it; + } + + checkSelected(); +} + +void CatalogManagerView::loadMarks() +{ + const KURL url = KFileDialog::getOpenURL( QString(),"*.marklist", this ); + if( url.isEmpty() ) return; + + QString filename; +#if KDE_IS_VERSION( 3, 2, 90 ) + if (!KIO::NetAccess::download( url, filename, this ) ) +#else + if( !KIO::NetAccess::download( url, filename ) ) +#endif + { + KMessageBox::error(this,i18n( + "Error while trying to open file:\n %1").arg(url.prettyURL())); + return; + } + + // now load from file + QStringList newMarkerList; // better create new list in case of problems + QFile f( filename ); + if( f.open( IO_ReadOnly) ) + { + QTextStream s(&f); + + QString input; + + s >> input ; + if( input == "[Markers]" ) + { + while( !s.atEnd() ) + { + s >> input; + newMarkerList.append(input); + } + } + else + { + KMessageBox::error(this + ,i18n("Error while trying to read file:\n %1\n" + "Maybe it is not a valid file with list of markings.").arg(url.prettyURL())); + f.close(); + return; + } + f.close(); + } + else + { + KMessageBox::error(this,i18n( + "Error while trying to open file:\n %1").arg(url.prettyURL())); + } + + KIO::NetAccess::removeTempFile( filename ); + + // test validity of list items + QStringList testedList; + QStringList::const_iterator it; + for( it=newMarkerList.constBegin() ; it!=newMarkerList.constEnd() ; ++it ) + if( _fileList[(*it)] != 0 ) testedList.append( (*it) ); + + // apply new list + for( it=_markerList.constBegin() ; it!=_markerList.constEnd() ; ++it ) + { + CatManListItem* item = _fileList[(*it)]; + if( item ) item->setMarked(false); + } + + _markerList = testedList; + for( it=_markerList.constBegin() ; it!=_markerList.constEnd() ; ++it ) + { + CatManListItem* item = _fileList[(*it)]; + if( item ) item->setMarked(true); + } + + checkSelected(); +} + +void CatalogManagerView::saveMarks() +{ + const KURL url2 = KFileDialog::getSaveURL( QString(), "*.marklist", this ); + if( url2.isEmpty() ) return; + + // ### FIXME: why is the file dialog not doing this? + if ( KIO::NetAccess::exists( url2, false, this ) ) + { + if(KMessageBox::warningContinueCancel(this,QString("<qt>%1</qt>").arg(i18n("The file %1 already exists. " + "Do you want to overwrite it?").arg(url2.prettyURL())),i18n("Warning"),i18n("&Overwrite"))==KMessageBox::Cancel) + { + return; + } + } + +#if KDE_IS_VERSION( 3, 4, 92 ) + // Support for partially remote KIO slave like media: + const KURL url ( KIO::NetAccess::mostLocalURL( url2, this ) ); +#else + const KURL url ( url2 ); +#endif + kdDebug() << "Saving marks: " << url2.prettyURL() << " most-local: " << url.prettyURL() << endl; + + QFile* file = 0; + KTempFile* tempFile = 0; + QTextStream* stream = 0; + bool error = false; + + const bool localFile = url.isLocalFile(); + if ( localFile ) + { + // We have a local file + file = new QFile( url.path() ); + if ( file->open (IO_WriteOnly) ) + { + stream = new QTextStream( file ); + } + else + { + error = true; + } + } + else + { + tempFile = new KTempFile(); + tempFile->setAutoDelete(true); + stream = tempFile->textStream(); + error = !stream; + } + if ( !error ) + { + // ### TODO: try to get a better file format for KDE4 (XML?), one working with real relative paths (no / at start) and working with UTF-8 + *stream << "[Markers]" << endl; + for( QStringList::const_iterator it = _markerList.constBegin(); it!=_markerList.constEnd() ; ++it ) + *stream << (*it) << endl; + } + if ( error ) + { + // ### KDE4 FIXME: strip the final \n of the message + KMessageBox::error( this, + i18n( "An error occurred while trying to write to file:\n%1\n" ).arg( url.prettyURL()) ); + } + else if ( !localFile ) + { + tempFile->close(); + if( !KIO::NetAccess::upload( tempFile->name(), url, this ) ) + { + // ### KDE4 FIXME: strip the final \n of the message + KMessageBox::error(this, + i18n("An error occurred while trying to upload the file:\n%1\n").arg(url.prettyURL())); + } + } + + // We have finished so clean up + if ( localFile ) + { + delete stream; + file->close(); + delete file; + } + else + { + delete tempFile; + } + + checkSelected(); +} + +void CatalogManagerView::slotMarkPattern( ) +{ + setPatternMarks(true); +} + +void CatalogManagerView::slotUnmarkPattern( ) +{ + setPatternMarks(false); +} + +void CatalogManagerView::setPatternMarks(bool mark) +{ + CatManListItem * item = (CatManListItem*)currentItem( ); + if (!item) + item = (CatManListItem*)_dirList["/"]; + if (!item->isDir( )) + return; + + if (!markPatternDialog) + markPatternDialog = new MarkPatternDialog(this); + + markPatternDialog->setMode(mark); + + if (markPatternDialog->exec( ) != KDialog::Accepted) + return; + + QRegExp rx(markPatternDialog->pattern( )); + rx.setWildcard(!markPatternDialog->useRegExp( )); + rx.setCaseSensitive(markPatternDialog->isCaseSensitive( )); + + QStringList fileList = item->allChildrenList(true); + for (QStringList::const_iterator it = fileList.constBegin( ); it != fileList.constEnd( ); ++it) { + CatManListItem * i = _fileList[*it]; + + QString matchName; + if (i->hasPo( )) + matchName = i->poFile( ); + else if (i->hasPot( ) && markPatternDialog->includeTemplates( )) + matchName = i->potFile( ); + matchName = QFileInfo(matchName).baseName( ); + + if (mark) { + if (!matchName.isEmpty( ) && rx.exactMatch(matchName) && !i->marked( )) { + i->setMarked(true); + _markerList.append(i->package( )); + } + } else { + if (!matchName.isEmpty( ) && rx.exactMatch(matchName) && i->marked( )) { + i->setMarked(false); + _markerList.remove(i->package( )); + } + } + } +} + +void CatalogManagerView::statistics() +{ + CatManListItem* i=(CatManListItem*) currentItem(); + + if(!i) + i=(CatManListItem*)_dirList["/"]; + + if(isActive() && i->isDir()) + { + if(KMessageBox::warningContinueCancel(this + ,i18n("The Catalog Manager is still updating information about the files.\n" +"If you continue, it will try to update all necessary files, however this can take " +"a long time and may lead to wrong results. Please wait until all files are updated."),i18n("Warning") + ,KStdGuiItem::cont()) == KMessageBox::Cancel) + { + return; + } + } + + QStringList doList; + + if( i->isFile() ) doList.append(i->package()); + else doList = i->allChildrenList(true); + + showStatistics( i, doList ); +} + +void CatalogManagerView::markedStatistics() +{ + CatManListItem* i=(CatManListItem*) currentItem(); + + if(!i) + i=(CatManListItem*)_dirList["/"]; + + if(isActive() && i->isDir()) + { + if(KMessageBox::warningContinueCancel(this + ,i18n("The Catalog Manager is still updating information about the files.\n" +"If you continue, it will try to update all necessary files, however this can take " +"a long time and may lead to wrong results. Please wait until all files are updated."),i18n("Warning") + ,KStdGuiItem::cont()) == KMessageBox::Cancel) + { + return; + } + } + + QStringList doList; + + if( i->isFile() ) doList.append(i->package()); + else doList = i->allChildrenList(true); + + QStringList markedDoList; + QStringList::const_iterator it; + for( it = doList.constBegin(); it != doList.constEnd(); ++it ) + { + CatManListItem* item = _fileList[(*it)]; + if( item->marked() ) markedDoList.append(item->package()); + } + + showStatistics( i, markedDoList ); +} + +void CatalogManagerView::showStatistics( CatManListItem *i, QStringList &childrenList ) +{ + KLocale *locale = KGlobal::locale(); + + QString msg; + int totalPackages=0; + int totalPo=0; + int totalNoPot=0; + int needworkPo=0; + int totalMsgid=0; + int totalFuzzy=0; + int totalUntranslated=0; + + QStringList::const_iterator it; + for( it = childrenList.constBegin(); it != childrenList.constEnd(); ++it ) + { + CatManListItem* item = _fileList[(*it)]; + + /* + KASSERT1(item,KDEBUG_FATAL,KBABEL_CATMAN,"CatalogManagerView::statistics: item not in list %s" + ,(*it).ascii()); + */ + // be sure, that the information is updated + _updateNesting++; + item->checkUpdate(); + _updateNesting--; + if( _stop ) return; + + totalPackages++; + + int fuzzy=item->fuzzy(); + int total=item->total(); + int untrans=item->untranslated(); + + if(item->hasPo()) + totalPo++; + + if(!item->hasPot()) + totalNoPot++; + + + if(fuzzy || untrans) + needworkPo++; + + totalMsgid+=total; + totalFuzzy+=fuzzy; + totalUntranslated+=untrans; + } + + double percent; + + const QString name=i->package(false); + if(name.isEmpty()) + msg = i18n("Statistics for all:\n"); + else + msg = i18n("Statistics for %1:\n").arg(name); + + msg+=i18n("Number of packages: %1\n").arg(locale->formatNumber(totalPackages, 0)); + + percent=100.0-((double)needworkPo*100.0)/totalPackages; + msg+=i18n("Complete translated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalPackages-needworkPo, 0)); + + percent=100.0-((double)totalPo*100.0)/totalPackages; + msg+=i18n("Only template available: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalPackages-totalPo,0)); + percent=((double)totalNoPot*100.0)/totalPackages; + msg+=i18n("Only PO file available: %1 % (%2)\n").arg(locale->formatNumber(percent,02)).arg(locale->formatNumber(totalNoPot, 0)); + + msg+=i18n("Number of messages: %1\n").arg(locale->formatNumber(totalMsgid, 0)); + + long int totalTranslated = totalMsgid - totalFuzzy - totalUntranslated; + percent=((double)totalTranslated*100.0)/totalMsgid; + msg+=i18n("Translated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalTranslated, 0)); + + percent=((double)totalFuzzy*100.0)/totalMsgid; + msg+=i18n("Fuzzy: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalFuzzy, 0)); + + percent=((double)totalUntranslated*100.0)/totalMsgid; + msg+=i18n("Untranslated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalUntranslated, 0)); + + KMessageBox::information(this,msg,i18n("Statistics")); +} + +void CatalogManagerView::checkSyntax() +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(!item) + item=(CatManListItem*) _dirList["/"]; + + if(item->isFile()) + { + if(!item->hasPo()) + return; + + Msgfmt::Status status; + QString output; + Msgfmt msgfmt; + + status=msgfmt.checkSyntax(item->poFile(),output); + + switch(status) + { + case Msgfmt::Ok: + { + KMessageBox::information(this,i18n("The file is syntactically correct.\nOutput of \"msgfmt --statistics\":")+"\n"+output); + break; + } + case Msgfmt::SyntaxError: + { + KMessageBox::information(this,i18n("The file has syntax errors.\nOutput of \"msgfmt --statistics\":")+"\n"+output); + break; + } + case Msgfmt::HeaderError: + { + KMessageBox::information(this,i18n("The file has header syntax error.\nOutput of \"msgfmt --statistics\":")+"\n"+output); + break; + } + case Msgfmt::Error: + { + KMessageBox::error(this,i18n("An error occurred while processing \"msgfmt --statistics\"")); + break; + } + case Msgfmt::NoExecutable: + { + KMessageBox::sorry(this,i18n("Cannot execute msgfmt. Please make sure that you have msgfmt in your PATH.")); + break; + } + case Msgfmt::Unsupported: + { + KMessageBox::sorry(this,i18n("You can use gettext tools only for checking PO files.")); + break; + } + } + + } + else + { + Msgfmt::Status status; + QString output; + Msgfmt msgfmt; + + status=msgfmt.checkSyntaxInDir(item->poFile(), "*.po", output); + + QString name=item->package(false); + + switch(status) + { + case Msgfmt::Ok: + { + QString msg; + if(!name.isEmpty()) + { + msg=i18n("All files in folder %1 are syntactically correct.\n" +"Output of \"msgfmt --statistics\":\n").arg(name)+output; + } + else + { + msg=i18n("All files in the base folder are syntactically correct.\n" +"Output of \"msgfmt --statistics\":\n")+output; + } + KMessageBox::information(this,msg); + break; + } + case Msgfmt::SyntaxError: + { + QString msg; + if(!name.isEmpty()) + { + msg=i18n("At least one file in folder %1 has syntax errors.\n" +"Output of \"msgfmt --statistics\":\n").arg(name)+output; + } + else + { + msg=i18n("At least one file in the base folder has syntax errors.\n" +"Output of \"msgfmt --statistics\":\n")+output; + } + KMessageBox::information(this,msg); + break; + } + case Msgfmt::HeaderError: + { + QString msg; + if(!name.isEmpty()) + { + msg=i18n("At least one file in folder %1 has header syntax errors.\n" +"Output of \"msgfmt --statistics\":\n").arg(name)+output; + } + else + { + msg=i18n("At least one file in the base folder has header syntax errors.\n" +"Output of \"msgfmt --statistics\":\n")+output; + } + KMessageBox::information(this,msg); + break; + } + case Msgfmt::Error: + { + QString msg; + if(!name.isEmpty()) + { + msg=i18n("An error occurred while processing \"msgfmt --statistics *.po\" " +"in folder %1").arg(name); + } + else + { + msg=i18n("An error occurred while processing \"msgfmt --statistics *.po\" " +"in the base folder"); + } + KMessageBox::error(this,msg); + break; + } + case Msgfmt::NoExecutable: + { + KMessageBox::sorry(this,i18n("Cannot execute msgfmt. Please make sure that you have msgfmt in your PATH.")); + break; + } + case Msgfmt::Unsupported: + { + KMessageBox::sorry(this,i18n("You can use gettext tools only for checking PO files.")); + break; + } + } + } +} + +void CatalogManagerView::roughTranslation() +{ + QPtrList<CatManListItem> result; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + if( current->isDir() ) + { + QStringList s = current->allChildrenList(true); + QStringList::const_iterator it; + for( it = s.constBegin() ; it != s.constEnd(); ++it ) + { + CatManListItem *item = _fileList[(*it)]; + if( item ) result.append( item ); + } + } + else + { + result.append( current ); + } + + MultiRoughTransDlg* dialog=new MultiRoughTransDlg( _dictBox, result, this ); + dialog->exec(); + delete dialog; +} + +void CatalogManagerView::markedRoughTranslation() +{ + if( _markerList.count() == 0 ) return; + + QPtrList<CatManListItem> result; + + QStringList::const_iterator it; + for( it = _markerList.constBegin() ; it != _markerList.constEnd(); ++it ) + { + CatManListItem *item = _fileList[(*it)]; + result.append( item ); + } + + MultiRoughTransDlg* dialog=new MultiRoughTransDlg( _dictBox, result, this ); + dialog->exec(); + delete dialog; +} + +void CatalogManagerView::mailFiles() +{ + CatManListItem* item = (CatManListItem*)currentItem(); + if(item->isDir()) { + QStringList filesToSend; + QStringList childrenList = item->allChildrenList(true); + + QStringList::const_iterator it; + for (it = childrenList.constBegin(); it != childrenList.constEnd(); ++it) { + CatManListItem* i = _fileList[(*it)]; + if (i->hasPo()) { + filesToSend << i->poFile(); + } + } + mailer->sendFiles(filesToSend, item->text(0)); + } else { + if (item->hasPo()) { + mailer->sendOneFile(item->poFile()); + } + } +} + +void CatalogManagerView::mailMarkedFiles() +{ + if (_markerList.count() == 0) + return; + + QStringList filesToSend; + QStringList::const_iterator it; + for (it = _markerList.constBegin(); it != _markerList.constEnd(); ++it) { + CatManListItem* i = _fileList[(*it)]; + if (i->hasPo()) { + filesToSend << i->poFile(); + } + } + mailer->sendFiles(filesToSend); +} + +void CatalogManagerView::packageFiles( ) +{ + CatManListItem* item = (CatManListItem*)currentItem(); + if(item->isDir()) { + QStringList filesToPackage; + QStringList childrenList = item->allChildrenList(true); + + QStringList::const_iterator it; + for (it = childrenList.constBegin(); it != childrenList.constEnd(); ++it) { + CatManListItem* i = _fileList[(*it)]; + if (i->hasPo()) { + filesToPackage << i->poFile(); + } + } + QString packageFileName = KFileDialog::getSaveFileName(QString::null,"*.tar.bz2\n*.tar.gz",this); + mailer->buildArchive( filesToPackage, packageFileName, QString::null, false ); + } + else { + if (item->hasPo()) { + QStringList fileToPackage(item->poFile()); + QString packageFileName = KFileDialog::getSaveFileName(QString::null,"*.tar.bz2\n*.tar.gz",this); + mailer->buildArchive( fileToPackage, packageFileName, QString::null, false ); + } + } +} +void CatalogManagerView::packageMarkedFiles( ) +{ + if (_markerList.count() == 0) + return; + + QStringList filesToPackage; + QStringList::const_iterator it; + for (it = _markerList.constBegin(); it != _markerList.constEnd(); ++it) { + CatManListItem* i = _fileList[(*it)]; + if (i->hasPo()) { + filesToPackage << i->poFile(); + } + } + + QString packageFileName = KFileDialog::getSaveFileName(QString::null,"*.tar.bz2\n*.tar.gz",this); + mailer->buildArchive( filesToPackage, packageFileName, QString::null, false ); +} + +// CVS +void CatalogManagerView::cvsUpdate( ) +{ + doCVSCommand( CVS::Update ); +} + +void CatalogManagerView::cvsUpdateMarked( ) +{ + doCVSCommand( CVS::Update, true ); +} + +void CatalogManagerView::cvsCommit( ) +{ + doCVSCommand( CVS::Commit ); +} + +void CatalogManagerView::cvsCommitMarked( ) +{ + doCVSCommand( CVS::Commit, true ); +} + +void CatalogManagerView::cvsStatus( ) +{ + doCVSCommand( CVS::Status ); +} + +void CatalogManagerView::cvsStatusMarked( ) +{ + doCVSCommand( CVS::Status, true ); +} + +void CatalogManagerView::cvsUpdateTemplate( ) +{ + doCVSCommand( CVS::Update, false, true ); +} + +void CatalogManagerView::cvsUpdateMarkedTemplate( ) +{ + doCVSCommand( CVS::Update, true, true ); +} + +void CatalogManagerView::cvsCommitTemplate( ) +{ + doCVSCommand( CVS::Commit, false, true ); +} + +void CatalogManagerView::cvsCommitMarkedTemplate( ) +{ + doCVSCommand( CVS::Commit, true, true ); +} + +void CatalogManagerView::cvsDiff( ) +{ + doCVSCommand( CVS::Diff, false, false ); +} + +void CatalogManagerView::doCVSCommand( CVS::Command cmd, bool marked, bool templates ) +{ + KSharedConfig* config = _project->sharedConfig(); + if ( marked ) { + if ( _markerList.isEmpty() ) return; + QStringList fileList; + QStringList::const_iterator it; + for ( it = _markerList.constBegin( ); it != _markerList.constEnd( ); ++it ) { + CatManListItem * i = _fileList[(*it)]; + if ( templates && i->hasPot( ) ) + fileList << i->potFile( ); + else if ( !templates && i->hasPo( ) ) + fileList << i->poFile( ); + } + cvshandler->execCVSCommand( this, cmd, fileList, templates, config ); + } else { + const QString basedir = ( templates ? _settings.potBaseDir : _settings.poBaseDir ); + QString cvsItem; + CatManListItem * item = (CatManListItem*)currentItem( ); + if ( ( cmd == CVS::Commit || cmd == CVS::Diff ) && item->isDir( ) ) { + // all children including directories + QStringList cvsItems = item->allChildrenFileList (true, false, true); + if ( !cvsItems.isEmpty( ) ) + cvshandler->execCVSCommand( this, cmd, cvsItems, templates, config ); + } else { + if ( templates && item->hasPot( ) ) + cvsItem = item->potFile( ); + else if ( !templates && item->hasPo( ) ) + cvsItem = item->poFile( ); + + if ( !cvsItem.isEmpty( ) ) + cvshandler->execCVSCommand( this, cmd, cvsItem, templates, config ); + } + } +} + +//SVN +void CatalogManagerView::svnUpdate( ) +{ + doSVNCommand( SVN::Update ); +} + +void CatalogManagerView::svnUpdateMarked( ) +{ + doSVNCommand( SVN::Update, true ); +} + +void CatalogManagerView::svnCommit( ) +{ + doSVNCommand( SVN::Commit ); +} + +void CatalogManagerView::svnCommitMarked( ) +{ + doSVNCommand( SVN::Commit, true ); +} + +void CatalogManagerView::svnStatusRemote( ) +{ + doSVNCommand( SVN::StatusRemote ); +} + +void CatalogManagerView::svnStatusRemoteMarked( ) +{ + doSVNCommand( SVN::StatusRemote, true ); +} + +void CatalogManagerView::svnStatusLocal( ) +{ + doSVNCommand( SVN::StatusLocal ); +} + +void CatalogManagerView::svnStatusLocalMarked( ) +{ + doSVNCommand( SVN::StatusLocal, true ); +} + +void CatalogManagerView::svnInfo() +{ + doSVNCommand( SVN::Info ); +} + +void CatalogManagerView::svnInfoMarked() +{ + doSVNCommand( SVN::Info, true ); +} + +void CatalogManagerView::svnUpdateTemplate( ) +{ + doSVNCommand( SVN::Update, false, true ); +} + +void CatalogManagerView::svnUpdateMarkedTemplate( ) +{ + doSVNCommand( SVN::Update, true, true ); +} + +void CatalogManagerView::svnCommitTemplate( ) +{ + doSVNCommand( SVN::Commit, false, true ); +} + +void CatalogManagerView::svnCommitMarkedTemplate( ) +{ + doSVNCommand( SVN::Commit, true, true ); +} + +void CatalogManagerView::svnDiff( ) +{ + doSVNCommand( SVN::Diff, false, false ); +} + +void CatalogManagerView::doSVNCommand( SVN::Command cmd, bool marked, bool templates ) +{ + KSharedConfig* config = _project->sharedConfig(); + if ( marked ) { + if ( _markerList.isEmpty() ) return; + QStringList fileList; + QStringList::const_iterator it; + for ( it = _markerList.constBegin( ); it != _markerList.constEnd( ); ++it ) { + CatManListItem * i = _fileList[(*it)]; + if ( templates && i->hasPot( ) ) + fileList << i->potFile( ); + else if ( !templates && i->hasPo( ) ) + fileList << i->poFile( ); + } + svnhandler->execSVNCommand( this, cmd, fileList, templates, config ); + } else { + const QString basedir = ( templates ? _settings.potBaseDir : _settings.poBaseDir ); + QString svnItem; + CatManListItem * item = (CatManListItem*)currentItem( ); + if ( ( cmd == SVN::Commit || cmd == SVN::Diff ) && item->isDir( ) ) { + // all children including directories + QStringList svnItems = item->allChildrenFileList (true, false, true); + if ( !svnItems.isEmpty( ) ) + svnhandler->execSVNCommand( this, cmd, svnItems, templates, config ); + } else { + if ( templates && item->hasPot( ) ) + svnItem = item->potFile( ); + else if ( !templates && item->hasPo( ) ) + svnItem = item->poFile( ); + + if ( !svnItem.isEmpty( ) ) + svnhandler->execSVNCommand( this, cmd, svnItem, templates, config ); + } + } +} + +void CatalogManagerView::showLog() +{ + _logWindow->show(); +} + +QString CatalogManagerView::find( FindOptions &options, QStringList &rest ) +{ + CatManListItem* i=(CatManListItem*) currentItem(); + + if(!i || options.inAllFiles) + i=(CatManListItem*)_dirList["/"]; + + QValueList<QString> foundFiles; + _stopSearch = false; + + const QString search = options.findStr.lower().simplifyWhiteSpace(); + QStringList searchWords = QStringList::split(' ', search); + + QStringList childrenList; + if( i->isFile() ) childrenList.append(i->name()); + else childrenList =i->allChildrenList(true); + + emit prepareFindProgressBar(childrenList.size()); + + QStringList::const_iterator it; + for( it = childrenList.constBegin(); it != childrenList.constEnd(); ++it ) + { + CatManListItem* item = _fileList[(*it)]; + + if( !item ) + { + kdWarning(KBABEL_CATMAN) << "The file information not found, skipping" << endl; + continue; + } + + // skip if not marked and we lookup in marked + if( options.inMarkedFiles && !item->marked() ) + { + kdDebug(KBABEL_CATMAN) << "Skipping due marking " << item->name() << endl; + emit signalSearchedFile(1); + continue; + } + + bool doSearch = options.isRegExp || options.inTemplates; // for regexp and templates we do not support index search + if( item->wordsUpdated() ) + doSearch = doSearch || hasMatchingWords(item->wordList(), searchWords); + else doSearch = true; // we do not have index, we need to search + if( doSearch ) + { + QString itemFile; + if( options.inTemplates ) + { + if( item->hasPot() ) itemFile=item->potFile(); + } else { + if( item->hasPo() ) itemFile=item->poFile(); + } + + if( itemFile.isNull() ) + { + emit signalSearchedFile(1); + continue; + } + + if( PoInfo::findInFile( itemFile , options ) ) + { + emit signalSearchedFile(1); + rest.clear(); + if( _stopSearch ) + { + // if we are stopped, return what we found and clear the rest + _stopSearch = false; + return itemFile; + } + const QString foundItemFile = itemFile; + + it++; + while( it != childrenList.constEnd() ) + { + CatManListItem *item = _fileList[(*it)]; + + itemFile = QString::null; + if( options.inTemplates ) + { + if( item->hasPot() ) itemFile=item->potFile(); + } else { + if( item->hasPo() )itemFile=item->poFile(); + } + if( options.inMarkedFiles && !item->marked() ) + itemFile=QString::null; + + if( !itemFile.isNull()) + { + if( item->wordsUpdated() && !options.inTemplates ) + { + if( options.isRegExp || hasMatchingWords(item->wordList(), searchWords) ) + { + rest.append( itemFile ); + } + else kdDebug(KBABEL_CATMAN) << "Don't try to lookup in " << itemFile << endl; + } else { + rest.append( itemFile ); // there is no word index, add the file + } + } else emit signalSearchedFile(1); + + it++; + } + return foundItemFile; + + } + } else kdDebug(KBABEL_CATMAN) << "Skipping " << item->poFile() << endl; + emit signalSearchedFile(1); + if( _stop || _stopSearch ) { + _stopSearch = false; + rest.clear(); + if( _updateNesting == 0 && !_stop ) emit updateFinished(); + return QString::null; + } + } + return QString::null; +} + +bool CatalogManagerView::hasMatchingWords( QStringList &itemWords, QStringList &searchWords) +{ + for( QStringList::const_iterator it1 = searchWords.constBegin() ; it1 != searchWords.constEnd() ; ++it1 ) + for( QStringList::const_iterator it2 = itemWords.constBegin() ; it2 != itemWords.constEnd() ; ++it2 ) + if( *it1 == *it2 + || (*it1).contains(*it2) + || (*it2).contains(*it1) ) return true; + return false; +} + +void CatalogManagerView::showContentsMenu(QListViewItem *i, const QPoint &point, int) +{ + CatManListItem* item = (CatManListItem*) i; + + if(!item) + return; + + if(item->isDir()) + { + _dirContentsMenu->exec(point); + } + else + { + _fileContentsMenu->exec(point); + } +} + +void CatalogManagerView::checkSelected() +{ + CatManListItem* item=(CatManListItem*)selectedItem(); + if(!item) return; + + const uint actionValue = + NEEDS_PO * item->hasPo() + NEEDS_POT * item->hasPot() + + NEEDS_MARK * item->marked() + NEEDS_DIR * item->isDir() + + NEEDS_PO_CVS * m_validPOCVSRepository + NEEDS_POT_CVS * m_validPOTCVSRepository + + NEEDS_PO_SVN * m_validPOSVNRepository + NEEDS_POT_SVN * m_validPOTSVNRepository; + + emit selectedChanged(actionValue); +} + +void CatalogManagerView::activateItem(QListViewItem *) +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(!item) + return; + + if(item->isDir()) + { + item->setOpen(!item->isOpen()); + return; + } + + if(item->hasPo()) + { + emit openFile(item->poFile(),item->package()); + } + else if(item->hasPot()) + { + emit openTemplate(item->potFile(),item->poFile(),item->package()); + } + else + { + kdError(KBABEL_CATMAN) << "CatalogManagerView::activateItem: item has no file?" << endl; + } + +} + +void CatalogManagerView::slotOpenFile() +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(item && item->isFile()) + { + activateItem(item); + } +} + +void CatalogManagerView::slotOpenFileInNewWindow() +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(item && item->isFile()) + { + QString filename; + if(item->hasPo()) + { + emit openFileInNewWindow(item->poFile(),item->package()); + } + else if(item->hasPot()) + { + emit openTemplateInNewWindow(item->potFile(),item->poFile(),item->package()); + } + } +} + +void CatalogManagerView::slotOpenTemplate() +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(item && item->isFile()) + { + emit openFile(item->potFile(),item->package()); + } +} + +void CatalogManagerView::slotDeleteFile() +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(item && item->isFile() && item->hasPo() && !item->hasPot()) + { + const QString msg=i18n("Do you really want to delete the file %1?").arg(item->poFile()); + if(KMessageBox::warningContinueCancel(this,msg,i18n("Warning"),KGuiItem( i18n("Delete"), "editdelete"))== KMessageBox::Continue) + { + if(!QFile::remove(item->poFile())) + { + KMessageBox::sorry(this,i18n("Was not able to delete the file %1!").arg(item->poFile())); + } + } + } +} + +void CatalogManagerView::toggleMark() +{ + CatManListItem* i = (CatManListItem*) currentItem(); + if( i && i->isDir() ) slotToggleMarksInDir(); + else slotToggleMark(); +} + +void CatalogManagerView::slotToggleMark() +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(item && item->isFile()) + { + bool wasMarked=item->marked(); + item->setMarked(!wasMarked); + + if(wasMarked) + { + _markerList.remove(item->package()); + } + else + { + _markerList.append(item->package()); + } + } + + checkSelected(); +} + +void CatalogManagerView::slotToggleMarksInDir() +{ + CatManListItem* i=(CatManListItem*) currentItem(); + + if(i && i->isDir()) + { + const QStringList contentList = i->allChildrenList(true); + + QStringList::const_iterator it; + for( it = contentList.constBegin(); it != contentList.constEnd(); ++it ) + { + CatManListItem* item = _fileList[(*it)]; + + if ( item == 0 ) + kdFatal(KBABEL_CATMAN) << "CatalogManagerView::slotToggleMarkInDir: item not in list" << endl; + + const bool wasMarked=item->marked(); + item->setMarked(!wasMarked); + + if(wasMarked) + { + _markerList.remove(item->package()); + } + else + { + _markerList.append(item->package()); + } + } + } + + checkSelected(); +} + + +void CatalogManagerView::slotClearMarksInDir() +{ + CatManListItem* i=(CatManListItem*) currentItem(); + + if(i && i->isDir()) + { + const QStringList contentList=i->contentsList(true); + + QStringList::const_iterator it; + for( it = contentList.constBegin(); it != contentList.constEnd(); ++it ) + { + CatManListItem* item = _fileList[(*it)]; + + if ( item == 0 ) + kdFatal(KBABEL_CATMAN) << "CatalogManagerView::slotClearMarkInDir: item not in list" << endl; + + if(item->marked()) + { + _markerList.remove(item->package()); + } + item->setMarked(false); + } + } + + checkSelected(); +} + + +void CatalogManagerView::slotDirCommand(int index) +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + + if(index>=0 && item && item->isDir()) + { + QString cmd=*(_settings.dirCommands).at(index); + cmd.replace("@PACKAGE@",item->name()); + cmd.replace("@PODIR@",item->poFile()); + cmd.replace("@POTDIR@",item->potFile()); + cmd.replace("@POFILES@",current().join(" ")); + cmd.replace("@MARKEDPOFILES@",marked().join(" ")); + + kdDebug(KBABEL_CATMAN) << cmd << endl; + + KProcess* proc = new KShellProcess(); + _pendingProcesses.append(proc); + + connect( proc,SIGNAL( processExited(KProcess *) ), this + ,SLOT( processEnded(KProcess*) ) ); + connect( proc,SIGNAL( receivedStdout(KProcess*,char*,int) ), this + ,SLOT( showOutput(KProcess*,char*,int) ) ); + connect( proc,SIGNAL( receivedStderr(KProcess*,char*,int) ), this + ,SLOT( showOutput(KProcess*,char*,int) ) ); + + *proc << "cd" << item->poFile() << ";" << cmd; + proc->start(KProcess::NotifyOnExit,KProcess::AllOutput); + } +} + +void CatalogManagerView::slotFileCommand(int index) +{ + CatManListItem* item=(CatManListItem*) currentItem(); + + if(index>=0 && item && item->isFile()) + { + CatManListItem* parent = (CatManListItem*)item->parent(); + + QString cmd=*(_settings.fileCommands).at(index); + cmd.replace("@PACKAGE@",item->name()); + cmd.replace("@POFILE@",item->poFile()); + cmd.replace("@POTFILE@",item->potFile()); + cmd.replace("@PODIR@",parent->poFile()); + cmd.replace("@POTDIR@",parent->potFile()); + cmd.replace("@POEMAIL@",item->text(COL_TRANSLATOR)); + + kdDebug(KBABEL_CATMAN) << cmd << endl; + + KProcess* proc = new KShellProcess(); + _pendingProcesses.append(proc); + + connect( proc,SIGNAL( processExited(KProcess *) ), this + ,SLOT( processEnded(KProcess*) ) ); + connect( proc,SIGNAL( receivedStdout(KProcess*,char*,int) ), this + ,SLOT( showOutput(KProcess*,char*,int) ) ); + connect( proc,SIGNAL( receivedStderr(KProcess*,char*,int) ), this + ,SLOT( showOutput(KProcess*,char*,int) ) ); + + *proc << "cd" << parent->poFile() << ";" << cmd; + proc->start(KProcess::NotifyOnExit,KProcess::AllOutput); + } + +} + + +void CatalogManagerView::updateFile(QString fileWithPath, bool force) +{ + QString relFile; + if(fileWithPath.startsWith(_settings.poBaseDir)) + { + relFile=fileWithPath.mid(_settings.poBaseDir.length()); + } + else if(fileWithPath.startsWith(_settings.potBaseDir)) + { + relFile=fileWithPath.mid(_settings.potBaseDir.length()); + } + else + { + return; + } + + if(relFile.endsWith(".pot")) + { + relFile.truncate(relFile.length()-4); + } + else if(relFile.endsWith(".po")) + { + relFile.truncate(relFile.length()-3); + } + + CatManListItem* item=_fileList[relFile]; + + if(item) + { + _updateNesting++; + if( force ) item->forceUpdate(); + else item->checkUpdate(); + _updateNesting--; + } + +} + +void CatalogManagerView::updateAfterSave(QString fileWithPath, PoInfo &newInfo) +{ + QString relFile; + if(fileWithPath.startsWith(_settings.poBaseDir)) + { + relFile=fileWithPath.mid(_settings.poBaseDir.length()); + } + else if(fileWithPath.startsWith(_settings.potBaseDir)) + { + relFile=fileWithPath.mid(_settings.potBaseDir.length()); + } + else + { + return; + } + + if(relFile.endsWith(".pot")) + { + relFile.truncate(relFile.length()-4); + } + else if(relFile.endsWith(".po")) + { + relFile.truncate(relFile.length()-3); + } + + CatManListItem* item=_fileList[relFile]; + + if(item) + { + item->updateAfterSave(newInfo); + } + +} + +void CatalogManagerView::buildTree() +{ + // in case we were called after settings update + disconnect( this, SIGNAL( updateFinished() ), this, SLOT(buildTree() ) ); + + emit signalBuildTree(false); // announce start of building + + clear(); + + if(isActive()) + return; + + _updateNesting++; + + _active=true; + _stop=false; + + + CatManListItem* root = new CatManListItem(this, this,_settings.poBaseDir,_settings.potBaseDir); + _dirList.insert("/",root); + //root->setSelectable(false); + + QFileInfo fileInfo(_settings.poBaseDir); + if(!fileInfo.isDir()) + { + KMessageBox::error(this,i18n("You have not specified a valid folder " +"for the base folder of the PO files:\n%1\n" +"Please check your settings in the project settings dialog.").arg(_settings.poBaseDir)); + + _active=false; + _updateNesting--; + if( _updateNesting == 0 ) emit updateFinished(); + return; + } + + cvshandler->setPOBaseDir( _settings.poBaseDir ); + svnhandler->setPOBaseDir( _settings.poBaseDir ); + mailer->setPOBaseDir(_settings.poBaseDir); + + fileInfo.setFile(_settings.potBaseDir); + if(!fileInfo.isDir() && !_settings.potBaseDir.isEmpty()) + { + KMessageBox::error(this,i18n("You have not specified a valid folder " +"for the base folder of the PO template files:\n%1\n" +"Please check your settings in the project settings dialog.").arg(_settings.potBaseDir)); + } + + cvshandler->setPOTBaseDir( _settings.potBaseDir ); + svnhandler->setPOTBaseDir( _settings.potBaseDir ); + + setCursor(KCursor::waitCursor()); + + //"/" is the root item + buildDir("/",true); // build dir without updating the items... + + if( _stop ) { + _active = false; + _updateNesting--; + if( _updateNesting == 0 ) emit updateFinished(); + return; + } + + _dirWatch->addDir(_settings.poBaseDir); + if(!_settings.potBaseDir.isEmpty()) + _dirWatch->addDir(_settings.potBaseDir); + + emit signalBuildTree(true); // announce beginning of tree building + + unsetCursor(); + + if( _stop ) { + _active = false; + _updateNesting--; + if( _updateNesting == 0 ) emit updateFinished(); + return; + } + + updateMarkerList(); + + const int files=_fileList.count()+_dirList.count(); + + _readInfoCount = 0; + + emit prepareProgressBar(i18n("Reading file information"),files); + + root->setOpen(true); + + if( _stop ) { + _active = false; + _updateNesting--; + if( _updateNesting == 0 ) emit updateFinished(); + return; + } + + // first read information about the files... + QDictIterator<CatManListItem> it( _fileList ); // iterator for dict + + int i=0; + while ( it.current() && !_stop) + { + it.current()->checkUpdate(true); + ++i; + ++it; + } + + // ...then update directories + QDictIterator<CatManListItem> dit( _dirList ); // iterator for dict + + while ( dit.current() && !_stop) + { + dit.current()->checkUpdate(); + ++i; + ++dit; + } + + emit clearProgressBar(); + + _dirWatch->startScan(); + pause(false); + + _active=false; + + _updateNesting--; + + if( _updateNesting == 0 ) + { + emit updateFinished(); + } +} + +bool CatalogManagerView::buildDir(QString relDir,bool fast) +{ + if( _stop ) return false; + + bool haveTemplateDir=true; + QFileInfo fileInfo; + + fileInfo.setFile(_settings.potBaseDir); + if(!fileInfo.isDir()) + { + haveTemplateDir=false; + } + + bool potHasFiles=false; + if(haveTemplateDir) + potHasFiles=buildDir(_settings.potBaseDir,relDir,".pot",fast); + + bool poHasFiles=buildDir(_settings.poBaseDir,relDir,".po",fast); + + return (poHasFiles | potHasFiles); +} + + +bool CatalogManagerView::buildDir(const QString& baseDir,const QString& relDir + , const QString extension , bool fast) +{ + if( _stop ) return false; + + bool havePoFiles=false; + + CatManListItem* thisItem=_dirList[relDir]; + if(!thisItem) + { + kdFatal(KBABEL_CATMAN) << "null pointer to this item" << endl; + return false; + } + + const QString poBaseDir=_settings.poBaseDir; + const QString potBaseDir=_settings.potBaseDir; + + // traverse directory in poBaseDir + QDir dir(baseDir+relDir); + QStringList entryList=dir.entryList("*"+extension,QDir::Files,QDir::Name); + + QStringList::const_iterator it; + + for ( it = entryList.constBegin(); it != entryList.constEnd() && !_stop ; ++it ) + { + if( _stop ) return false; + + havePoFiles=true; + + QString file=relDir+(*it); + file.remove(QRegExp(extension+"$")); + CatManListItem* item = _fileList[file]; + if(!item) + { + item = new CatManListItem(this,thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file); + _fileList.insert(file,item); + _readInfoFileList.prepend(file); + + if(_markerList.contains(file)) + { + item->setMarked(true); + } + + if(!fast) + { + item->checkUpdate(); + } + } + } + + entryList=dir.entryList(QDir::Dirs,QDir::Name); + + for ( it = entryList.constBegin(); it != entryList.constEnd() && !_stop ; ++it ) + { + if( _stop ) return false; + + if((*it)=="." || (*it)=="..") + { + continue; + } + + QString subDir=relDir+(*it)+"/"; + if(!_dirWatch->contains(baseDir+subDir)) + { + _dirWatch->addDir(baseDir+subDir); + } + + bool otherHasFiles=true; + + CatManListItem* item = _dirList[subDir]; + if(!item && !_stop) + { + item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir); + _dirList.insert(subDir,item); + + otherHasFiles=false; + } + + if( _stop ) return false; + + // recursive call + if(!buildDir(baseDir,subDir,extension,fast) && !otherHasFiles) + { + kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl; + deleteDirItem(subDir); + item=0; + } + else + havePoFiles=true; + + } // end looking up directories in po base dir + + return havePoFiles; +} + + +void CatalogManagerView::updateDir(QString relDir) +{ + if( _stop ) return; + + kdDebug(KBABEL_CATMAN) << "updating dir " << relDir << endl; + + bool havePoFiles=false; + + CatManListItem* thisItem=_dirList[relDir]; + if(!thisItem) + { + kdFatal(KBABEL_CATMAN) << "null pointer to this item" << endl; + return; + } + + QStringList contentList = thisItem->contentsList(true); + + const QString poBaseDir=_settings.poBaseDir; + const QString potBaseDir=_settings.potBaseDir; + + // first lookup template directory + QDir dir(potBaseDir+relDir); + QStringList entryList=dir.entryList("*.pot",QDir::Files,QDir::Name); + + QStringList::const_iterator it; + + for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it ) + { + if( _stop ) return; + + havePoFiles=true; + + QString file=relDir+(*it); + file.remove(QRegExp(".pot$")); + CatManListItem* item = _fileList[file]; + if(!item) + { + item = new CatManListItem(this, thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file); + _fileList.insert(file,item); + + if(_markerList.contains(file)) + { + item->setMarked(true); + } + + item->checkUpdate(); + } + else + { + item->checkUpdate(); + } + + contentList.remove(file); + } + + entryList=dir.entryList(QDir::Dirs,QDir::Name); + + for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it ) + { + if( _stop ) return; + + if((*it)=="." || (*it)=="..") + { + continue; + } + + bool newDirAdded=false; + + QString subDir=relDir+(*it)+"/"; + if(!_dirWatch->contains(potBaseDir+subDir)) + { + _dirWatch->addDir(potBaseDir+subDir); + + newDirAdded=true; + } + + CatManListItem* item = _dirList[subDir]; + if(!item && newDirAdded) + { + item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir); + _dirList.insert(subDir,item); + + if(!buildDir(subDir,false)) + { + kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl; + deleteDirItem(subDir); + item=0; + } + } + else if(newDirAdded) + { + updateDir(subDir); + } + + + // if directory was already here, but no item + // -> directory contains no files + if(item && !newDirAdded) + { + havePoFiles=true; + } + + } // end looking up directories in template dir + + // now traverse directory in poBaseDir + dir.setPath(poBaseDir+relDir); + entryList=dir.entryList("*.po",QDir::Files,QDir::Name); + + for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it ) + { + havePoFiles=true; + + if( _stop ) return; + + QString file=relDir+(*it); + file.remove(QRegExp(".po$")); + CatManListItem* item = _fileList[file]; + if(!item) + { + item = new CatManListItem(this, thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file); + _fileList.insert(file,item); + + if(_markerList.contains(file)) + { + item->setMarked(true); + } + + item->checkUpdate(); + } + else + { + item->checkUpdate(); + } + + contentList.remove(file); + } + + entryList=dir.entryList(QDir::Dirs,QDir::Name); + + for ( it = entryList.constBegin(); it != entryList.constEnd(); ++it ) + { + if( _stop ) return; + + if((*it)=="." || (*it)=="..") + { + continue; + } + + bool newDirAdded=false; + + QString subDir=relDir+(*it)+"/"; + if(!_dirWatch->contains(poBaseDir+subDir)) + { + _dirWatch->addDir(poBaseDir+subDir); + newDirAdded=true; + } + + CatManListItem* item = _dirList[subDir]; + + bool templateHasFiles=(bool)item; + + if(!item && newDirAdded) + { + item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir); + _dirList.insert(subDir,item); + + if(!buildDir(subDir,false) && !templateHasFiles) + { + kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl; + deleteDirItem(subDir); + item=0; + } + } + else if(newDirAdded) + { + updateDir(subDir); + } + + // if directory was already here, but no item + // -> directory contains no files + if(item && !newDirAdded) + { + havePoFiles=true; + } + + + } // end looking up directories in po base dir + + + // check, if something in the directory has been deleted + // but only if we traversed also the template directory + if(contentList.count()>0) + { + QStringList::const_iterator it; + for( it = contentList.constBegin(); it != contentList.constEnd(); ++it ) + { + QFileInfo po(poBaseDir+(*it)); + QFileInfo pot(potBaseDir+(*it)); + + if(!po.exists() && !pot.exists()) + { + CatManListItem* item = _fileList[(*it)]; + if(item) + { + if(item->marked()) + _markerList.remove(item->package()); + + _fileList.remove((*it)); + delete item; + } + } + } + } + + if(!havePoFiles) + { + deleteDirItem(relDir); + + // if this directory has to be removed, check, if + // the parent directory has to be removed too + const int index=relDir.findRev("/",relDir.length()-2); + if(index<0) + { + relDir="/"; + } + relDir=relDir.left(index+1); + updateDir(relDir); + } +} + +void CatalogManagerView::directoryChanged(const QString& dir) +{ + pause(true); + + QString relDir, relDirPo, relDirPot; + if(dir.startsWith(_settings.poBaseDir)) + { + relDirPo=dir.mid(_settings.poBaseDir.length()); + } + if(dir.startsWith(_settings.potBaseDir)) + { + relDirPot=dir.mid(_settings.potBaseDir.length()); + } + + if( relDirPo.isEmpty() ) + { + // use POT + relDir = relDirPot; + } + else if( relDirPot.isEmpty() ) + { + // use PO + relDir = relDirPo; + } + else + { + // both PO and POT usable, find out the correct one + if( relDirPo.left(1) == "/" ) + { + relDir = relDirPo; + } + else + { + relDir = relDirPot; + } + } + + if(relDir.right(1)!="/") + { + relDir+="/"; + } + + kdDebug(KBABEL_CATMAN) << "directory changed: " << relDir << endl; + + QFileInfo fileInfo(_settings.potBaseDir); + + CatManListItem* thisItem=_dirList[relDir]; + if(!thisItem) + { + // if this item is not in the list search for next existing parent item + QString prevRelDir; + do + { + prevRelDir=relDir; + const int index=relDir.findRev("/",relDir.length()-2); + if(index<0) + { + relDir="/"; + } + relDir=relDir.left(index+1); + + thisItem=_dirList[relDir]; + } + while(relDir!="/" && !thisItem); + + if(!thisItem) + { + kdFatal(KBABEL_CATMAN) << "null pointer to this item: " << relDir << endl; + return; + } + else + { + // if a parent item dir is found, create the needed item in this dir + // and build the tree from this item on + kdDebug(KBABEL_CATMAN) << "building dir: " << prevRelDir << endl; + CatManListItem* item = new CatManListItem(this, thisItem,_settings.poBaseDir+prevRelDir + ,_settings.potBaseDir+prevRelDir,prevRelDir); + _dirList.insert(prevRelDir,item); + + + if(!buildDir(prevRelDir,false)) + { + deleteDirItem(prevRelDir); + } + } + } + else + { + updateDir(relDir); + } + + pause(false); +} + + +void CatalogManagerView::directoryDeleted(const QString& dir) +{ + pause(true); + + QString relDir, relDirPo, relDirPot; + if(dir.startsWith(_settings.poBaseDir)) + { + relDirPo=dir.mid(_settings.poBaseDir.length()); + } + if(dir.startsWith(_settings.potBaseDir)) + { + relDirPot=dir.mid(_settings.potBaseDir.length()); + } + + if( relDirPo.isEmpty() ) + { + // use POT + relDir = relDirPot; + } + else if( relDirPot.isEmpty() ) + { + // use PO + relDir = relDirPo; + } + else + { + // both PO and POT usable, find out the correct one + if( relDirPo.left(1) == "/" ) + { + relDir = relDirPo; + } + else + { + relDir = relDirPot; + } + } + + if(relDir.right(1)!="/") + { + relDir+="/"; + } + + kdDebug(KBABEL_CATMAN) << "directory deleted: " << relDir << endl; + + CatManListItem* thisItem=_dirList[relDir]; + if(thisItem) + { + // we have to take care, if one directory still exists + const bool poDeleted=!thisItem->hasPo(); + const bool potDeleted=!thisItem->hasPot(); + + // if neither the po- nor the pot-directory exists any more + // delete all sub items + if(poDeleted && potDeleted) + { + deleteDirItem(relDir); + } + else + { + QStringList childList = thisItem->contentsList(); + + CatManListItem* item; + QStringList::const_iterator it; + for( it = childList.constBegin();it != childList.constEnd(); ++it ) + { + item=_fileList[(*it)]; + if(item) + { + if( (poDeleted && !item->hasPot()) || + (potDeleted && !item->hasPo()) ) + { + _fileList.remove((*it)); + delete item; + } + else + { + item->checkUpdate(); + } + } + else + { + item=_dirList[(*it)]; + if(item) + { + if( (poDeleted && !item->hasPot()) || + (potDeleted && !item->hasPo()) ) + { + deleteDirItem((*it)); + } + } + else + { + kdDebug(KBABEL_CATMAN) << "directoryDeleted: don't have item " + << (*it) << endl; + } + } + } + } + } + + pause(false); +} + +void CatalogManagerView::fileInfoRead( QString filename ) +{ + if( _readInfoFileList.find( filename ) != _readInfoFileList.end() ) { + emit progress( ++_readInfoCount); + _readInfoFileList.remove( filename ); + } + + if( _readInfoFileList.isEmpty() ) emit clearProgressBar(); +} + +void CatalogManagerView::setSettings(CatManSettings newSettings) +{ + CatManSettings oldSettings=_settings; + _settings=newSettings; + + if(_settings.poBaseDir.right(1)=="/") + _settings.poBaseDir.truncate(_settings.poBaseDir.length()-1); + if(_settings.potBaseDir.right(1)=="/") + _settings.potBaseDir.truncate(_settings.potBaseDir.length()-1); + + _dirCommandsMenu->clear(); + int counter=0; + for ( QStringList::const_iterator it = _settings.dirCommandNames.constBegin() + ; it != _settings.dirCommandNames.constEnd(); ++it ) + { + _dirCommandsMenu->insertItem((*it),counter); + counter++; + } + _dirCommandsMenu->insertSeparator(); + _dirCommandsMenu->insertItem(i18n("Log Window"),this,SLOT(showLog())); + + _fileCommandsMenu->clear(); + counter=0; + for ( QStringList::const_iterator it = _settings.fileCommandNames.constBegin() + ; it != _settings.fileCommandNames.constEnd(); ++it ) + { + _fileCommandsMenu->insertItem((*it),counter); + counter++; + } + _fileCommandsMenu->insertSeparator(); + _fileCommandsMenu->insertItem(i18n("Log Window"),this,SLOT(showLog())); + + const bool pathChanged = (oldSettings.poBaseDir!=_settings.poBaseDir) + || (oldSettings.potBaseDir!=_settings.potBaseDir); + + if(pathChanged) + { + if( !isActive() ) { + QTimer::singleShot(100,this,SLOT(buildTree())); + } else { + stop(); + connect( this, SIGNAL( updateFinished() ), this, SLOT(buildTree() ) ); + } + } + + toggleColumn( COL_MARKER, _settings.flagColumn ); + toggleColumn( COL_FUZZY, _settings.fuzzyColumn ); + toggleColumn( COL_UNTRANS, _settings.untranslatedColumn ); + toggleColumn( COL_TOTAL, _settings.totalColumn ); + // FIXME: follow CVS/SVN status + toggleColumn( COL_CVS_OR_SVN, _settings.cvsColumn ); + toggleColumn( COL_REVISION, _settings.revisionColumn ); + toggleColumn( COL_TRANSLATOR, _settings.translatorColumn ); +} + + +CatManSettings CatalogManagerView::settings() const +{ + return _settings; +} + + +void CatalogManagerView::hideEvent(QHideEvent*) +{ + pause(true); + + if(_dirWatch) + _dirWatch->stopScan(); +} + +void CatalogManagerView::showEvent(QShowEvent*) +{ + QTimer::singleShot(1,this,SLOT(checkUpdate())); + + pause(false); + + if(_dirWatch) + _dirWatch->startScan(true); +} + +void CatalogManagerView::contentsMousePressEvent(QMouseEvent* event) +{ + if(event->button() == LeftButton) + _pressPos=event->pos(); + + QListView::contentsMousePressEvent( event ); +} + +void CatalogManagerView::contentsMouseMoveEvent(QMouseEvent* event) +{ + if(event->state() & LeftButton) + { + const int delay = KGlobalSettings::dndEventDelay(); + if(QABS( event->pos().x() - _pressPos.x() ) >= delay || + QABS( event->pos().y() - _pressPos.y() ) >= delay) + { + CatManListItem* item = (CatManListItem*)itemAt(contentsToViewport(_pressPos)); + if(item && item->isFile()) + { + // always add the po-file and if existing the pot-file to the drag and + // let the user decide what to do, when dropping into kbabel + QStrList uri; + uri.append(QUriDrag::localFileToUri(item->poFile())); + if(item->hasPot()) + uri.append(QUriDrag::localFileToUri(item->potFile())); + + QUriDrag* drag = new QUriDrag(uri,this); + QPixmap icon=KGlobal::iconLoader()->loadIcon("txt",KIcon::Desktop); + drag->setPixmap(icon,QPoint(icon.width()/2,icon.height()/2)); + drag->drag(); + } + else + { + QListView::contentsMouseMoveEvent(event); + } + } + else + { + QListView::contentsMouseMoveEvent(event); + } + } + else + { + QListView::contentsMouseMoveEvent(event); + } +} + +void CatalogManagerView::readMarker( KConfig* config) +{ + KConfigGroupSaver cs(config,"CatalogManager"); + + _markerList = config->readListEntry("Marker"); +} + +void CatalogManagerView::saveMarker( KConfig* config) const +{ + KConfigGroupSaver cs(config,"CatalogManager"); + + config->writeEntry("Marker",_markerList); + config->sync(); +} + + +void CatalogManagerView::deleteDirItem(QString relDir) +{ + CatManListItem* thisItem=_dirList[relDir]; + + if(!thisItem) + return; + + _dirList.remove(relDir); + + QStringList childList = thisItem->allChildrenList(); + + QStringList::const_iterator it; + for( it = childList.constBegin();it != childList.constEnd(); ++it ) + { + if(!_fileList.remove((*it))) + _dirList.remove((*it)); + } + + + // delete the item with all sub item + delete thisItem; +} + + + +void CatalogManagerView::processEnded(KProcess* proc) +{ + _pendingProcesses.removeRef(proc); +} + + +void CatalogManagerView::showOutput(KProcess*, char *buffer, int buflen) +{ + const QCString output(buffer,buflen+1); + + _logView->insert(output); +} + +void CatalogManagerView::columnClicked(QListViewItem * item, const QPoint &, int c) +{ + if( item && c == COL_MARKER ) + { + slotToggleMark(); + } +} + +CatManListItem *CatalogManagerView::itemBelow( CatManListItem *item ) +{ + if( item->isDir() ) + { + if( item->firstChild() ) + return static_cast<CatManListItem *>( item->firstChild() ); + else + { + while( !static_cast<CatManListItem *>( item->nextSibling() ) ) + { + item = static_cast<CatManListItem *>( item->parent() ); + if( !item ) return item; + } + return static_cast<CatManListItem *>( item->nextSibling() ); + } + } + else + { + while( !static_cast<CatManListItem *>( item->nextSibling() ) ) + { + item = static_cast<CatManListItem *>( item->parent()); + if( !item ) return item; + } + return static_cast<CatManListItem *>( item->nextSibling() ); + } +} + +CatManListItem *CatalogManagerView::itemAbove( CatManListItem *item ) +{ + if( item->isDir() ) + { + if( item->firstChild() ) + return static_cast<CatManListItem *>( item->lastChild() ); + else + { + while( !static_cast<CatManListItem *>( item->previousSibling() ) ) + { + item = static_cast<CatManListItem *>( item->parent() ); + if( !item ) return item; + } + return static_cast<CatManListItem *>( item->previousSibling() ); + } + } + else + { + while( !static_cast<CatManListItem *>( item->previousSibling() ) ) + { + item = static_cast<CatManListItem *>( item->parent()); + if( !item ) return item; + } + return static_cast<CatManListItem *>( item->previousSibling() ); + } +} + +void CatalogManagerView::gotoNextUntranslated() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( ( i = itemBelow(current)) ) + { + if( i->untranslated() > 0 ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoPreviousUntranslated() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( (i = itemAbove(current)) ) + { + if( i->untranslated() > 0 ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoNextFuzzy() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( ( i = itemBelow(current)) ) + { + if( i->fuzzy() > 0 ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoPreviousFuzzy() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( (i = itemAbove(current)) ) + { + if( i->fuzzy() > 0 ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoNextFuzzyOrUntranslated() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( ( i = itemBelow(current)) ) + { + if( i->untranslated() > 0 || i->fuzzy() > 0 ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoPreviousFuzzyOrUntranslated() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( (i = itemAbove(current)) ) + { + if( i->untranslated() > 0 || i->fuzzy() > 0 ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoNextError() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( ( i = itemBelow(current)) ) + { + if( i->hasErrors() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoPreviousError() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( (i = itemAbove(current)) ) + { + if( i->hasErrors() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoNextTemplate() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( ( i = itemBelow(current)) ) + { + if( i->hasPot() && !i->hasPo() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoPreviousTemplate() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( (i = itemAbove(current)) ) + { + if( i->hasPot() && !i->hasPo() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoNextPo() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( ( i = itemBelow(current)) ) + { + if( i->hasPo() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoPreviousPo() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( (i = itemAbove(current)) ) + { + if( i->hasPo() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoNextMarked() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( ( i = itemBelow(current)) ) + { + if( i->marked() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +void CatalogManagerView::gotoPreviousMarked() +{ + CatManListItem *i; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + while( (i = itemAbove(current)) ) + { + if( i->marked() ) + { + setCurrentItem(i); + ensureItemVisible(i); + return; + } else current = i; + } +} + +QStringList CatalogManagerView::current() +{ + QStringList result; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + if( current->isDir() ) + { + QStringList s = current->allChildrenList(true); + QStringList::const_iterator it; + for( it = s.constBegin() ; it != s.constEnd(); ++it ) + { + CatManListItem *item = _fileList[(*it)]; + result.append( item->poFile() ); + } + } + else + { + if( current->hasPo() ) result.append( current->poFile() ); + } + return result; +} + +QStringList CatalogManagerView::marked() +{ + QStringList result; + + QStringList::const_iterator it; + for( it = _markerList.constBegin() ; it != _markerList.constEnd(); ++it ) + { + CatManListItem *item = _fileList[(*it)]; + result.append( item->poFile() ); + } + return result; +} + +void CatalogManagerView::updateCurrent() +{ + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + if( !current->hasPo() && !current->hasPot() ) + { + if( current->isFile() ) + { + _fileList.remove(current->package()); + delete current; + } + else + { + directoryDeleted(current->package()); + } + } + else + { + if( current->isDir() ) + { + directoryChanged(current->poFile() ); + } + + // check, if the item didn't get lost by the update in directoryChanged() + CatManListItem *new_current = static_cast<CatManListItem *>(currentItem()); + if (new_current == current) + { + current->forceUpdate(); + } + } +} + +void CatalogManagerView::updateFiles( const QStringList& files ) +{ + QStringList::ConstIterator it; + for ( it = files.constBegin( ); it != files.constEnd( ); ++it ) { + updateFile( *it, true ); + } +} + +CVSHandler * CatalogManagerView::cvsHandler( ) +{ + return cvshandler; +} + +SVNHandler * CatalogManagerView::svnHandler( ) +{ + return svnhandler; +} + +void CatalogManagerView::validateUsingTool( const KDataToolInfo &tool, const QString& command ) +{ + QStringList result; + CatManListItem *current = static_cast<CatManListItem *>(currentItem()); + if( current->isDir() ) + { + const QStringList s = current->allChildrenList(true); + QStringList::const_iterator it; + for( it = s.constBegin() ; it != s.constEnd(); ++it ) + { + CatManListItem *item = _fileList[(*it)]; + if( item && item->hasPo() ) result.append( item->package() ); + } + } + else + { + result.append( current->package() ); + } + + validate_internal( result, tool, command ); +} + +void CatalogManagerView::validateMarkedUsingTool( const KDataToolInfo &tool, const QString& command ) +{ + validate_internal( _markerList, tool, command ); +} + +void CatalogManagerView::validate_internal( const QStringList& files, const KDataToolInfo &tool, const QString& ) +{ + if( files.isEmpty() ) return; + + KDataTool* t = tool.createTool(); + + if( !t ) + { + KMessageBox::error( this, i18n("Cannot instantiate a validation tool.\n" + "Please check your installation."), i18n("Validation Tool Error") ); + return; + } + + // setup options + if( !_validateOptionsDlg ) + { + _validateOptionsDlg = new KDialogBase( this, "validation options", + true, i18n("Validation Options"), KDialogBase::Ok|KDialogBase::Cancel); + _validateOptions = new ValidationOptions(_validateOptionsDlg); + _validateOptionsDlg->setMainWidget( _validateOptions ); + _validateOptions->resize( _validateOptions->sizeHint() ); + + // setup stored values + _validateOptions->markAsFuzzy->setChecked( _markAsFuzzy ); + _validateOptions->ignoreFuzzy->setChecked( _ignoreFuzzy ); + } + + if( _validateOptionsDlg->exec() != QDialog::Accepted ) + { + delete t; + + return; + } + + if( !_validateDialog ) + { + _validateDialog = new ValidateProgressDialog(_settings.ignoreURL, this); + connect( _validateDialog, SIGNAL( errorDoubleClicked(const QString,const int)), + this, SLOT(showError( const QString, const int ))); + } + + _markAsFuzzy = _validateOptions->markAsFuzzy->isChecked(); + _ignoreFuzzy = _validateOptions->ignoreFuzzy->isChecked(); + + _validateDialog->setMarkAsFuzzy(_markAsFuzzy); + _validateDialog->setIgnoreFuzzy(_ignoreFuzzy); + + QPtrList<CatManListItem> fileitems; + + for( QValueListConstIterator<QString> it=files.begin() ; it!=files.end() ; ++it ) + { + CatManListItem* item=_fileList[ (*it) ]; + if( item ) { + fileitems.append(item); + } else kdDebug(KBABEL_CATMAN) << "Cannot find the file item for " << (*it) << endl; + } + + _validateDialog->validate(tool, fileitems); + + delete t; +} + +void CatalogManagerView::showError( const QString package, const int num ) +{ + CatManListItem* item = _fileList[ package]; + if( !item ) + { + kdWarning() << "Can not find error package: " << package << endl; + return; + } + + emit gotoFileEntry( item->poFile(), package, num ); +} + +void CatalogManagerView::updateMarkerList() +{ + QStringList newMarkers; + + for( QStringList::const_iterator it = _markerList.constBegin(); it != _markerList.constEnd(); ++it ) { + if( _fileList[ (*it) ] ) + newMarkers.append( (*it) ); + } + + _markerList = newMarkers; +} + +void CatalogManagerView::slotValidPOCVSRepository( bool valid ) +{ + m_validPOCVSRepository = valid; + slotToggleCVSOrSVNColumn(valid); + // set initial state for CVS menu entries + emit selectedChanged(NEEDS_PO + NEEDS_PO_CVS * m_validPOCVSRepository); +} + +void CatalogManagerView::slotValidPOSVNRepository( bool valid ) +{ + m_validPOSVNRepository = valid; + slotToggleCVSOrSVNColumn(valid); + // set initial state for SVN menu entries + emit selectedChanged(NEEDS_PO + NEEDS_PO_SVN * m_validPOSVNRepository); +} + +void CatalogManagerView::slotValidPOTCVSRepository( bool valid ) +{ + m_validPOTCVSRepository = valid; + // set initial state for CVS menu entries + // ### TODO: something missing here? +} + +void CatalogManagerView::slotValidPOTSVNRepository( bool valid ) +{ + m_validPOTSVNRepository = valid; + // set initial state for SVN menu entries + // ### TODO: something missing here? +} + +void CatalogManagerView::slotToggleCVSOrSVNColumn( bool show ) +{ +#if 0 + toggleColumn( COL_CVS_OR_SVN, show ); +#else + // ### HACK + toggleColumn( COL_CVS_OR_SVN, m_validPOCVSRepository || m_validPOSVNRepository ); + +#endif +} + +void CatalogManagerView::toggleColumn( uint column, bool show ) +{ + if ( show ) { + setColumnWidthMode( column, Maximum ); + setColumnWidth( column, -1 ); + // ensure that the column heading is always fully visible + setColumnText( column, COLTEXT(column)); + } else { + setColumnWidthMode( column, Manual ); + setColumnWidth( column, 0 ); + } +} + +#include "catalogmanagerview.moc" +// kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/kbabel/catalogmanager/catalogmanagerview.h b/kbabel/catalogmanager/catalogmanagerview.h new file mode 100644 index 00000000..e4421973 --- /dev/null +++ b/kbabel/catalogmanager/catalogmanagerview.h @@ -0,0 +1,474 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2004 by Stanislav Visnovsky <visnovsky@kde.org> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef CATALOGMANAGERVIEW_H +#define CATALOGMANAGERVIEW_H + +#include <qdict.h> +#include <qlistview.h> +#include <qdatetime.h> +#include <qtimer.h> +#include <qfileinfo.h> +#include <qguardedptr.h> + +#include <kdialogbase.h> +#include <kdirwatch.h> +#include <kprocess.h> +#include <qptrlist.h> + +#include "kbproject.h" +#include "projectsettings.h" +#include "findoptions.h" +#include "cvsresources.h" +#include "svnresources.h" + +class CatManListItem; +class QPixmap; +class QPopupMenu; +class KBabelDictBox; +class CatManPreferences; +class QTextEdit; +class KProgress; +class KConfig; +class KDataToolInfo; +class ValidateProgressDialog; +class CVSHandler; +class SVNHandler; +class MarkPatternDialog; +class ValidationOptions; + +namespace KBabel +{ + class KBabelMailer; + class PoInfo; +} + +class CatalogManagerView : public QListView +{ + Q_OBJECT +public: + CatalogManagerView(KBabel::Project::Ptr project, QWidget* parent=0, const char* name=0); + virtual ~CatalogManagerView(); + + KBabel::CatManSettings settings() const; + /** clears the tree */ + virtual void clear(); + + /** pauses the update timer */ + void pause(bool); + + /** if file fileWithPath exists in the treeview, this is updated */ + void updateFile(QString fileWithPath, bool force = false); + + void updateAfterSave(QString fileWithPath, KBabel::PoInfo &info); + + bool isActive() const {return _active;} + bool isStopped() const {return _stop;} + + void restoreView(KConfig *config); + void saveView(KConfig *config) const; + + void setRMBMenuFile( QPopupMenu *m); + void setRMBMenuDir( QPopupMenu *m); + void setDirCommandsMenu( QPopupMenu *m); + void setFileCommandsMenu( QPopupMenu *m); + + CVSHandler * cvsHandler(); + SVNHandler * svnHandler(); + +public slots: + void setSettings(KBabel::CatManSettings newSettings); + void toggleMark(); + /** + * removes all marks in directory of current item (must be a directory) + */ + void slotClearMarksInDir(); + void clearAllMarks(); + void toggleAllMarks(); + void markModifiedFiles(); + void loadMarks(); + void saveMarks(); + void slotMarkPattern( ); + void slotUnmarkPattern( ); + /** + * traverses all childs in the directory of the current item + * (including all subdirectories) and displays some statistics + * about the translations. If the item is a file, its + * parent directory is used instead. + */ + void statistics(); + /** + * traverses all marked childs in the directory of the current item + * (including all subdirectories) and displays some statistics + * about the translations. If the item is a file, its + * parent directory is used instead. + */ + void markedStatistics(); + /** + * calls @ref Msgfmt::checkSyntax, to check the po-file of + * the selected item + */ + void checkSyntax(); + + void roughTranslation(); + void markedRoughTranslation(); + + /** Send the selected item as a compressed mail attachment. If the + * selected item is a directory send the items contained in the + * directory. + */ + void mailFiles(); + /** Send the marked items as a compressed mail attachment. + */ + void mailMarkedFiles(); + + void packageFiles(); + void packageMarkedFiles(); + + void cvsUpdate( ); + void cvsUpdateMarked( ); + void cvsCommit( ); + void cvsCommitMarked( ); + void cvsStatus( ); + void cvsStatusMarked( ); + void cvsUpdateTemplate( ); + void cvsUpdateMarkedTemplate( ); + void cvsCommitTemplate( ); + void cvsCommitMarkedTemplate( ); + void cvsDiff( ); + + void svnUpdate( ); + void svnUpdateMarked( ); + void svnCommit( ); + void svnCommitMarked( ); + void svnStatusRemote(); + void svnStatusRemoteMarked(); + void svnStatusLocal(); + void svnStatusLocalMarked(); + void svnUpdateTemplate( ); + void svnUpdateMarkedTemplate( ); + void svnCommitTemplate( ); + void svnCommitMarkedTemplate( ); + void svnDiff( ); + void svnInfo(); + void svnInfoMarked(); + + QString find(KBabel::FindOptions &options, QStringList &rest); + + void showLog(); + + void stop(bool s = true); + + /** + * Stop searching, do not try to proceed to the next file + * @ref @find will return clear list of rest to be searched + * and @ref QString::null, if search string was not is the last searched file + */ + void stopSearch(); + + /** + * Information for this file has been read. If the file is in + * @ref @_readInfoFileList, it will update progress bar by emitting @ref @progress + */ + void fileInfoRead( QString file ); + + void gotoNextUntranslated(); + void gotoPreviousUntranslated(); + void gotoNextFuzzy(); + void gotoPreviousFuzzy(); + void gotoNextFuzzyOrUntranslated(); + void gotoPreviousFuzzyOrUntranslated(); + void gotoNextError(); + void gotoPreviousError(); + void gotoNextTemplate(); + void gotoPreviousTemplate(); + void gotoNextPo(); + void gotoPreviousPo(); + void gotoNextMarked(); + void gotoPreviousMarked(); + + void validateUsingTool( const KDataToolInfo &, const QString& ); + void validateMarkedUsingTool( const KDataToolInfo &, const QString& ); + + void showError( const QString package, const int num); + + void updateCurrent(); + + /** + * An update for more than one file has become necessary. For instance + * after 'cvs commit' or 'svn commit' the file contents have not changed + * but the CVS/SVN file status could have changed. + */ + void updateFiles( const QStringList& files ); + + /** + * Returns the list of all currently selected files. If current selection is dir, + * it returns list of all its children. + */ + QStringList current(); + /** + * Returns the list of all currently marked files. + */ + QStringList marked(); + +signals: + void openFile(QString filename,QString package); + void openFileInNewWindow(QString filename,QString package); + void openTemplate(QString openFilename,QString saveFileName,QString package); + void openTemplateInNewWindow(QString openFilename,QString saveFileName,QString package); + void gotoFileEntry(QString filename,QString package,int msgid); + void prepareProgressBar(QString msg,int max); + void progress(int); + void clearProgressBar(); + void prepareFindProgressBar(int max); + void signalBuildTree(bool done); + void signalSearchedFile(int count); + + void newValidationFile(QString); + void newValidationTool(QString); + void setValidationProgressBar(int); + void advanceValidationFileProgressBar(int); + void setMaxValidationProgressBar(int); + void setMaxValidationFileProgressBar(int); + + /** + * The selected item in the tree view has changed. + * This signal emits the corresponding action value for this item. + * @param actionValue Action value for the selected item. + */ + void selectedChanged(uint actionValue); + +signals: + void updateFinished(); + +protected: + /** + * builds the tree under dir relDir, but does not update any files + * this functions always traverses all subdirs + * + * @param relDir the relative dir under the po- and pot- base directories + * @param fast if true, no files will be updated + * + * @return true, if the directory contains any po or pot-files + * @see CatalogManagerView::buildDir + * @see CatalogManagerView::updateDir + */ + bool buildDir(QString relDir,bool fast=true); + + /** + * This function is traversing the real directory on the + * disc using baseDir as the + * base directory and starts at baseDir+relDir + * @param extension the extension of the files in this directory + * @param fast if true, no file will be updated + * + * @return true, if the directory contains any po or pot-files + * @see CatalogManagerView::buildDir + * @see CatalogManagerView::updateDir + */ + bool buildDir(const QString& baseDir,const QString& relDir, const QString extension,bool fast=true); + + /** + * updates dir relDir and if any new subdir is added + * builds this with @ref buildDir + * + * This function doesn't enters subdirs except when a new subdir is added. + * @see CatalogManagerView::buildDir + */ + void updateDir(QString relDir); + + /** + * stops the update timer and the dirwatch + * @see KDirWatch::stop + * @see QTimer::stop + */ + virtual void hideEvent(QHideEvent*); + /** + * restarts the update timer and the dirwatch + * @see KDirWatch::start + * @see QTimer::start + */ + virtual void showEvent(QShowEvent*); + + /** used for dragging */ + virtual void contentsMousePressEvent(QMouseEvent* e); + /** used for dragging */ + virtual void contentsMouseMoveEvent(QMouseEvent* e); + + void showStatistics( CatManListItem *i, QStringList &packages); + +protected slots: + /** rebuilds the tree*/ + void buildTree(); + /** + * recurse all visible files and updates them if necessary + * @see CatManListItem::checkUpdate + */ + void checkUpdate(); + + /** this is called from KDirWatch when a directory has changed */ + void directoryChanged(const QString& dir); + /** this is called from KDirWatch when a directory has been deleted */ + void directoryDeleted(const QString& dir); + + void showContentsMenu(QListViewItem *, const QPoint &, int col); + /** does the default action on the currently selected item*/ + void activateItem(QListViewItem *); + /** emits the state of the selected item using selectedChanged*/ + void checkSelected(); + /** calls @ref activateItem with the selected item as argument*/ + void slotOpenFile(); + void slotOpenFileInNewWindow(); + /** emits signal @ref openTemplate */ + void slotOpenTemplate(); + /** deletes the po-file on the disc, that belongs to the selected item */ + void slotDeleteFile(); + /** toggles the mark of the selected item */ + void slotToggleMark(); + /** + * toggles all marks in directory of current item (must be a directory) + */ + void slotToggleMarksInDir(); + void slotDirCommand(int); + void slotFileCommand(int); + +private slots: + void showOutput(KProcess *proc, char *buffer, int buflen); + void processEnded(KProcess *proc); + void columnClicked(QListViewItem * item, const QPoint & pnt, int c); + + void slotToggleCVSOrSVNColumn( bool ); + + void slotValidPOCVSRepository( bool ); + void slotValidPOSVNRepository( bool ); + void slotValidPOTCVSRepository( bool ); + void slotValidPOTSVNRepository( bool ); + +private: + void toggleColumn( uint id, bool show); + + void readMarker(KConfig *config); + void saveMarker(KConfig *config) const; + /** + * remove marked entries, which are not in the current file list + */ + void updateMarkerList(); + + /** + * Mark or unmark entries. + * + * @param mark If true the items are marked, if false the marks are removed. + */ + void setPatternMarks(bool mark); + + /** + * deletes item with package name (relative directory) relDir + * and makes sure, that all subitems are removed from the lists + */ + void deleteDirItem(QString relDir); + + bool hasMatchingWords( QStringList &itemWords, QStringList &searchWords); + + CatManListItem *itemBelow( CatManListItem *item ); + CatManListItem *itemAbove( CatManListItem *item ); + + void validate_internal( const QStringList&, const KDataToolInfo &, const QString& ); + + void doCVSCommand( CVS::Command cmd, bool marked = false, bool templates = false ); + void doSVNCommand( SVN::Command cmd, bool marked = false, bool templates = false ); + +private: + QDict<CatManListItem> _dirList; + QDict<CatManListItem> _fileList; + + KDirWatch *_dirWatch; + QTimer *_updateTimer; + + // list of files for which was calculated the progress bar for reading file info + QStringList _readInfoFileList; + // current count of already read files in @ref @_readInfoFileList. + int _readInfoCount; + + KBabel::CatManSettings _settings; + + QStringList _markerList; + + bool _active; + // stopping, application quit + bool _stop; + // stop searching, do not proceed to the next file + bool _stopSearch; + int _updateNesting; + + QPtrList<KProcess> _pendingProcesses; + + QTextEdit* _logView; + KDialogBase* _logWindow; + QPopupMenu* _fileContentsMenu; + QPopupMenu* _dirContentsMenu; + QPopupMenu* _dirCommandsMenu; + QPopupMenu* _fileCommandsMenu; + + /** used for starting a drag */ + QPoint _pressPos; + + KBabelDictBox* _dictBox; + + KBabel::KBabelMailer* mailer; + + CVSHandler* cvshandler; + SVNHandler* svnhandler; + + /// Is the PO path a valid CVS repository? + bool m_validPOCVSRepository; + /// Is the POT path a valid CVS repository? + bool m_validPOTCVSRepository; + /// Is the PO path a valid SVN repository? + bool m_validPOSVNRepository; + /// Is the POT path a valid SVN repository? + bool m_validPOTSVNRepository; + + MarkPatternDialog * markPatternDialog; + + //validation + ValidateProgressDialog* _validateDialog; + ValidationOptions* _validateOptions; + KDialogBase* _validateOptionsDlg; + bool _markAsFuzzy; + bool _ignoreFuzzy; + + KBabel::Project::Ptr _project; +}; + +#endif // CATALOGMANAGERVIEW_H diff --git a/kbabel/catalogmanager/catmanlistitem.cpp b/kbabel/catalogmanager/catmanlistitem.cpp new file mode 100644 index 00000000..249cb053 --- /dev/null +++ b/kbabel/catalogmanager/catmanlistitem.cpp @@ -0,0 +1,932 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2003 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + +#include "catmanresource.h" +#include "catmanlistitem.h" +#include "catalogmanagerview.h" +#include "catalog.h" + +#include "resources.h" + +#include <klocale.h> + +#include <qfileinfo.h> +#include <qdir.h> +#include <qbitmap.h> +#include <qlabel.h> +#include <qpainter.h> + +#include <cvshandler.h> +#include <svnhandler.h> + +using namespace KBabel; + +CatManListItem::CatManListItem(CatalogManagerView *view, QListViewItem* parent,QString fullPath,QString fullPotPath,QString package) + : QListViewItem(parent) +{ + _view = view; + init(fullPath,fullPotPath,package); +} + +CatManListItem::CatManListItem(CatalogManagerView *view, QListView* parent,QString fullPath,QString fullPotPath) + : QListViewItem(parent) +{ + _primary=QFileInfo(fullPath); + _template=QFileInfo(fullPotPath); + _package="/"; + _type=Dir; + _marked=false; + _view = view; + + _hasPo=false; + _hasPot=false; + _hasErrors=false; + + _primary.setCaching(false); + _template.setCaching(false); + + setText(COL_NAME,i18n("Message Catalogs")); + setPixmap(COL_NAME,ICON_FOLDER_CLOSED_OK); +} + + +void CatManListItem::init(const QString& fullPath, const QString& fullPotPath, const QString& package) +{ + _primary=QFileInfo(fullPath); + _template=QFileInfo(fullPotPath); + _package=package; + _marked=false; + + _hasPo=false; + _hasPot=false; + _hasErrors=false; + + _primary.setCaching(false); + _template.setCaching(false); + + // set + _lastUpdated=QDate(1900,1,1); + + _wordList.clear(); + _wordListUpdated = false; + + update(parent()->isOpen(),false,true); + + if( !isDir() ) setPixmap(COL_MARKER,ICON_NOFLAG); +} + +void CatManListItem::setMarked(bool on) +{ + if(on) + { + setPixmap(COL_MARKER,ICON_FLAG); + } + else + { + setPixmap(COL_MARKER,ICON_NOFLAG); + } + + _marked=on; +} + +bool CatManListItem::marked() const +{ + if( isFile() ) return _marked; + else if( isDir() ) + { + CatManListItem * myChild = (CatManListItem*)firstChild(); + while( myChild ) + { + if(myChild->isFile() && myChild->marked() ) return true; + else if(myChild->isDir() && myChild->marked() ) return true; + myChild = (CatManListItem*)myChild->nextSibling(); + } + + } + return false; +} + +void CatManListItem::setOpen(bool open) +{ + bool needWork = needsWork(); + QListViewItem::setOpen(open); + + if(open && _type==Dir) + { + QPixmap icon; + icon = needWork ? ICON_FOLDER_OPEN_WORK : ICON_FOLDER_OPEN_OK; + + if(!_template.exists()) + { + icon=paintExclamation(&icon); + } + + setPixmap(COL_NAME,icon); + + CatManListItem * myChild = (CatManListItem*)firstChild(); + while( myChild ) + { + myChild->checkUpdate(); + myChild = (CatManListItem*)myChild->nextSibling(); + } + } + else + { + QPixmap icon; + + if(needsWork()) + icon = ICON_FOLDER_CLOSED_WORK; + else + icon = ICON_FOLDER_CLOSED_OK; + + if(!_template.exists()) + { + icon=paintExclamation(&icon); + } + + setPixmap(COL_NAME,icon); + } + +} + +QStringList CatManListItem::allChildrenList(bool onlyFiles) const +{ + QStringList childrenList; + + CatManListItem * myChild = (CatManListItem*)firstChild(); + while( myChild ) + { + QString name=myChild->package(); + + if(myChild->isFile()) + { + childrenList.append(name); + } + else if(myChild->isDir()) + { + if(!onlyFiles) + childrenList.append(name); + + childrenList+=myChild->allChildrenList(onlyFiles); + } + + myChild = (CatManListItem*)myChild->nextSibling(); + } + + return childrenList; +} + + +QStringList CatManListItem::allChildrenFileList(bool onlyFiles, bool emptyDirs, bool onlyModified) const +{ + QStringList childrenList; + + CatManListItem * myChild = (CatManListItem*)firstChild(); + while( myChild ) + { + if(myChild->isFile() && myChild->hasPo() && + !(!myChild->isModified() && onlyModified)) + { + childrenList.append(myChild->poFile()); + } + else if(myChild->isDir()) + { + if(!onlyFiles && (emptyDirs || myChild->_primary.exists() )) + { + childrenList.append(myChild->poFile()); + } + + childrenList+=myChild->allChildrenFileList(onlyFiles,false,onlyModified); + } + + myChild = (CatManListItem*)myChild->nextSibling(); + } + + return childrenList; +} + + +QStringList CatManListItem::contentsList(bool onlyFiles) const +{ + QStringList childList; + + CatManListItem * myChild = (CatManListItem*)firstChild(); + while( myChild ) + { + QString name=myChild->package(); + + if(onlyFiles) + { + if(myChild->isFile()) + { + childList.append(name); + } + } + else + { + childList.append(name); + } + + myChild = (CatManListItem*)myChild->nextSibling(); + } + + return childList; +} + + +void CatManListItem::forceUpdate() +{ + update(true,true,false); +} + +void CatManListItem::checkUpdate(bool noParents) +{ + // if a file has disappeared or is new + if(_hasPo != hasPo() || _hasPot != hasPot()) + { + update(true,false,noParents); + } + else if(!isFile()) + { + update(true,false,noParents); + } + else if(_hasPo && _lastUpdated < _primary.lastModified()) + { + update(true,false,noParents); + } + else if(_hasPot && _lastUpdated < _template.lastModified()) + { + update(true,false,noParents); + } +} + +QString CatManListItem::key(int col, bool) const +{ + // show directories first + QString key=text(col); + + if(col==COL_NAME) + { + if(_type==Dir) + { + key="a"+key; + } + else + { + key="b"+key; + } + } + // fuzzy, untranslated, total + else if(col==COL_FUZZY || col ==COL_TOTAL || col==COL_UNTRANS) + { + key=key.rightJustify(10,'0'); + } + // marked po's + else if(col==COL_MARKER) + { + if(_marked) + { + key="1"; + } + else + { + key="0"; + } + } + + return key; +} + +void CatManListItem::update(bool showPoInfo,bool includeChildren + , bool noParents) +{ + if( _view->isStopped() ) return; // if parent view is stopped, we should stop as well + + bool updateWordList = _view->settings().indexWords; + + // flag, if something has changed and parent has to be updated + bool updateParent=false; + + // update flags for files... + const bool hadPo=_hasPo; + _hasPo = hasPo(); + const bool hadPot = _hasPot; + _hasPot = hasPot(); + + // and check if something changed + if(hadPo != _hasPo || hadPot != _hasPot) + updateParent=true; + + + if(_package!="/") // don't update root item + { + if(_primary.exists()) + { + if(_primary.isDir()) + { + QDir dir=_primary.dir(); + setText(COL_NAME,dir.dirName()); + + // count the childen numbers + int fuzzy = 0; + int untrans = 0; + int total = 0; + + CatManListItem* ch = static_cast<CatManListItem*>(firstChild ()); + + while (ch) + { + fuzzy += ch->fuzzy (); + untrans += ch->untranslated (); + total += ch->total (); + ch = static_cast<CatManListItem*>(ch->nextSibling()); + } + + setText(COL_FUZZY,QString::number(fuzzy)); + setText(COL_UNTRANS,QString::number(untrans)); + setText(COL_TOTAL,QString::number(total)); + + //setSelectable(false); + _type=Dir; + + bool needWork = needsWork(); + QPixmap icon; + if(!isOpen()) + { + if( needWork ) + icon = ICON_FOLDER_CLOSED_WORK; + else + icon = ICON_FOLDER_CLOSED_OK; + } + else + { + icon = needWork ? ICON_FOLDER_OPEN_WORK : ICON_FOLDER_OPEN_OK; + } + + // check if the same directory exists also in the + // template directory + if(_template.isDir()) + { + setPixmap( COL_NAME, icon ); + } + else + { + QPixmap folder = icon; + icon=paintExclamation(&folder); + + setPixmap(COL_NAME,folder); + } + } + else // primary is file + { + _type=File; + QString name=_primary.fileName(); + setText(COL_NAME,name.left(name.length()-3)); + + if(showPoInfo) + { + _lastUpdated=QDateTime::currentDateTime(); + + bool neededWork=needsWork(); + bool needWork=false; + + PoInfo poInfo; + QPixmap icon = ICON_UPDATING; + setPixmap(COL_NAME,icon); + if ( PoInfo::info( _primary.absFilePath(), poInfo, _wordList, updateWordList, true, true ) == OK ) + { + if( _view->isStopped() ) return; + if( updateWordList) _wordListUpdated = true; + + _hasErrors=false; + + const CVSHandler* cvsHandler = _view->cvsHandler(); + const SVNHandler* svnHandler = _view->svnHandler(); + + const CVSHandler::FileStatus cvsFileStatus = cvsHandler->fstatus( poFile() ); + const SVNHandler::FileStatus svnFileStatus = svnHandler->fstatus( poFile() ); + + _isModified = cvsHandler->isConsideredModified( cvsFileStatus ) + || svnHandler->isConsideredModified( svnFileStatus ); + + QString versionControl; + if ( cvsFileStatus != CVSHandler::NO_REPOSITORY ) + versionControl = cvsHandler->fileStatus( cvsFileStatus ); + else if ( svnFileStatus != SVNHandler::NO_REPOSITORY ) + versionControl = svnHandler->fileStatus( svnFileStatus ); + else + versionControl = i18n("No version control"); + + setText(COL_FUZZY,QString::number(poInfo.fuzzy)); + setText(COL_UNTRANS,QString::number(poInfo.untranslated)); + setText(COL_TOTAL,QString::number(poInfo.total)); + setText( COL_CVS_OR_SVN, versionControl ); + setText(COL_REVISION,poInfo.revision); + setText(COL_TRANSLATOR,poInfo.lastTranslator); + + if(needsWork()) + { + icon=ICON_NEEDWORK; + needWork = true; + } + else + { + icon = ICON_OK; + needWork=false; + } + } + else + { + kdDebug(KBABEL_CATMAN) << "This file is broken" << endl; + if( _view->isStopped() ) return; + _hasErrors=true; + icon = ICON_BROKEN; + needWork=true; + } + + if(!_template.exists()) + { + icon=paintExclamation(&icon); + } + + setPixmap(COL_NAME,icon); + + updateParent=true; + } + } + } + // only the template exists + else if(_template.exists()) + { + if(_template.isDir()) + { + QDir dir=_template.dir(); + setText(COL_NAME,dir.dirName()); + //setSelectable(false); + _type=Dir; + + // count the childen numbers + int total = 0; + + CatManListItem* ch = static_cast<CatManListItem*>(firstChild ()); + + while (ch) + { + total += ch->total (); + ch = static_cast<CatManListItem*>(ch->nextSibling()); + } + + setText(COL_TOTAL,QString::number(total)); + + + QPixmap icon; + if(!isOpen()) + { + icon = ICON_FOLDER_CLOSED_WORK; + } + else + { + icon = needsWork() ? ICON_FOLDER_OPEN_WORK : ICON_FOLDER_OPEN_OK; + } + + setPixmap(COL_NAME, icon ); + } + // item is file + else + { + _type=File; + QString name=_primary.fileName(); + setText(COL_NAME,name.left(name.length()-3)); + + if(showPoInfo) + { + _lastUpdated=QDateTime::currentDateTime(); + + // clean previous state information + setText(COL_FUZZY,QString::null); + setText(COL_UNTRANS,QString::null); + setText(COL_TOTAL,QString::null); + setText(COL_CVS_OR_SVN, QString::null); + setText(COL_REVISION, QString::null); + setText(COL_TRANSLATOR, QString::null); + + setPixmap(COL_NAME,ICON_UPDATING); + + PoInfo poInfo; + if ( PoInfo::info( _template.absFilePath(), poInfo, _wordList, false, true, true ) == OK ) + { + if( _view->isStopped() ) return; + setText(COL_TOTAL,QString::number(poInfo.total)); + } + if( _view->isStopped() ) return; + } + setPixmap(COL_NAME,ICON_MISSING); + + updateParent = true; + } + } + else + { + kdWarning(KBABEL_CATMAN) << "whether po nor pot exists: " << _package << endl; + } + } + + _view->fileInfoRead( package() ); + + if( _view->isStopped() ) return; + + if(updateParent && !noParents) + { + updateParents(); + } + + if( _view->isStopped() ) return; + + if(includeChildren) + { + CatManListItem *myChild = (CatManListItem*)firstChild(); + while( myChild ) + { + myChild->update(showPoInfo,includeChildren); + myChild = (CatManListItem*)myChild->nextSibling(); + } + } + + // HACK to get the signal emitted + if (isSelected( )) { + listView( )->setSelected(this, false); + listView( )->setSelected(this, true); + } +} + +// we know that this item was saved and PoInfo contains new information +// about this item, the item is file +// however, is can be saved template or translation!!! - only translation is handled??? +void CatManListItem::updateAfterSave( PoInfo &poInfo ) +{ + // flag, if something has changed and parent has to be updated + bool updateParent=false; + + // update flags for files... + const bool hadPo=_hasPo; + _hasPo = hasPo(); + const bool hadPot = _hasPot; + _hasPot = hasPot(); + + // and check if something changed + if(hadPo != _hasPo || hadPot != _hasPot) + updateParent=true; + + if(_primary.exists()) + { + // primary is existent file + + _type=File; + QString name=_primary.fileName(); + setText(COL_NAME,name.left(name.length()-3)); + + _lastUpdated=QDateTime::currentDateTime(); + + bool neededWork=needsWork(); + bool needWork=false; + + QPixmap icon; + _hasErrors=false; + + const CVSHandler::FileStatus cvsFileStatus = _view->cvsHandler()->fstatus(poFile()); + const SVNHandler::FileStatus svnFileStatus = _view->svnHandler()->fstatus(poFile()); + + QString versionControl; + if ( cvsFileStatus != CVSHandler::NO_REPOSITORY ) + versionControl = _view->cvsHandler()->fileStatus( cvsFileStatus ); + else if ( svnFileStatus != SVNHandler::NO_REPOSITORY ) + versionControl = _view->svnHandler()->fileStatus( svnFileStatus ); + else + versionControl = i18n("No version control"); + + setText(COL_FUZZY,QString::number(poInfo.fuzzy)); + setText(COL_UNTRANS,QString::number(poInfo.untranslated)); + setText(COL_TOTAL,QString::number(poInfo.total)); + setText( COL_CVS_OR_SVN, versionControl ); + setText(COL_REVISION,poInfo.revision); + setText(COL_TRANSLATOR,poInfo.lastTranslator); + + if(needsWork()) + { + icon=ICON_NEEDWORK; + needWork = true; + } + else + { + icon = ICON_OK; + needWork=false; + } + + if(!_template.exists()) + { + icon=paintExclamation(&icon); + } + + setPixmap(COL_NAME,icon); + + // if the status changed, update the parent item + if(needWork != neededWork) + { + updateParent=true; + } + } + + if(updateParent) + { + updateParents(); + } +} + + +void CatManListItem::updateParents() +{ + CatManListItem *item = (CatManListItem*)parent(); + while( item && !_view->isStopped()) + { + item->update(false,false); + item = (CatManListItem*)item->parent(); + } +} + +bool CatManListItem::hasPo() const +{ + return _primary.exists(); +} + +bool CatManListItem::hasPot() const +{ + return _template.exists(); +} + +bool CatManListItem::isModified() const +{ + return _isModified; +} + +int CatManListItem::fuzzy() const +{ + bool success; + int number=text(COL_FUZZY).toInt(&success); + if(!success) + number=0; + + return number; +} + +int CatManListItem::untranslated() const +{ + bool success; + int number; + if( !hasPo() ) + { + number=total(); + } + else + { + number=text(COL_UNTRANS).toInt(&success); + if(!success) + number=0; + } + + return number; +} + +int CatManListItem::total() const +{ + bool success; + int number=text(COL_TOTAL).toInt(&success); + if(!success) + number=0; + + return number; +} + +bool CatManListItem::needsWork() const +{ + bool flag=false; + + if(isFile()) + { + if(!hasPo() || fuzzy() > 0 || untranslated() > 0 || _hasErrors) + flag=true; + } + else + { + CatManListItem *myChild = (CatManListItem*)firstChild(); + while( myChild ) + { + if( myChild->needsWork() ) + { + flag=true; + myChild=0; + } + else + { + myChild = (CatManListItem*)myChild->nextSibling(); + } + } + } + + return flag; +} + +bool CatManListItem::isDir() const +{ + return type()==Dir; +} + +bool CatManListItem::isFile() const +{ + return type()==File; +} + +QString CatManListItem::poFile() const +{ + return _primary.absFilePath(); +} + +QString CatManListItem::potFile() const +{ + return _template.absFilePath(); +} + +QString CatManListItem::package(bool rootSlash) const +{ + if(rootSlash) + return _package; + else + { + return _package.right(_package.length()-1); + } +} + +QString CatManListItem::packageDir( ) const +{ + return ( _type == Dir ? _package : QString::null ); +} + +QString CatManListItem::name() const +{ + int index = _package.findRev("/"); + return _package.right(_package.length()-index-1); +} + +QPixmap CatManListItem::paintExclamation(QPixmap* pixmap) +{ + if(!pixmap || pixmap->isNull()) + return QPixmap(0,0); + + if(_package=="/" && _template.filePath().isEmpty()) + return *pixmap; + + if(isDir() && _package == _template.filePath()) + return *pixmap; + + if(isFile() && _package+".pot" == _template.filePath()) + return *pixmap; + + int width=pixmap->width(); + int height=pixmap->height(); + + int diameter=QMIN(width,height); + + QBitmap mask=pixmap->createHeuristicMask(); + + QPainter mp(&mask); + mp.setPen(QPen(Qt::color1,1)); + mp.drawEllipse(width-diameter,height-diameter,diameter,diameter); + + QPixmap result(width,height); + + QPainter p(&result); + p.drawPixmap(0,0,*pixmap); + p.setPen( QPen(red,1) ); + p.drawEllipse(width-diameter,height-diameter,diameter,diameter); + + result.setMask(mask); + + return result; +} + +QListViewItem *CatManListItem::previousSibling() +{ + QListViewItem * i = parent(); + if( !i ) return i; + i = i->firstChild(); + if( !i ) return i; + if( i == this ) return 0; + while( i->nextSibling()!=this ) i = i->nextSibling(); + return i; +} + +QListViewItem *CatManListItem::lastChild() +{ + QListViewItem * i = firstChild(); + if( !i ) return i; + while( i->nextSibling() ) i = i->nextSibling(); + return i; +} + +void CatManListItem::checkErrors(KDataTool* tool, QObject* progressSignalHandler, bool ignoreFuzzy, bool markAsFuzzy) +{ + bool hasError=false; + _errors.clear(); + Catalog* cat = new Catalog(); + + QObject::connect( cat, SIGNAL( signalProgress(int) ), progressSignalHandler, SIGNAL( setValidationProgressBar(int))); + QObject::connect( cat, SIGNAL( signalResetProgressBar(QString, int) ), progressSignalHandler, SLOT( setupFileProgressBar(QString, int))); + + if( cat->openURL(KURL( poFile() )) == OK ) + { + kdDebug(KBABEL_CATMAN) << "File opened succesfully" << endl; + if( !cat->checkUsingTool(tool,true) ) + { + hasError = true; + } else forceUpdate(); // no error, find out the new state + } else { + kdDebug(KBABEL_CATMAN) << "File not opened !!!!!" << endl; + hasError=true; + } + + if( hasError ) + { + QString errortext; + _hasErrors = true; + + DocPosition dummy; + IgnoreItem i; + i.fileURL = poFile(); + + if( cat->hasError(0,dummy) && (!ignoreFuzzy || !cat->isFuzzy(0))) + { + i.msgid = cat->msgid(0); + i.msgstr = cat->msgstr(0); + i.index = 0; + _errors.append( i ); + + if( markAsFuzzy ) cat->setFuzzy(0, true); + } + + int index=0; + do + { + index=cat->nextError(index,dummy); + if( index != -1 && (!ignoreFuzzy || !cat->isFuzzy(index) ) ) + { + i.msgid = cat->msgid(index); + i.msgstr = cat->msgstr(index); + i.index = index; + _errors.append( i ); + if( markAsFuzzy ) cat->setFuzzy(index, true); + } + } while(index>=0); + + // change icon only if there were non-ignored errors + if( !_errors.isEmpty() ) + { + setPixmap(COL_NAME, ICON_ERROR); + } + + // if we changed fuzzy flags, save the result + if( cat->isModified() ) cat->saveFile(); + } + + delete cat; +} diff --git a/kbabel/catalogmanager/catmanlistitem.h b/kbabel/catalogmanager/catmanlistitem.h new file mode 100644 index 00000000..a5f41e2f --- /dev/null +++ b/kbabel/catalogmanager/catmanlistitem.h @@ -0,0 +1,238 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2003 by Stanislav Visnovsky <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef CATMANLISTITEM_H +#define CATMANLISTITEM_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qstringlist.h> +#include <qlistview.h> +#include <qdatetime.h> +#include <qfileinfo.h> + +#include "validateprogress.h" + +class CatalogManagerView; +class QPixmap; +class KDataTool; + +namespace KBabel +{ + class PoInfo; +} + +class CatManListItem : public QListViewItem +{ +public: + /** the type of this item */ + enum Type{File,Dir}; + + CatManListItem(CatalogManagerView *view, QListViewItem* parent,QString fullPath + ,QString fullPotPath,QString package); + + /** creates the toplevel root item with package name "/" */ + CatManListItem(CatalogManagerView *view, QListView* parent,QString fullPath, QString fullPotPath); + + /** + * returns the package names (including relative path) of the + * children of this item + */ + QStringList contentsList(bool onlyFiles=false) const; + /** + * returns the package names of all children of this item + * (including all subdirectries) + * @param onlyFiles flag, if only the names of files should be returned + * @see CatManListItem::contentsList + */ + QStringList allChildrenList(bool onlyFiles=false) const; + + /** + * returns the relative file names of all children of this item + * (including all subdirectries) + * @param onlyFiles flag, if only the names of files should be returned + * @param emptyDirs flag, if the empty dirs (dirs without PO files in them) should be returned + * @param onlyModified, if only modified files should be returned + * @see CatManListItem::contentsList + */ + QStringList allChildrenFileList(bool onlyFiles=false, bool emptyDirs=false, bool onlyModified=false) const; + + void setMarked(bool on); + bool marked() const; + /** + * checks if the file on the disc has changed, + * reads information about the file and displays it + * @param noParents flag, if the update has to include the parent + * of the item, if the status has changed. Since at the first build of + * the tree, the status of every item changes, this is not useful then. + */ + void checkUpdate(bool noParents=false); + void forceUpdate(); + + /** + * checks the corresponding PO file using validation tool. On + * errors it fills the list of errors, which can be accessed + * using @see errors(). + * @param validator instance of KDataTool to be used for checking + * @param progressSignalHangler widget, to which the checks should send progress signals + * @param ignoreFuzzy flag, whether fuzzy messages in the file should be not checked + * @param markAsFuzzy flag, whether the error messages should be marked as fuzzy (this alters the PO file) + */ + void checkErrors(KDataTool* validator, QObject* progressSignalHandler, bool ignoreFuzzy, bool markAsFuzzy); + + /** return the absolute filename of the po-File */ + QString poFile() const; + /** return the absolute filename of the pot-File */ + QString potFile() const; + /** returns the package name (inlcuding relative path to base-directory) */ + QString package(bool rootSlash=true) const; + + /** returns the relative path of a dir or QString::null if not a dir. */ + QString packageDir( ) const; + + /** returns the package name (without path) */ + QString name() const; + + /** + * returns the type of this item + * @see CatManListItem::Type + */ + Type type() const{return _type;} + bool isDir() const; + bool isFile() const; + /** returns true, if the po-file exists*/ + bool hasPo() const; + /** returns true, if the pot-file exists*/ + bool hasPot() const; + bool isModified() const; + /** + * @return the number of fuzzy messages in the po-file, + * 0 if no po-file exists + */ + int fuzzy() const; + /** + * @return the number of untranslated messages in the po-file, + * @ref total if no po-file exists + */ + int untranslated() const; + /** @return number of messages in the po- or pot-file */ + int total() const; + /** + * @return true, if there are untranslated or fuzzy items. + * If this item is a directory, it returns true, if a subitem + * contains untranslated or fuzzy items + */ + bool needsWork() const; + /** + * @return true, if there were errors while parsing the file + */ + bool hasErrors() const {return _hasErrors;} + QValueList<IgnoreItem> errors() const {return _errors;} + + virtual QString key(int col,bool) const; + virtual void setOpen(bool); + + /** paints the marking, if this package has no template */ + QPixmap paintExclamation(QPixmap*); + + void updateAfterSave( KBabel::PoInfo &po); + + QStringList &wordList() { return _wordList; } + bool wordsUpdated() { return _wordListUpdated; } + + /** These are not in Qt, so we need to implement it ourselves*/ + QListViewItem *previousSibling(); + QListViewItem *lastChild(); + +private: + void init(const QString& fullPath, const QString& fullPotPath,const QString& package); + /** + * updates the item + * @param showPoInfo if true, reads information about the + * file using @ref Catalog::info + * ( slow for big files ) + * @param includeChildren flag, if possible children should be updated,too + * @param noParents flag, if parents should be updated, when state + * of the item has changed + */ + void update(bool showPoInfo=true,bool includeChildren=false + , bool noParents=false ); + void updateParents(); + +private: + /** + * holds the date and the time this item was + * last updated. This is used to check, if the file + * on the disc has changed since last update. + */ + QDateTime _lastUpdated; + + /** the po-file */ + QFileInfo _primary; + /** the pot-file */ + QFileInfo _template; + /** + * The package name, includes the relative path beginning + * at the base directory. + * The package name begins with "/" and if this is a directory it end with "/" + * The root item has the package name "/" + * @see CatManListItem::CatManListItem + */ + QString _package; + Type _type; + bool _marked; + + /** flag, to detect if file has been deleted or is new */ + bool _hasPo; + /** flag, to detect if file has been deleted or is new */ + bool _hasPot; + + bool _isModified; + /** flag, to detect if file has been modified or new */ + + /** flag, if the PO-file has a syntax error */ + bool _hasErrors; + /** a list of errors found by validation tool*/ + QValueList<IgnoreItem> _errors; + + /** parent view for this item, used for stopping the activity */ + CatalogManagerView *_view; + + /** index of words, but it does not contain any useful information as values */ + QStringList _wordList; + bool _wordListUpdated; +}; + +#endif // CATMANLISTITEM_H diff --git a/kbabel/catalogmanager/catmanresource.h b/kbabel/catalogmanager/catmanresource.h new file mode 100644 index 00000000..06b3ac33 --- /dev/null +++ b/kbabel/catalogmanager/catmanresource.h @@ -0,0 +1,73 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2002 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + +#ifndef CATMANRESOURCE_H +#define CATMANRESOURCE_H + +#include <kiconloader.h> + +#define COL_NAME 0 +#define COL_MARKER 1 +#define COL_FUZZY 2 +#define COL_UNTRANS 3 +#define COL_TOTAL 4 +#define COL_CVS_OR_SVN 5 +#define COL_REVISION 6 +#define COL_TRANSLATOR 7 + +#define ICON_OK UserIcon("ok",KIcon::DefaultState) +#define ICON_MISSING UserIcon("missing",KIcon::DefaultState) +#define ICON_NEEDWORK UserIcon("needwork",KIcon::DefaultState) +#define ICON_BROKEN UserIcon("broken",KIcon::DefaultState) +#define ICON_UPDATING SmallIcon("reload") +#define ICON_FLAG SmallIcon("flag") +#define ICON_FOLDER_CLOSED_OK SmallIcon("folder_green") +#define ICON_FOLDER_CLOSED_WORK SmallIcon("folder_red") +#define ICON_FOLDER_OPEN_OK SmallIcon("folder_green_open") +#define ICON_FOLDER_OPEN_WORK SmallIcon("folder_red_open") +#define ICON_ERROR UserIcon("error",KIcon::DefaultState) +#define ICON_NOFLAG UserIcon("noflag",KIcon::DefaultState) + +// Needed for determining which actions should be enabled and which not. +#define NEEDS_PO 1 +#define NEEDS_POT 2 +#define NEEDS_MARK 4 +#define NEEDS_DIR 8 +#define NEEDS_PO_CVS 16 +#define NEEDS_POT_CVS 32 +#define NEEDS_PO_SVN 64 +#define NEEDS_POT_SVN 128 + +#endif diff --git a/kbabel/catalogmanager/findinfilesdialog.cpp b/kbabel/catalogmanager/findinfilesdialog.cpp new file mode 100644 index 00000000..b11a20d8 --- /dev/null +++ b/kbabel/catalogmanager/findinfilesdialog.cpp @@ -0,0 +1,229 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#include "findinfilesdialog.h" + +#include <qcheckbox.h> +#include <qgroupbox.h> +#include <qlayout.h> +#include <qwhatsthis.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> + +using namespace KBabel; + +FindInFilesDialog::FindInFilesDialog(bool forReplace, QWidget* parent) + :FindDialog(forReplace, parent) +{ + QGroupBox* box = new QGroupBox(2, Qt::Horizontal, i18n("File Options"), mainWidget()); + mainWidget()->layout()->add(box); + + _inAllFiles = new QCheckBox(i18n("&In all files"),box); + _inMarked = new QCheckBox(i18n("&Marked files"),box); + _inTemplates = new QCheckBox(i18n("In &templates"),box); + _askForNextFile = new QCheckBox(i18n("Ask before ne&xt file"),box); + _askForSave = new QCheckBox(i18n("Save &without asking"),box); + + QWhatsThis::add(box,i18n("<qt><p><b>File Options</b></p>" + "<p>Here you can finetune where to find:" + "<ul><li><b>In all files</b>: search in all files, otherwise searched " + "is the selected file or files in the selected folder</li>" + "<li><b>Ask before next file</b>: show a dialog asking to proceed to the next file</li>" + "</ul></qt>")); + + readSettings(); +} + +FindInFilesDialog::~FindInFilesDialog() +{ + saveSettings(); +} + +int FindInFilesDialog::show(QString initialStr) +{ + + FindDialog::show(initialStr); + + int r = result(); + + if( r == QDialog::Accepted ) { + if( isReplaceDialog() ) { + ReplaceOptions options = replaceOpts(); + options.inAllFiles = _inAllFiles->isChecked(); + options.inMarkedFiles = _inMarked->isChecked(); + options.inTemplates = _inTemplates->isChecked(); + options.askForNextFile = _askForNextFile->isChecked(); + options.askForSave = !_askForSave->isChecked(); + FindDialog::setReplaceOpts(options); + } + else { + FindOptions options = findOpts(); + options.inAllFiles = _inAllFiles->isChecked(); + options.inMarkedFiles = _inMarked->isChecked(); + options.inTemplates = _inTemplates->isChecked(); + options.askForNextFile = _askForNextFile->isChecked(); + options.askForSave = !_askForSave->isChecked(); + FindDialog::setFindOpts( options ); + } + } + + return r; +} + +int FindInFilesDialog::exec(QString initialStr) +{ + FindDialog::exec(initialStr); + + int r = result(); + + if( r == QDialog::Accepted ) { + if(isReplaceDialog()) { + ReplaceOptions options = replaceOpts(); + options.inAllFiles = _inAllFiles->isChecked(); + options.inMarkedFiles = _inMarked->isChecked(); + options.inTemplates = _inTemplates->isChecked(); + options.askForNextFile = _askForNextFile->isChecked(); + options.askForSave = !_askForSave->isChecked(); + FindDialog::setReplaceOpts(options); + } + else { + FindOptions options = findOpts(); + options.inAllFiles = _inAllFiles->isChecked(); + options.inMarkedFiles = _inMarked->isChecked(); + options.inTemplates = _inTemplates->isChecked(); + options.askForNextFile = _askForNextFile->isChecked(); + options.askForSave = !_askForSave->isChecked(); + FindDialog::setFindOpts( options ); + } + } + + return r; +} + +void FindInFilesDialog::setFindOpts(FindOptions options) +{ + FindDialog::setFindOpts(options); + + _inAllFiles->setChecked(options.inAllFiles); + _inTemplates->setChecked(options.inTemplates); + _inMarked->setChecked(options.inMarkedFiles); + _askForNextFile->setChecked(options.askForNextFile); + _askForSave->setChecked(!options.askForSave); +} + +void FindInFilesDialog::setReplaceOpts(ReplaceOptions options) +{ + FindDialog::setReplaceOpts(options); + + _inAllFiles->setChecked(options.inAllFiles); + _inTemplates->setChecked(options.inTemplates); + _inMarked->setChecked(options.inMarkedFiles); + _askForNextFile->setChecked(options.askForNextFile); + _askForSave->setChecked(!options.askForSave); +} + +void FindInFilesDialog::readSettings() +{ + KConfig* config = KGlobal::config(); + + if(isReplaceDialog()) { + KConfigGroupSaver cgs(config,"ReplaceDialog"); + + ReplaceOptions options = replaceOpts(); + + options.inAllFiles = config->readBoolEntry("AllFiles", false); + options.inTemplates = config->readBoolEntry("InTemplates", false); + options.inMarkedFiles = config->readBoolEntry("InMarked", false); + options.askForNextFile = config->readBoolEntry("AskForNextFile", true); + options.askForSave = config->readBoolEntry("AskForSave", true); + + _inAllFiles->setChecked(options.inAllFiles); + _inTemplates->setChecked(options.inTemplates); + _inMarked->setChecked(options.inMarkedFiles); + _askForNextFile->setChecked(options.askForNextFile); + _askForSave->setChecked(!options.askForSave); + + FindDialog::setReplaceOpts(options); + } + else { + KConfigGroupSaver cgs(config,"FindDialog"); + + FindOptions options = findOpts(); + + options.inAllFiles = config->readBoolEntry("AllFiles", false); + options.inTemplates = config->readBoolEntry("InTemplates", false); + options.inMarkedFiles = config->readBoolEntry("InMarked", false); + options.askForNextFile = config->readBoolEntry("AskForNextFile", true); + options.askForSave = config->readBoolEntry("AskForSave", true); + + _inAllFiles->setChecked(options.inAllFiles); + _inTemplates->setChecked(options.inTemplates); + _inMarked->setChecked(options.inMarkedFiles); + _askForNextFile->setChecked(options.askForNextFile); + _askForSave->setChecked(!options.askForSave); + + FindDialog::setFindOpts(options); + } + +} + +void FindInFilesDialog::saveSettings() +{ + KConfig* config = KGlobal::config(); + + if(isReplaceDialog()) { + KConfigGroupSaver cgs(config,"ReplaceDialog"); + ReplaceOptions options = replaceOpts(); + + config->writeEntry("AllFiles", options.inAllFiles); + config->writeEntry("InMarked", options.inMarkedFiles); + config->writeEntry("InTemplates", options.inTemplates); + config->writeEntry("AskForNextFile",options.askForNextFile); + config->writeEntry("AskForSave",options.askForSave); + } + else { + KConfigGroupSaver cgs(config,"FindDialog"); + + FindOptions options = findOpts(); + + config->writeEntry("AllFiles", options.inAllFiles); + config->writeEntry("InMarked", options.inMarkedFiles); + config->writeEntry("InTemplates", options.inTemplates); + config->writeEntry("AskForNextFile",options.askForNextFile); + config->writeEntry("AskForSave",options.askForSave); + } +} + +#include "findinfilesdialog.moc" diff --git a/kbabel/catalogmanager/findinfilesdialog.h b/kbabel/catalogmanager/findinfilesdialog.h new file mode 100644 index 00000000..fd25f845 --- /dev/null +++ b/kbabel/catalogmanager/findinfilesdialog.h @@ -0,0 +1,85 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2000 by Matthias Kiefer + <matthias.kiefer@gmx.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef FINDINFILESDIALOG_H +#define FINDINFILESDIALOG_H + +#include "findoptions.h" +#include "finddialog.h" + +class QCheckBox; + +class FindInFilesDialog : public FindDialog +{ + Q_OBJECT +public: + /** + * Constructor + * @param replaceDlg flag, if this is a replace dialog + */ + FindInFilesDialog(bool replaceDlg, QWidget* parent); + ~FindInFilesDialog(); + + /** + * shows the dialog + * @param initialStr string to display in find field. + * If empty, the last used string is used. + * + * @return the result code of the dialog + */ + int show(QString initialStr); + + /** + * executes the dialog as modal + * @param initialStr string to display in find field. + * If empty, the last used string is used. + * + * @return the result code of the dialog + */ + int exec(QString initialStr); + + void setFindOpts(KBabel::FindOptions options); + void setReplaceOpts(KBabel::ReplaceOptions options); + +protected: + void readSettings(); + void saveSettings(); + +private: + QCheckBox *_inAllFiles; + QCheckBox *_inTemplates; + QCheckBox *_inMarked; + QCheckBox *_askForNextFile; + QCheckBox *_askForSave; +}; + +#endif // FINDDIALOG_H diff --git a/kbabel/catalogmanager/future.cpp b/kbabel/catalogmanager/future.cpp new file mode 100644 index 00000000..4c9c8a90 --- /dev/null +++ b/kbabel/catalogmanager/future.cpp @@ -0,0 +1,17 @@ +// This files holds a few user-visible messages that will be needed by the SVN support + +// Misc. messages already existing in the kbabel-svn branch +i18n("SVN"); +i18n( "CVS/SVN Status" ); + +// Messages for further SVN functions +i18n( "Resolved" ); +i18n( "Resolved for Marked" ); +i18n( "Revert" ); +i18n( "Revert for Marked" ); +i18n( "Cleanup" ); +i18n( "Cleanup for Marked" ); + +// Messages that will probably not be needed +i18n( "No repository" ); + diff --git a/kbabel/catalogmanager/hi16-app-catalogmanager.png b/kbabel/catalogmanager/hi16-app-catalogmanager.png Binary files differnew file mode 100644 index 00000000..c2a3ef67 --- /dev/null +++ b/kbabel/catalogmanager/hi16-app-catalogmanager.png diff --git a/kbabel/catalogmanager/hi22-app-catalogmanager.png b/kbabel/catalogmanager/hi22-app-catalogmanager.png Binary files differnew file mode 100644 index 00000000..3b9dfecc --- /dev/null +++ b/kbabel/catalogmanager/hi22-app-catalogmanager.png diff --git a/kbabel/catalogmanager/hi32-app-catalogmanager.png b/kbabel/catalogmanager/hi32-app-catalogmanager.png Binary files differnew file mode 100644 index 00000000..3601807e --- /dev/null +++ b/kbabel/catalogmanager/hi32-app-catalogmanager.png diff --git a/kbabel/catalogmanager/hi48-app-catalogmanager.png b/kbabel/catalogmanager/hi48-app-catalogmanager.png Binary files differnew file mode 100644 index 00000000..8d5090ea --- /dev/null +++ b/kbabel/catalogmanager/hi48-app-catalogmanager.png diff --git a/kbabel/catalogmanager/icons/Makefile.am b/kbabel/catalogmanager/icons/Makefile.am new file mode 100644 index 00000000..f6ca354f --- /dev/null +++ b/kbabel/catalogmanager/icons/Makefile.am @@ -0,0 +1,5 @@ +# Add all of your pixmaps here +icons_ICON = AUTO + +# This is where it will all be installed +iconsdir = $(kde_datadir)/kbabel/icons diff --git a/kbabel/catalogmanager/icons/hi16-action-nextmarked.png b/kbabel/catalogmanager/icons/hi16-action-nextmarked.png Binary files differnew file mode 100644 index 00000000..1e71607f --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-nextmarked.png diff --git a/kbabel/catalogmanager/icons/hi16-action-nextpo.png b/kbabel/catalogmanager/icons/hi16-action-nextpo.png Binary files differnew file mode 100644 index 00000000..650ec8e9 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-nextpo.png diff --git a/kbabel/catalogmanager/icons/hi16-action-nexttemplate.png b/kbabel/catalogmanager/icons/hi16-action-nexttemplate.png Binary files differnew file mode 100644 index 00000000..8422a3c6 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-nexttemplate.png diff --git a/kbabel/catalogmanager/icons/hi16-action-prevmarked.png b/kbabel/catalogmanager/icons/hi16-action-prevmarked.png Binary files differnew file mode 100644 index 00000000..880e694d --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-prevmarked.png diff --git a/kbabel/catalogmanager/icons/hi16-action-prevpo.png b/kbabel/catalogmanager/icons/hi16-action-prevpo.png Binary files differnew file mode 100644 index 00000000..f5e668c4 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-prevpo.png diff --git a/kbabel/catalogmanager/icons/hi16-action-prevtemplate.png b/kbabel/catalogmanager/icons/hi16-action-prevtemplate.png Binary files differnew file mode 100644 index 00000000..4b799896 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-prevtemplate.png diff --git a/kbabel/catalogmanager/icons/hi16-action-statistics.png b/kbabel/catalogmanager/icons/hi16-action-statistics.png Binary files differnew file mode 100644 index 00000000..456be360 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-statistics.png diff --git a/kbabel/catalogmanager/icons/hi16-action-syntax.png b/kbabel/catalogmanager/icons/hi16-action-syntax.png Binary files differnew file mode 100644 index 00000000..221c3b87 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi16-action-syntax.png diff --git a/kbabel/catalogmanager/icons/hi22-action-nextmarked.png b/kbabel/catalogmanager/icons/hi22-action-nextmarked.png Binary files differnew file mode 100644 index 00000000..020ead66 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-nextmarked.png diff --git a/kbabel/catalogmanager/icons/hi22-action-nextpo.png b/kbabel/catalogmanager/icons/hi22-action-nextpo.png Binary files differnew file mode 100644 index 00000000..8579fefd --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-nextpo.png diff --git a/kbabel/catalogmanager/icons/hi22-action-nexttemplate.png b/kbabel/catalogmanager/icons/hi22-action-nexttemplate.png Binary files differnew file mode 100644 index 00000000..064ab5bd --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-nexttemplate.png diff --git a/kbabel/catalogmanager/icons/hi22-action-prevmarked.png b/kbabel/catalogmanager/icons/hi22-action-prevmarked.png Binary files differnew file mode 100644 index 00000000..38113a73 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-prevmarked.png diff --git a/kbabel/catalogmanager/icons/hi22-action-prevpo.png b/kbabel/catalogmanager/icons/hi22-action-prevpo.png Binary files differnew file mode 100644 index 00000000..883ca21a --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-prevpo.png diff --git a/kbabel/catalogmanager/icons/hi22-action-prevtemplate.png b/kbabel/catalogmanager/icons/hi22-action-prevtemplate.png Binary files differnew file mode 100644 index 00000000..0def2356 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-prevtemplate.png diff --git a/kbabel/catalogmanager/icons/hi22-action-statistics.png b/kbabel/catalogmanager/icons/hi22-action-statistics.png Binary files differnew file mode 100644 index 00000000..aff3294f --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-statistics.png diff --git a/kbabel/catalogmanager/icons/hi22-action-syntax.png b/kbabel/catalogmanager/icons/hi22-action-syntax.png Binary files differnew file mode 100644 index 00000000..d0c7decc --- /dev/null +++ b/kbabel/catalogmanager/icons/hi22-action-syntax.png diff --git a/kbabel/catalogmanager/icons/hi32-action-nextmarked.png b/kbabel/catalogmanager/icons/hi32-action-nextmarked.png Binary files differnew file mode 100644 index 00000000..32cd2f48 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-nextmarked.png diff --git a/kbabel/catalogmanager/icons/hi32-action-nextpo.png b/kbabel/catalogmanager/icons/hi32-action-nextpo.png Binary files differnew file mode 100644 index 00000000..2320ecf8 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-nextpo.png diff --git a/kbabel/catalogmanager/icons/hi32-action-nexttemplate.png b/kbabel/catalogmanager/icons/hi32-action-nexttemplate.png Binary files differnew file mode 100644 index 00000000..be6e8c04 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-nexttemplate.png diff --git a/kbabel/catalogmanager/icons/hi32-action-prevmarked.png b/kbabel/catalogmanager/icons/hi32-action-prevmarked.png Binary files differnew file mode 100644 index 00000000..b9c85a05 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-prevmarked.png diff --git a/kbabel/catalogmanager/icons/hi32-action-prevpo.png b/kbabel/catalogmanager/icons/hi32-action-prevpo.png Binary files differnew file mode 100644 index 00000000..28d31e80 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-prevpo.png diff --git a/kbabel/catalogmanager/icons/hi32-action-prevtemplate.png b/kbabel/catalogmanager/icons/hi32-action-prevtemplate.png Binary files differnew file mode 100644 index 00000000..0f9e9c0c --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-prevtemplate.png diff --git a/kbabel/catalogmanager/icons/hi32-action-statistics.png b/kbabel/catalogmanager/icons/hi32-action-statistics.png Binary files differnew file mode 100644 index 00000000..5f428a65 --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-statistics.png diff --git a/kbabel/catalogmanager/icons/hi32-action-syntax.png b/kbabel/catalogmanager/icons/hi32-action-syntax.png Binary files differnew file mode 100644 index 00000000..0be5c2db --- /dev/null +++ b/kbabel/catalogmanager/icons/hi32-action-syntax.png diff --git a/kbabel/catalogmanager/icons/lo16-action-nextmarked.png b/kbabel/catalogmanager/icons/lo16-action-nextmarked.png Binary files differnew file mode 100644 index 00000000..fdbb9664 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-nextmarked.png diff --git a/kbabel/catalogmanager/icons/lo16-action-nextpo.png b/kbabel/catalogmanager/icons/lo16-action-nextpo.png Binary files differnew file mode 100644 index 00000000..b9d0ce11 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-nextpo.png diff --git a/kbabel/catalogmanager/icons/lo16-action-nexttemplate.png b/kbabel/catalogmanager/icons/lo16-action-nexttemplate.png Binary files differnew file mode 100644 index 00000000..979ba277 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-nexttemplate.png diff --git a/kbabel/catalogmanager/icons/lo16-action-prevmarked.png b/kbabel/catalogmanager/icons/lo16-action-prevmarked.png Binary files differnew file mode 100644 index 00000000..b712b63c --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-prevmarked.png diff --git a/kbabel/catalogmanager/icons/lo16-action-prevpo.png b/kbabel/catalogmanager/icons/lo16-action-prevpo.png Binary files differnew file mode 100644 index 00000000..3736c141 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-prevpo.png diff --git a/kbabel/catalogmanager/icons/lo16-action-prevtemplate.png b/kbabel/catalogmanager/icons/lo16-action-prevtemplate.png Binary files differnew file mode 100644 index 00000000..62b3746d --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-prevtemplate.png diff --git a/kbabel/catalogmanager/icons/lo16-action-statistics.png b/kbabel/catalogmanager/icons/lo16-action-statistics.png Binary files differnew file mode 100644 index 00000000..1c298a5b --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-statistics.png diff --git a/kbabel/catalogmanager/icons/lo16-action-syntax.png b/kbabel/catalogmanager/icons/lo16-action-syntax.png Binary files differnew file mode 100644 index 00000000..79fea79a --- /dev/null +++ b/kbabel/catalogmanager/icons/lo16-action-syntax.png diff --git a/kbabel/catalogmanager/icons/lo22-action-statistics.png b/kbabel/catalogmanager/icons/lo22-action-statistics.png Binary files differnew file mode 100644 index 00000000..00ee1475 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo22-action-statistics.png diff --git a/kbabel/catalogmanager/icons/lo22-action-syntax.png b/kbabel/catalogmanager/icons/lo22-action-syntax.png Binary files differnew file mode 100644 index 00000000..801b8cc4 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo22-action-syntax.png diff --git a/kbabel/catalogmanager/icons/lo32-action-nextmarked.png b/kbabel/catalogmanager/icons/lo32-action-nextmarked.png Binary files differnew file mode 100644 index 00000000..ded540c2 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-nextmarked.png diff --git a/kbabel/catalogmanager/icons/lo32-action-nextpo.png b/kbabel/catalogmanager/icons/lo32-action-nextpo.png Binary files differnew file mode 100644 index 00000000..e0fcc825 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-nextpo.png diff --git a/kbabel/catalogmanager/icons/lo32-action-nexttemplate.png b/kbabel/catalogmanager/icons/lo32-action-nexttemplate.png Binary files differnew file mode 100644 index 00000000..da024779 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-nexttemplate.png diff --git a/kbabel/catalogmanager/icons/lo32-action-prevmarked.png b/kbabel/catalogmanager/icons/lo32-action-prevmarked.png Binary files differnew file mode 100644 index 00000000..942587eb --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-prevmarked.png diff --git a/kbabel/catalogmanager/icons/lo32-action-prevpo.png b/kbabel/catalogmanager/icons/lo32-action-prevpo.png Binary files differnew file mode 100644 index 00000000..55cb73a3 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-prevpo.png diff --git a/kbabel/catalogmanager/icons/lo32-action-prevtemplate.png b/kbabel/catalogmanager/icons/lo32-action-prevtemplate.png Binary files differnew file mode 100644 index 00000000..eb485afc --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-prevtemplate.png diff --git a/kbabel/catalogmanager/icons/lo32-action-statistics.png b/kbabel/catalogmanager/icons/lo32-action-statistics.png Binary files differnew file mode 100644 index 00000000..298e4577 --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-statistics.png diff --git a/kbabel/catalogmanager/icons/lo32-action-syntax.png b/kbabel/catalogmanager/icons/lo32-action-syntax.png Binary files differnew file mode 100644 index 00000000..4292ffaf --- /dev/null +++ b/kbabel/catalogmanager/icons/lo32-action-syntax.png diff --git a/kbabel/catalogmanager/libcvs/Makefile.am b/kbabel/catalogmanager/libcvs/Makefile.am new file mode 100644 index 00000000..e3e4f9ac --- /dev/null +++ b/kbabel/catalogmanager/libcvs/Makefile.am @@ -0,0 +1,11 @@ +noinst_LTLIBRARIES = libcatalogmanagercvs.la + +# set the include path for X, qt and KDE +INCLUDES = -I.. -I../../common $(all_includes) + +libcatalogmanagercvs_la_SOURCES = cvshandler.cpp cvsdialog.cpp + +noinst_HEADERS = cvshandler.h cvsdialog.h cvsresources.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO diff --git a/kbabel/catalogmanager/libcvs/cvsdialog.cpp b/kbabel/catalogmanager/libcvs/cvsdialog.cpp new file mode 100644 index 00000000..af76d9d0 --- /dev/null +++ b/kbabel/catalogmanager/libcvs/cvsdialog.cpp @@ -0,0 +1,423 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +// Qt include files +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qfileinfo.h> +#include <qframe.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlistbox.h> +#include <qpushbutton.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qtextedit.h> +#include <qtextcodec.h> +// KDE include files +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kprocess.h> +#include <ktempfile.h> +#include <kmessagebox.h> +#include <kstringhandler.h> +#include <kcombobox.h> +#include <kcharsets.h> +// Project specific include files +#include "cvsdialog.h" + + +CVSDialog::CVSDialog( CVS::Command cmd, QWidget * parent, KSharedConfig* config ) + : KDialog( parent, "CVSDIALOG", true ), m_config( config ) +{ + _cmd = cmd; + p=0L; + setCaption( i18n( "CVS Dialog" ) ); + + QString temp; + + QVBoxLayout * layout = new QVBoxLayout( this, 6, 6, "MAIN LAYOUT" ); + + // Set the label's text depending on the CVS command. + switch ( cmd ) { + case CVS::Update: + temp = i18n( "Update the following files:" ); + break; + case CVS::Commit: + temp = i18n( "Commit the following files:" ); + break; + case CVS::Status: + temp = i18n( "Get status for the following files:" ); + break; + case CVS::Diff: + temp = i18n( "Get diff for the following files:" ); + break; + } + layout->addWidget( new QLabel( temp, this ) ); + + // Widget for showing the list of files. + filebox = new QListBox( this ); + layout->addWidget( filebox ); + + // Add special widgets for 'cvs commit'. + if ( cmd == CVS::Commit ) { + QLabel * label; + + // Combobox for displaying old log messages. + label = new QLabel( i18n( "&Old messages:" ), this ); + oldMessages = new QComboBox( this ); + oldMessages->setDuplicatesEnabled( false ); + label->setBuddy( oldMessages ); + layout->addWidget( label ); + layout->addWidget( oldMessages ); + + // Textfield for entering a log message. + label = new QLabel( i18n( "&Log message:" ), this ); + logedit = new QTextEdit( this ); + label->setBuddy( logedit ); + layout->addWidget( label ); + layout->addWidget( logedit ); + + label = new QLabel( i18n( "E&ncoding:" ), this ); + m_encodingComboBox = new KComboBox( this ); + label->setBuddy( m_encodingComboBox ); + layout->addWidget( label ); + layout->addWidget( m_encodingComboBox ); + QStringList encodingList; + // The last encoding will be added at the top of the list, when the seetings will be read. + encodingList << i18n( "Descriptive encoding name", "Recommended ( %1 )" ).arg( "UTF-8" ); + encodingList << i18n( "Descriptive encoding name", "Locale ( %1 )" ).arg( QTextCodec::codecForLocale()->mimeName() ); + encodingList += KGlobal::charsets()->descriptiveEncodingNames(); + m_encodingComboBox->insertStringList( encodingList ); + + connect( oldMessages, SIGNAL( activated( int ) ), + this, SLOT( slotComboActivated( int ) ) ); + } + + QHBoxLayout * buttons = new QHBoxLayout( 0, 0, 6, "BUTTON LAYOUT" ); + // Add special buttons for 'cvs commit'. + if ( cmd == CVS::Commit ) { + autoAddBox = new QCheckBox( i18n( "Auto&matically add files if necessary" ), this ); + buttons->addWidget( autoAddBox ); + } + buttons->addItem( new QSpacerItem( 1, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ) ); + + // Set the main button's text depending on the CVS comand. + switch ( cmd ) { + case CVS::Update: + temp = i18n( "&Update" ); + break; + case CVS::Commit: + temp = i18n( "&Commit" ); + break; + case CVS::Status: + temp = i18n( "&Get Status" ); + break; + case CVS::Diff: + temp = i18n( "&Get Diff" ); + break; + } + mainBtn = new QPushButton( temp, this ); + mainBtn->setDefault( true ); + buttons->addWidget( mainBtn ); + + cancelBtn = new QPushButton( i18n( "C&ancel" ), this ); + buttons->addWidget( cancelBtn ); + layout->addLayout( buttons ); + + QFrame * line = new QFrame( this ); + line->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + layout->addWidget( line ); + + layout->addWidget( new QLabel( i18n( "Command output:" ), this ) ); + + output = new QTextEdit( this ); + output->setReadOnly( true ); + layout->addWidget( output ); + + resize( QSize( 600, 450 ).expandedTo( minimumSizeHint( ) ) ); + + if ( cmd == CVS::Commit ) + logedit->setFocus( ); + + readSettings( ); + + connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( slotExecuteCommand( ) ) ); + connect( cancelBtn, SIGNAL( clicked( ) ), this, SLOT( reject( ) ) ); +} + +void CVSDialog::slotComboActivated( int index ) +{ + if ( index < 0 || index >= m_logMessages.count() ) + return; + logedit->setText( m_logMessages[index] ); +} + +CVSDialog::~CVSDialog() +{ + delete p; +} + +void CVSDialog::accept( ) +{ + saveSettings( ); + KDialog::accept( ); +} + +void CVSDialog::setFiles( const QStringList& files ) +{ + filebox->insertStringList( files ); +} + +void CVSDialog::setCommandLine( const QString& command ) +{ + _commandLine = command; +} + +void CVSDialog::setAddCommand( const QString& command ) +{ + _addCommand = command; +} + +void CVSDialog::slotExecuteCommand( ) +{ + // Nothing to do here. + if ( _commandLine.isEmpty( ) ) return; + + kdDebug() << "Preparing KProcess" << endl; + + // Create a new shell process + p = new KProcess; + p->setUseShell( true, "/bin/sh" ); + + if ( _cmd == CVS::Commit ) { + // Include command for 'cvs add'. + if ( autoAddBox->isChecked( ) && !_addCommand.isEmpty( ) ) + _commandLine.prepend( _addCommand ); + + const QString msg( logedit->text() ); + + if ( msg.isEmpty() ) + { + // A good commit should never have an empty comment, so ask the user if he really wants it. + const int res = KMessageBox::warningContinueCancel( this, + i18n( "The commit log message is empty. Do you want to continue?" ) ); + if ( res != KMessageBox::Continue ) + return; + } + + m_encoding = KGlobal::charsets()->encodingForName( m_encodingComboBox->currentText() ); + QTextCodec* codec = QTextCodec::codecForName( m_encoding.utf8() ); + + if ( !codec ) + { + KMessageBox::error( this, i18n( "Cannot find encoding: %1" ).arg( m_encoding ) ); + return; + } + else if ( !codec->canEncode( msg ) ) + { + const int res = KMessageBox::warningContinueCancel( this, + i18n( "The commit log message cannot be encoded in the selected encoding: %1.\n" + "Do you want to continue?" ).arg( m_encoding ) ); + if ( res != KMessageBox::Continue ) + return; + } + + // Write the commit log message from the input field to a temporary file + m_tempFile = new KTempFile; + m_tempFile->setAutoDelete( true ); + QTextStream* stream = m_tempFile->textStream(); + if ( !stream ) + { + kdError() << "Could not create QTextStream for file " << m_tempFile->name(); + delete m_tempFile; + m_tempFile = 0; + KMessageBox::error( this, i18n( "Cannot open temporary file for writing. Aborting.") ); + return; + } + stream->setCodec( codec ); + *stream << msg; + m_tempFile->close(); + + if ( m_tempFile->status() ) + { + kdError() << "Could not write to file " << m_tempFile->name(); + delete m_tempFile; + m_tempFile = 0; + KMessageBox::error( this, i18n( "Cannot write to temporary file. Aborting.") ); + return; + } + + // Change the command line to have the real name of the temporary file + _commandLine.replace( "@LOG@FILE@", KProcess::quote( m_tempFile->name() ) ); + + // Update the list of log messages + if ( !msg.isEmpty() ) { + const QString shortLog = KStringHandler::csqueeze( msg, 80 ); + + + // Remove the message from the list if it already exists + m_logMessages.remove( msg ); + // Prepend the current message to the list + m_logMessages.prepend( msg ); + + // At this time of the process, we do not need the combobox anymore, so we do not squeeze the changed strings. + } + } + + // Set the KProcess' command line. + *p << _commandLine; + + connect( p, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT ( slotProcessStdout( KProcess*, char*, int ) ) ); + connect( p, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT ( slotProcessStderr( KProcess*, char*, int ) ) ); + connect( p, SIGNAL( processExited( KProcess* ) ), + this, SLOT( slotProcessExited( KProcess* ) ) ); + + output->append( i18n( "[ Starting command ]" ) ); + + if ( p->start( KProcess::NotifyOnExit, KProcess::Communication( KProcess::AllOutput ) ) ) { + // Disable the main button (and the log edit if in commit mode) to + // indicate activity. + mainBtn->setEnabled( false ); + if ( _cmd == CVS::Commit ) + logedit->setEnabled( false ); + } else + { + kdError() << "Process could not be started." << endl; + KMessageBox::error( this, i18n( "The process could not be started." ) ); + } +} + +void CVSDialog::slotProcessStdout( KProcess*, char * buffer, int len ) +{ + output->append( QString::fromLocal8Bit( buffer, len ) ); + // Set the cursor's position at the end of the output. + output->setCursorPosition( output->lines( ), 0 ); + + // If the command is 'cvs status' or 'cvs diff' collect the output of stdout. + if ( (_cmd == CVS::Status) || (_cmd == CVS::Diff) ) + _statusOutput += QString::fromLocal8Bit( buffer, len ); +} + +void CVSDialog::slotProcessStderr( KProcess*, char * buffer, int len ) +{ + // If an error occurs while executing the command display stderr in + // another color. + QColor oldColor( output->color( ) ); + output->setColor( Qt::red ); + output->append( QString::fromLocal8Bit( buffer, len ) ); + output->setColor( oldColor ); + output->setCursorPosition( output->lines( ), 0 ); +} + +void CVSDialog::slotProcessExited( KProcess * p ) +{ + if ( p->exitStatus( ) ) + output->append( i18n( "[ Exited with status %1 ]" ).arg( p->exitStatus( ) ) ); + else + output->append( i18n( "[ Finished ]" ) ); + + // The command is finished. Now we can reconnect the main button. + disconnect( mainBtn, 0, 0, 0 ); + if ( _cmd == CVS::Diff ) + mainBtn->setText( i18n( "&Show Diff" ) ); + else + mainBtn->setText( i18n( "&Close" ) ); + connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( accept( ) ) ); + + // Reenable the button and the log edit now that the process is finished. + mainBtn->setEnabled( true ); + if ( _cmd == CVS::Commit ) + logedit->setEnabled( true ); +} + +QString CVSDialog::statusOutput( ) +{ + return _statusOutput; +} + +void CVSDialog::readSettings( ) +{ + KSharedConfig * config = m_config; + config->setGroup( "CVSSupport" ); + + if ( _cmd == CVS::Commit ) { + autoAddBox->setChecked( config->readBoolEntry( "AutoAddFiles", true ) ); + + // Fill the combobox with old messages. + m_logMessages.clear(); + m_squeezedLogMessages.clear(); + for ( int cnt = 0; cnt < 10; cnt++ ) + if ( config->hasKey( QString( "CommitLogMessage%1" ).arg( cnt ) ) ) + { + const QString logMessage = config->readEntry( QString( "CommitLogMessage%1" ).arg( cnt ) ); + if ( !logMessage.isEmpty() ) + { + // If the message is too long, cut it to 80 characters (or the combo box becomes too wide) + // ### FIXME: if the string matches the squeezed 80 chars, it might overwrite another entry + const QString shortLog = KStringHandler::csqueeze( logMessage ); + m_logMessages.append( logMessage ); + m_squeezedLogMessages.append( shortLog ); + oldMessages->insertItem( shortLog ); + } + } + + m_encoding = config->readEntry( "CVSEncoding", "UTF-8" ); + m_encodingComboBox->insertItem( i18n( "Descriptive encoding name", "Last choice ( %1 )" ).arg( m_encoding ), 0); + } +} + +void CVSDialog::saveSettings( ) +{ + KSharedConfig * config = m_config; + config->setGroup( "CVSSupport" ); + if ( _cmd == CVS::Commit ) { + config->writeEntry( "AutoAddFiles", autoAddBox->isChecked( ) ); + + // Write the log messages to the config file. + int cnt = 0; + QStringList::const_iterator it; + for ( it = m_logMessages.constBegin( ); it != m_logMessages.constEnd( ) && cnt < 10 ; ++it, ++cnt ) + config->writeEntry( QString( "CommitLogMessage%1" ).arg( cnt ), *it ); + + config->writeEntry( "CVSEncoding", m_encoding ); + } + m_config->sync(); +} + +#include "cvsdialog.moc" diff --git a/kbabel/catalogmanager/libcvs/cvsdialog.h b/kbabel/catalogmanager/libcvs/cvsdialog.h new file mode 100644 index 00000000..658e9883 --- /dev/null +++ b/kbabel/catalogmanager/libcvs/cvsdialog.h @@ -0,0 +1,158 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#ifndef CVSDIALOG_H +#define CVSDIALOG_H + +// KDE include files +#include <kdialog.h> +// Project specific include files +#include "cvsresources.h" +// Forwarding Qt classes +class QCheckBox; +class QComboBox; +class QListBox; +class QPushButton; +class QString; +class QStringList; +class QTextEdit; +// Forwarding KDE classes +class KProcess; +class KTempFile; +class KComboBox; + +/** + * This class represents the dialog which is used for executing CVS commands + * in KBabel's Catalog Manager. The dialog shows the list of files to be + * processed as well as the output from the command. + * + * In Commit mode there is also an option for automatically executing + * 'cvs add' if necessary. + * + * @short Dialog for CVS support in Catalog Manager + * @author Marco Wegner <mail@marcowegner.de> + */ +class CVSDialog : public KDialog +{ + Q_OBJECT + + public: + /** + * Constructor for creating the dialog. + * @param cmd The type of command to be executed. + */ + CVSDialog( CVS::Command cmd, QWidget * parent, KSharedConfig* config ); + ~CVSDialog(); + /** + * Set the list of files which will be used for the CVS command. + * @param files The list of files. + */ + void setFiles( const QStringList& files ); + /** + * Set the command line for the execution of the CVS command. + * @param command The command line. + */ + void setCommandLine( const QString& command ); + /** + * Set the command line for adding files to the CVS repository. + * This method is only used together with a 'cvs commit' for automatically + * adding files which are not yet in the repository. + * @param command The command line. + */ + void setAddCommand( const QString& command ); + /** + * Return the output of a 'cvs status' command. + * @returns The complete output. + */ + QString statusOutput( ); + + protected: + /** + * This method is overwritten so that the settings can be saved after + * pressing the 'Close' button. + */ + virtual void accept( ); + /** Read the dialog's settings. */ + void readSettings( ); + /** Save the dialog's settings. */ + void saveSettings( ); + + protected slots: + /** Slot for executing the CVS Command. */ + void slotExecuteCommand( ); + /** Slot for processing the stdout of the CVS Command. */ + void slotProcessStdout( KProcess*, char * buffer, int len ); + /** Slot for processing the stderr of the CVS Command. */ + void slotProcessStderr( KProcess*, char * buffer, int len ); + /** Slot for post-processing after the CVS command is fninished. */ + void slotProcessExited( KProcess * p ); + /// Slot for combox having been activated + void slotComboActivated( int ); + + private: + CVS::Command _cmd; + + QPushButton * mainBtn; + QPushButton * cancelBtn; + QListBox * filebox; + QComboBox * oldMessages; + QTextEdit * logedit; + QTextEdit * output; + QCheckBox * autoAddBox; + + KProcess * p; + + QString _commandLine; + QString _addCommand; + QString _statusOutput; + + /// Log messages (long version) + QStringList m_logMessages; + /// Log messages (short version) + QStringList m_squeezedLogMessages; + + /// Temporary file (for commits) + KTempFile* m_tempFile; + + /// Encoding for the commit log message + QString m_encoding; + + /// Combo box for the encoding + KComboBox* m_encodingComboBox; + + /// Configuration data (of the KBabel project) + KSharedConfig* m_config; +}; + +#endif // CVSDIALOG_H diff --git a/kbabel/catalogmanager/libcvs/cvshandler.cpp b/kbabel/catalogmanager/libcvs/cvshandler.cpp new file mode 100644 index 00000000..d3f2ae18 --- /dev/null +++ b/kbabel/catalogmanager/libcvs/cvshandler.cpp @@ -0,0 +1,398 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +// System include files +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +// Qt include files +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> +#include <qstring.h> +#include <qstringlist.h> +// KDE include files +#include <kapplication.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ktempfile.h> +// project specific include files +#include "cvshandler.h" + + +CVSHandler::CVSHandler( const QString& poBaseDir, const QString& potBaseDir ) +{ + setPOBaseDir( poBaseDir ); + setPOTBaseDir( potBaseDir ); + _autoUpdateTemplates = false; +} + +void CVSHandler::setPOBaseDir( const QString& dir ) +{ + // check if 'CVS/Entries' exists in the PO base directory + if ( QFileInfo( dir + "/CVS/Entries" ).exists( ) ) { + _isPORepository = true; + _poBaseDir = dir; + } else + _isPORepository = false; + emit signalIsPORepository( _isPORepository ); +} + +void CVSHandler::setPOTBaseDir( const QString& dir ) +{ + // check if 'CVS/Entries' exists in the POT base directory + if ( QFileInfo( dir + "/CVS/Entries" ).exists( ) ) { + _isPOTRepository = true; + _potBaseDir = dir; + } else + _isPOTRepository = false; + emit signalIsPOTRepository( _isPOTRepository ); +} + +QString CVSHandler::fileStatus( const FileStatus status ) const +{ + switch ( status ) { + case NO_REPOSITORY: + return i18n( "No CVS repository" ); + break; + case NOT_IN_CVS: + return i18n( "Not in CVS" ); + break; + case LOCALLY_ADDED: + return i18n( "Locally added" ); + break; + case LOCALLY_REMOVED: + return i18n( "Locally removed" ); + break; + case LOCALLY_MODIFIED: + return i18n( "Locally modified" ); + break; + case UP_TO_DATE: + return i18n( "Up-to-date" ); + break; + case CONFLICT: + return i18n( "Conflict" ); + break; + default: + return i18n( "Unknown" ); + break; + } +} + +CVSHandler::FileStatus CVSHandler::fstatus( const QString& filename ) const +{ + // no valid repository + if ( !_isPORepository ) + return NO_REPOSITORY; + + QString fn( filename ); + fn = fn.remove( QRegExp( "/$" ) ); + + QFileInfo info( fn ); + + // check if 'CVS/Entries' exists and can be read + QFile entries( info.dir( true ).path( ) + "/CVS/Entries" ); + if ( !entries.open( IO_ReadOnly ) ) + return NOT_IN_CVS; // we already know that it's a repository + + // ### FIXME: it does not take care of CVS/Entries.Log + // a line in CVS/Entries has the following format: + // [D]/NAME/REVISION/[CONFLICT+]TIMESTAMP/OPTIONS/TAGDATE + QRegExp rx( QString( "^D?/%1/" ).arg( info.fileName( ) ) ); + + QString temp; + QTextStream stream( &entries ); + + bool isInRepository = false; + while ( !stream.atEnd() ) { + temp = stream.readLine( ); + if ( temp.find( rx ) == 0 ) { + isInRepository = true; + break; + } + } + entries.close( ); + + // no entry found + if ( !isInRepository ) + return NOT_IN_CVS; + + const QStringList fields = QStringList::split( '/', temp, true ); + // bool isDir = ( fields[0] == "D" ); + const QString cvsname( fields[1] ); + const QString revision( fields[2] ); + const QString timestamp( fields[3] ); + // ignore the other fields for now + + if ( revision == "0" && timestamp == "dummy timestamp" ) + return LOCALLY_ADDED; + if ( revision.startsWith( "-" ) && timestamp == "dummy timestamp" ) + return LOCALLY_REMOVED; + + // check for conflicts + if ( timestamp.find( '+' ) >= 0 ) + return CONFLICT; + + // calculate the UTC time from the file's last modified date + struct stat st; + lstat( QFile::encodeName(fn), &st ); + struct tm * tm_p = gmtime( &st.st_mtime ); + QString ftime = QString( asctime( tm_p ) ); + ftime.truncate( ftime.length( ) - 1 ); + if ( ftime != timestamp ) + return LOCALLY_MODIFIED; + + return UP_TO_DATE; +} + +QString CVSHandler::cvsStatus( const QString& filename ) const +{ + return map[filename]; +} + +void CVSHandler::execCVSCommand( QWidget* parent, CVS::Command cmd, const QString& filename, bool templates, KSharedConfig* config ) +{ + if ( !_isPORepository ) { + // This message box should never be visible but who knows... ;-) + KMessageBox::sorry( parent, i18n( "This is not a valid CVS repository. " + "The CVS commands cannot be executed." ) ); + return; + } + + QFileInfo info( filename ); + if ( !info.isDir( ) ) { + execCVSCommand( parent, cmd, QStringList( filename ), templates, config ); + return; + } + + // ### FIXME: instead of making a QString, use KProcess directly, so that it cares about quoting. + // ### FIXME: use KProcess::setWorkingDirectory instead of using "cd" (therefore allowing to use KProcess without a shell.) + // it's a dir + QString command( "cd " + filename + " && cvs " ); + switch ( cmd ) { + case CVS::Update: + command += "update -dP"; + break; + case CVS::Commit: + // The cvs client does not care about the encoding, so we cannot set anything here + command += "commit -F @LOG@FILE@"; + checkToAdd( QStringList( filename ) ); + break; + case CVS::Status: + command += "status"; + break; + case CVS::Diff: + command += "diff"; + break; + } + + showDialog( parent, cmd, QStringList( filename ), command, config ); +} + +void CVSHandler::execCVSCommand( QWidget* parent, CVS::Command cmd, const QStringList& files, bool templates, KSharedConfig* config ) +{ + if ( !_isPORepository ) { + // This message box should never be visible but who knows... ;-) + KMessageBox::sorry( parent, i18n( "This is not a valid CVS repository. " + "The CVS commands cannot be executed." ) ); + return; + } + + // ### FIXME: instead of making a QString, use KProcess directly, so that it cares about quoting. + // ### FIXME: use KProcess::setWorkingDirectory instead of using "cd" (therefore allowing to use KProcess without a shell.) + QString command("cd " + (templates ? _potBaseDir : _poBaseDir) + " && cvs "); + switch ( cmd ) { + case CVS::Update: + command += "update -dP"; + break; + case CVS::Commit: + command += "commit -F @LOG@FILE@"; + checkToAdd( files ); + break; + case CVS::Status: + command += "status"; + break; + case CVS::Diff: + command += "diff"; + break; + } + + QRegExp rx; + if (templates) + rx.setPattern(_potBaseDir + "/?"); + else + rx.setPattern(_poBaseDir + "/?"); + + QStringList::ConstIterator it; + for ( it = files.begin( ); it != files.end( ); ++it ) { + QString temp = *it; + temp.remove(rx); + command += " \'" + temp + "\'"; + } + + showDialog( parent, cmd, files, command, config ); +} + +void CVSHandler::setAutoUpdateTemplates( bool update ) +{ + _autoUpdateTemplates = update; +} + +void CVSHandler::showDialog( QWidget* parent, CVS::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config ) +{ + CVSDialog * dia = new CVSDialog( cmd, parent, config ); + dia->setFiles( files ); + dia->setCommandLine( commandLine ); + if ( cmd == CVS::Commit ) { + dia->setAddCommand( _addCommand ); + } + + if ( dia->exec( ) == KDialog::Accepted ) { + if ( cmd == CVS::Status ) + processStatusOutput( dia->statusOutput( ) ); + if ( cmd == CVS::Diff ) + processDiff( dia->statusOutput( ) ); + } + + delete dia; + + // file status display update necessary in Catalog Manager + if ( cmd == CVS::Commit ) + emit signalFilesCommitted( files ); +} + +void CVSHandler::checkToAdd( const QStringList& files ) +{ + if ( files.isEmpty( ) ) + return; + + QStringList toBeAdded; + + QStringList::ConstIterator it; + for ( it = files.begin( ); it != files.end( ); ++it ) { + // check for every entry if it needs to be added + if ( fstatus( *it ) == NOT_IN_CVS ) { + QFileInfo info( *it ); + QString temp; // will hold the dir path + if ( info.isDir( ) ) { + toBeAdded << *it; + temp = *it; + } else { + toBeAdded << *it; + temp = QFileInfo( *it ).dirPath( true ); + } + // check recursivlely if parent dirs have to be added as well + while ( fstatus( temp ) == NOT_IN_CVS && toBeAdded.findIndex( temp ) == -1 ) { + toBeAdded << temp; + temp = QFileInfo( temp ).dirPath( true ); + } + } + } + + // remove an old command + _addCommand.setLength( 0 ); + + // make sure the diectories are added before the files + toBeAdded.sort( ); + + // create a command line for adding the files and dirs + for ( it = toBeAdded.begin( ); it != toBeAdded.end( ); ++it ) { + QFileInfo info( *it ); + _addCommand += "cd " + info.dirPath( true ) + " && cvs add " + info.fileName( ) + "; "; + } +} + +void CVSHandler::processStatusOutput( const QString& status ) +{ + if ( !_isPORepository ) + return; + + // at first we need to extract the name of the base directory on the server + QFile f( _poBaseDir + "/CVS/Root" ); + if ( !f.open( IO_ReadOnly ) ) + return; + + QTextStream stream( &f ); + // extract the string after the last colon in the first line + QString basedir = stream.readLine( ).section( ':', -1 ); + + f.close( ); + + // divide the complete status output in little chunks for every file + QStringList entries = QStringList::split( QRegExp( "={67,67}" ), status ); + QStringList::Iterator it; + for ( it = entries.begin( ); it != entries.end( ); ++it ) { + QString entr = *it; + // translate the filename from repository to local + QRegExp rx( basedir + ".*,v" ); + int pos = entr.find( rx ); + QString file = _poBaseDir + entr.mid( pos + basedir.length( ), + rx.matchedLength( ) - basedir.length( ) - 2 ); + + entr = "<qt>" + entr + "</qt>"; + + // TODO: do some markup + + map.replace( file, entr ); + } +} + +void CVSHandler::processDiff( QString output ) +{ + output.remove( QRegExp( "\\[ .* \\]$" )); + output.remove( QRegExp( "^" + i18n("[ Starting command ]" ).replace("[","\\[").replace("]","\\]"))); + + KTempFile tmpFile; + *(tmpFile.textStream()) << output; + tmpFile.close(); + + QString error; + if ( KApplication::startServiceByName( "Kompare", tmpFile.name(), &error ) ) + KMessageBox::error( 0, error ); +} + +bool CVSHandler::isConsideredModified( const FileStatus status ) const +{ + /* + * A file is modified if it is either: + * - locally modified for CVS + * - directory under CVS control but not the file + */ + return status == LOCALLY_MODIFIED || status == NOT_IN_CVS; +} + + + +#include "cvshandler.moc" diff --git a/kbabel/catalogmanager/libcvs/cvshandler.h b/kbabel/catalogmanager/libcvs/cvshandler.h new file mode 100644 index 00000000..44777aa3 --- /dev/null +++ b/kbabel/catalogmanager/libcvs/cvshandler.h @@ -0,0 +1,114 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#ifndef CVSHANDLER_H +#define CVSHANDLER_H + +// Qt include files +#include <qmap.h> +#include <qobject.h> +// Project specific include files +#include "cvsdialog.h" +#include "cvsresources.h" +// Forwarding Qt classes +class QString; +class QStringList; +class QWidget; + +class KSharedConfig; + +/** + * This class is the backend for CVS support in Catalog Manager. + * + * @short Backend for CVS support in Catalog Manager + * @author Marco Wegner <mail@marcowegner.de> + */ +class CVSHandler : public QObject +{ + Q_OBJECT + + public: + enum FileStatus { + NO_REPOSITORY, + NOT_IN_CVS, + LOCALLY_ADDED, + LOCALLY_REMOVED, + LOCALLY_MODIFIED, + CONFLICT, + UP_TO_DATE + }; + + CVSHandler( const QString& poBaseDir = QString::null, const QString& potBaseDir = QString::null ); + + void setPOBaseDir( const QString& dir ); + void setPOTBaseDir( const QString& dir ); + + FileStatus fstatus( const QString& filename ) const; + QString fileStatus( const FileStatus status ) const; + QString cvsStatus( const QString& filename ) const; + + void execCVSCommand( QWidget* parent, CVS::Command cmd, const QString& filename, bool templates, KSharedConfig* config ); + void execCVSCommand( QWidget* parent, CVS::Command cmd, const QStringList& files, bool templates, KSharedConfig* config ); + + void setAutoUpdateTemplates( bool update ); + + /** + * True if the file was modified or has another status considered as a modification + */ + bool isConsideredModified( const FileStatus status ) const; + + signals: + void signalIsPORepository( bool ); + void signalIsPOTRepository( bool ); + void signalFilesCommitted( const QStringList& ); + + private: + void showDialog( QWidget* parent, CVS::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config ); + void checkToAdd( const QStringList& files ); + void processStatusOutput( const QString& status ); + void processDiff( QString output ); + + private: + QString _poBaseDir; + QString _potBaseDir; + bool _isPORepository; + bool _isPOTRepository; + bool _autoUpdateTemplates; + QString _addCommand; + + /** Mapping the output of 'cvs status' against the filename. */ + QMap<QString,QString> map; +}; + +#endif // CVSHANDLER_H diff --git a/kbabel/catalogmanager/libcvs/cvsresources.h b/kbabel/catalogmanager/libcvs/cvsresources.h new file mode 100644 index 00000000..627802f7 --- /dev/null +++ b/kbabel/catalogmanager/libcvs/cvsresources.h @@ -0,0 +1,41 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#ifndef CVSRESOURCES_H +#define CVSRESOURCES_H + +namespace CVS { + enum Command { Update, Commit, Status, Diff }; +} + +#endif // CVSRESOURCES_H diff --git a/kbabel/catalogmanager/libsvn/Makefile.am b/kbabel/catalogmanager/libsvn/Makefile.am new file mode 100644 index 00000000..7c340974 --- /dev/null +++ b/kbabel/catalogmanager/libsvn/Makefile.am @@ -0,0 +1,11 @@ +noinst_LTLIBRARIES = libcatalogmanagersvn.la + +# set the include path for X, qt and KDE +INCLUDES = -I.. -I../../common $(all_includes) + +libcatalogmanagersvn_la_SOURCES = svnhandler.cpp svndialog.cpp + +noinst_HEADERS = svnhandler.h svndialog.h svnresources.h + +# let automoc handle all of the meta source files (moc) +METASOURCES = AUTO diff --git a/kbabel/catalogmanager/libsvn/svndialog.cpp b/kbabel/catalogmanager/libsvn/svndialog.cpp new file mode 100644 index 00000000..69653591 --- /dev/null +++ b/kbabel/catalogmanager/libsvn/svndialog.cpp @@ -0,0 +1,400 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +// Qt include files +#include <qcheckbox.h> +#include <qcombobox.h> +#include <qfileinfo.h> +#include <qframe.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlistbox.h> +#include <qpushbutton.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qtextedit.h> +// KDE include files +#include <kconfig.h> +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kprocess.h> +#include <ktempfile.h> +#include <kmessagebox.h> +#include <kstringhandler.h> +// Project specific include files +#include "svndialog.h" + + +SVNDialog::SVNDialog( SVN::Command cmd, QWidget * parent, KSharedConfig* config ) + : KDialog( parent, "SVN DIALOG", true ), m_tempFile( 0 ), m_config( config ) +{ + _cmd = cmd; + p=0L; + setCaption( i18n( "SVN Dialog" ) ); + + QString temp; + + QVBoxLayout * layout = new QVBoxLayout( this, 6, 6, "MAIN LAYOUT" ); + + // Set the label's text depending on the SVN command. + switch ( cmd ) { + case SVN::Update: + temp = i18n( "Update the following files:" ); + break; + case SVN::Commit: + temp = i18n( "Commit the following files:" ); + break; + case SVN::StatusRemote: + temp = i18n( "Get remote status for the following files:" ); + break; + case SVN::StatusLocal: + temp = i18n( "Get local status for the following files:" ); + break; + case SVN::Diff: + temp = i18n( "Get diff for the following files:" ); + break; + case SVN::Info: + temp = i18n( "Get information for the following files:" ); + break; + } + layout->addWidget( new QLabel( temp, this ) ); + + // Widget for showing the list of files. + filebox = new QListBox( this ); + layout->addWidget( filebox ); + + // Add special widgets for 'svn commit'. + if ( cmd == SVN::Commit ) { + QLabel * label; + + // Combobox for displaying old log messages. + label = new QLabel( i18n( "&Old messages:" ), this ); + oldMessages = new QComboBox( this ); + oldMessages->setDuplicatesEnabled( false ); + label->setBuddy( oldMessages ); + layout->addWidget( label ); + layout->addWidget( oldMessages ); + + // Textfield for entering a log message. + label = new QLabel( i18n( "&Log message:" ), this ); + logedit = new QTextEdit( this ); + label->setBuddy( logedit ); + layout->addWidget( label ); + layout->addWidget( logedit ); + + connect( oldMessages, SIGNAL( activated( int ) ), + this, SLOT( slotComboActivated( int ) ) ); + } + + QHBoxLayout * buttons = new QHBoxLayout( 0, 0, 6, "BUTTON LAYOUT" ); + // Add special buttons for 'svn commit'. + if ( cmd == SVN::Commit ) { + autoAddBox = new QCheckBox( i18n( "Auto&matically add files if necessary" ), this ); + buttons->addWidget( autoAddBox ); + } + buttons->addItem( new QSpacerItem( 1, 0, QSizePolicy::Expanding, QSizePolicy::Minimum ) ); + + // Set the main button's text depending on the SVN comand. + switch ( cmd ) { + case SVN::Update: + temp = i18n( "&Update" ); + break; + case SVN::Commit: + temp = i18n( "&Commit" ); + break; + case SVN::StatusRemote: + case SVN::StatusLocal: + temp = i18n( "&Get Status" ); + break; + case SVN::Diff: + temp = i18n( "&Get Diff" ); + break; + case SVN::Info: + temp = i18n( "&Get Information" ); + break; + } + mainBtn = new QPushButton( temp, this ); + mainBtn->setDefault( true ); + buttons->addWidget( mainBtn ); + + cancelBtn = new QPushButton( i18n( "C&ancel" ), this ); + buttons->addWidget( cancelBtn ); + layout->addLayout( buttons ); + + QFrame * line = new QFrame( this ); + line->setFrameStyle( QFrame::HLine | QFrame::Sunken ); + layout->addWidget( line ); + + layout->addWidget( new QLabel( i18n( "Command output:" ), this ) ); + + output = new QTextEdit( this ); + output->setReadOnly( true ); + layout->addWidget( output ); + + resize( QSize( 600, 450 ).expandedTo( minimumSizeHint( ) ) ); + + if ( cmd == SVN::Commit ) + logedit->setFocus( ); + + readSettings( ); + + connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( slotExecuteCommand( ) ) ); + connect( cancelBtn, SIGNAL( clicked( ) ), this, SLOT( reject( ) ) ); +} + +void SVNDialog::slotComboActivated( int index ) +{ + if ( index < 0 || index >= m_logMessages.count() ) + return; + logedit->setText( m_logMessages[index] ); +} + +SVNDialog::~SVNDialog() +{ + delete m_tempFile; + delete p; +} + +void SVNDialog::accept( ) +{ + saveSettings( ); + KDialog::accept( ); +} + +void SVNDialog::setFiles( const QStringList& files ) +{ + filebox->insertStringList( files ); +} + +void SVNDialog::setCommandLine( const QString& command ) +{ + _commandLine = command; +} + +void SVNDialog::setAddCommand( const QString& command ) +{ + _addCommand = command; +} + +void SVNDialog::slotExecuteCommand( ) +{ + // Nothing to do here. + if ( _commandLine.isEmpty( ) ) return; + + kdDebug() << "Preparing KProcess" << endl; + + // Create a new shell process + p = new KProcess; + p->setUseShell( true, "/bin/sh" ); + + if ( _cmd == SVN::Commit ) { + // Include command for 'svn add'. + if ( autoAddBox->isChecked( ) && !_addCommand.isEmpty( ) ) + _commandLine.prepend( _addCommand ); + + const QString msg( logedit->text() ); + + if ( msg.isEmpty() ) + { + // A good commit should never have an empty comment, so ask the user if he really wants it. + const int res = KMessageBox::warningContinueCancel( this, + i18n( "The commit log message is empty. Do you want to continue?" ) ); + if ( res != KMessageBox::Continue ) + return; + } + + // Write the commit log message from the input field to a temporary file + m_tempFile = new KTempFile; + m_tempFile->setAutoDelete( true ); + QTextStream* stream = m_tempFile->textStream(); + if ( !stream ) + { + kdError() << "Could not create QTextStream for file " << m_tempFile->name(); + delete m_tempFile; + m_tempFile = 0; + KMessageBox::error( this, i18n( "Cannot open temporary file for writing. Aborting.") ); + return; + } + stream->setEncoding( QTextStream::UnicodeUTF8 ); + *stream << msg; + m_tempFile->close(); + + if ( m_tempFile->status() ) + { + kdError() << "Could not write to file " << m_tempFile->name(); + delete m_tempFile; + m_tempFile = 0; + KMessageBox::error( this, i18n( "Cannot write to temporary file. Aborting.") ); + return; + } + + // Change the command line to have the real name of the temporary file + _commandLine.replace( "@LOG@FILE@", KProcess::quote( m_tempFile->name() ) ); + + // Update the list of log messages + if ( !msg.isEmpty() ) { + const QString shortLog = KStringHandler::csqueeze( msg, 80 ); + + + // Remove the message from the list if it already exists + m_logMessages.remove( msg ); + // Prepend the current message to the list + m_logMessages.prepend( msg ); + + // At this time of the process, we do not need the combobox anymore, so we do not squeeze the changed strings. + } + } + + // Set the KProcess' command line. + *p << _commandLine; + + connect( p, SIGNAL( receivedStdout( KProcess*, char*, int ) ), + this, SLOT ( slotProcessStdout( KProcess*, char*, int ) ) ); + connect( p, SIGNAL( receivedStderr( KProcess*, char*, int ) ), + this, SLOT ( slotProcessStderr( KProcess*, char*, int ) ) ); + connect( p, SIGNAL( processExited( KProcess* ) ), + this, SLOT( slotProcessExited( KProcess* ) ) ); + + output->append( i18n( "[ Starting command ]" ) ); + + if ( p->start( KProcess::NotifyOnExit, KProcess::Communication( KProcess::AllOutput ) ) ) { + // Disable the main button (and the log edit if in commit mode) to + // indicate activity. + mainBtn->setEnabled( false ); + if ( _cmd == SVN::Commit ) + logedit->setEnabled( false ); + } else + { + kdError() << "Process could not be started." << endl; + KMessageBox::error( this, i18n( "The process could not be started." ) ); + } +} + +void SVNDialog::slotProcessStdout( KProcess*, char * buffer, int len ) +{ + output->append( QString::fromLocal8Bit( buffer, len ) ); + // Set the cursor's position at the end of the output. + output->setCursorPosition( output->lines( ), 0 ); + + // If the command is 'svn status' or 'svn diff' collect the output of stdout. + if ( ( _cmd == SVN::StatusLocal ) || ( _cmd == SVN::StatusRemote ) || ( _cmd == SVN::Diff ) ) + _statusOutput += QString::fromLocal8Bit( buffer, len ); +} + +void SVNDialog::slotProcessStderr( KProcess*, char * buffer, int len ) +{ + // If an error occurs while executing the command display stderr in + // another color. + QColor oldColor( output->color( ) ); + output->setColor( Qt::red ); + output->append( QString::fromLocal8Bit( buffer, len ) ); + output->setColor( oldColor ); + output->setCursorPosition( output->lines( ), 0 ); +} + +void SVNDialog::slotProcessExited( KProcess * p ) +{ + if ( p->exitStatus( ) ) + output->append( i18n( "[ Exited with status %1 ]" ).arg( p->exitStatus( ) ) ); + else + output->append( i18n( "[ Finished ]" ) ); + + // The command is finished. Now we can reconnect the main button. + disconnect( mainBtn, 0, 0, 0 ); + if ( _cmd == SVN::Diff ) + mainBtn->setText( i18n( "&Show Diff" ) ); + else + mainBtn->setText( i18n( "&Close" ) ); + connect( mainBtn, SIGNAL( clicked( ) ), this, SLOT( accept( ) ) ); + + // Reenable the button and the log edit now that the process is finished. + mainBtn->setEnabled( true ); + if ( _cmd == SVN::Commit ) + logedit->setEnabled( true ); +} + +QString SVNDialog::statusOutput( ) +{ + return _statusOutput; +} + +void SVNDialog::readSettings( ) +{ + KSharedConfig * config = m_config; + config->setGroup( "SVNSupport" ); + + if ( _cmd == SVN::Commit ) { + autoAddBox->setChecked( config->readBoolEntry( "AutoAddFiles", true ) ); + + // Fill the combobox with old messages. + m_logMessages.clear(); + m_squeezedLogMessages.clear(); + for ( int cnt = 0; cnt < 10; cnt++ ) + if ( config->hasKey( QString( "CommitLogMessage%1" ).arg( cnt ) ) ) + { + const QString logMessage = config->readEntry( QString( "CommitLogMessage%1" ).arg( cnt ) ); + if ( !logMessage.isEmpty() ) + { + // If the message is too long, cut it to 80 characters (or the combo box becomes too wide) + // ### FIXME: if the string matches the squeezed 80 chars, it might overwrite another entry + const QString shortLog = KStringHandler::csqueeze( logMessage ); + m_logMessages.append( logMessage ); + m_squeezedLogMessages.append( shortLog ); + oldMessages->insertItem( shortLog ); + } + } + + } +} + +void SVNDialog::saveSettings( ) +{ + KSharedConfig * config = m_config; + config->setGroup( "SVNSupport" ); + if ( _cmd == SVN::Commit ) { + config->writeEntry( "AutoAddFiles", autoAddBox->isChecked( ) ); + + // Write the log messages to the config file. + int cnt = 0; + QStringList::const_iterator it; + for ( it = m_logMessages.constBegin( ); it != m_logMessages.constEnd( ) && cnt < 10 ; ++it, ++cnt ) + config->writeEntry( QString( "CommitLogMessage%1" ).arg( cnt ), *it ); + } + m_config->sync(); +} + +#include "svndialog.moc" + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kbabel/catalogmanager/libsvn/svndialog.h b/kbabel/catalogmanager/libsvn/svndialog.h new file mode 100644 index 00000000..0c824fa8 --- /dev/null +++ b/kbabel/catalogmanager/libsvn/svndialog.h @@ -0,0 +1,151 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#ifndef SVNDIALOG_H +#define SVNDIALOG_H + +// KDE include files +#include <kdialog.h> +// Project specific include files +#include "svnresources.h" +// Forwarding Qt classes +class QCheckBox; +class QComboBox; +class QListBox; +class QPushButton; +class QString; +class QStringList; +class QTextEdit; +// Forwarding KDE classes +class KProcess; +class KTempFile; +class KSharedConfig; + +/** + * This class represents the dialog which is used for executing SVN commands + * in KBabel's Catalog Manager. The dialog shows the list of files to be + * processed as well as the output from the command. + * + * In Commit mode there is also an option for automatically executing + * 'svn add' if necessary. + * + * @short Dialog for SVN support in Catalog Manager + */ +class SVNDialog : public KDialog +{ + Q_OBJECT + + public: + /** + * Constructor for creating the dialog. + * @param cmd The type of command to be executed. + */ + SVNDialog( SVN::Command cmd, QWidget * parent, KSharedConfig* config ); + ~SVNDialog(); + /** + * Set the list of files which will be used for the SVN command. + * @param files The list of files. + */ + void setFiles( const QStringList& files ); + /** + * Set the command line for the execution of the SVN command. + * @param command The command line. + */ + void setCommandLine( const QString& command ); + /** + * Set the command line for adding files to the SVN repository. + * This method is only used together with a 'svn commit' for automatically + * adding files which are not yet in the repository. + * @param command The command line. + */ + void setAddCommand( const QString& command ); + /** + * Return the output of a 'svn status' command. + * @returns The complete output. + */ + QString statusOutput( ); + + protected: + /** + * This method is overwritten so that the settings can be saved after + * pressing the 'Close' button. + */ + virtual void accept( ); + /** Read the dialog's settings. */ + void readSettings( ); + /** Save the dialog's settings. */ + void saveSettings( ); + + protected slots: + /** Slot for executing the SVN Command. */ + void slotExecuteCommand( ); + /** Slot for processing the stdout of the SVN Command. */ + void slotProcessStdout( KProcess*, char * buffer, int len ); + /** Slot for processing the stderr of the SVN Command. */ + void slotProcessStderr( KProcess*, char * buffer, int len ); + /** Slot for post-processing after the SVN command is fninished. */ + void slotProcessExited( KProcess * p ); + /// Slot for combox having been activated + void slotComboActivated( int ); + + private: + SVN::Command _cmd; + + QPushButton * mainBtn; + QPushButton * cancelBtn; + QListBox * filebox; + QComboBox * oldMessages; + QTextEdit * logedit; + QTextEdit * output; + QCheckBox * autoAddBox; + + KProcess * p; + + QString _commandLine; + QString _addCommand; + QString _statusOutput; + + /// Log messages (long version) + QStringList m_logMessages; + /// Log messages (short version) + QStringList m_squeezedLogMessages; + + /// Temporary file (for commits) + KTempFile* m_tempFile; + + /// Configuration data (of the KBabel project) + KSharedConfig* m_config; +}; + +#endif // SVNDIALOG_H diff --git a/kbabel/catalogmanager/libsvn/svnhandler.cpp b/kbabel/catalogmanager/libsvn/svnhandler.cpp new file mode 100644 index 00000000..8117fe62 --- /dev/null +++ b/kbabel/catalogmanager/libsvn/svnhandler.cpp @@ -0,0 +1,544 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +// System include files +#include <unistd.h> +#include <sys/stat.h> +#include <time.h> +// Qt include files +#include <qdir.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qdom.h> +// KDE include files +#include <kapplication.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kprocess.h> +// project specific include files +#include "svnhandler.h" + +SVNHandler::SVNHandler( const QString& poBaseDir, const QString& potBaseDir ) +{ + setPOBaseDir( poBaseDir ); + setPOTBaseDir( potBaseDir ); + _autoUpdateTemplates = false; +} + +void SVNHandler::setPOBaseDir( const QString& dir ) +{ + // check if '.svn/entries' exists in the PO base directory + if ( QFileInfo( dir + "/.svn/entries" ).exists( ) ) { + _isPORepository = true; + _poBaseDir = dir; + } else + _isPORepository = false; + emit signalIsPORepository( _isPORepository ); +} + +void SVNHandler::setPOTBaseDir( const QString& dir ) +{ + // check if '.svn/entries' exists in the POT base directory + if ( QFileInfo( dir + "/.svn/entries" ).exists( ) ) { + _isPOTRepository = true; + _potBaseDir = dir; + } else + _isPOTRepository = false; + emit signalIsPOTRepository( _isPOTRepository ); +} + +QString SVNHandler::fileStatus( const FileStatus status ) const +{ + switch ( status ) { + case NO_REPOSITORY: + return i18n( "No SVN repository" ); + break; + case NOT_IN_SVN: + return i18n( "Not in SVN" ); + break; + case LOCALLY_ADDED: + return i18n( "Locally added" ); + break; + case LOCALLY_REMOVED: + return i18n( "Locally removed" ); + break; + case LOCALLY_MODIFIED: + return i18n( "Locally modified" ); + break; + case UP_TO_DATE: + return i18n( "Up-to-date" ); + break; + case CONFLICT: + return i18n( "Conflict" ); + break; + case ERROR_IN_WC: + return i18n( "Error in Working Copy" ); + default: + return i18n( "Unknown" ); + break; + } +} + +SVNHandler::FileStatus SVNHandler::fstatus( const QString& filename ) const +{ + // no valid repository + if ( !_isPORepository ) + return NO_REPOSITORY; + + QString fn( filename ); + fn = fn.remove( QRegExp( "/$" ) ); + + QFileInfo info( fn ); + + // check if '.svn/entries' exists. + QFile entries( info.dir( true ).path( ) + "/.svn/entries" ); + + if ( !entries.exists() ) + return NOT_IN_SVN; + + KProcess proc; + SVNOutputCollector out( &proc ); + + proc << "svn" << "status" << "-v" << "--xml" << info.absFilePath(); + + if( !proc.start( KProcess::Block, KProcess::Stdout ) ) + return ERROR_IN_WC; + + QDomDocument doc; + QString errorMsg; + int errorLine, errorCol; + QDomNodeList nodelist; + QDomNode node; + QDomElement entry, wcStatus; + + // Parse the output. + if ( !doc.setContent( out.getOutput(), &errorMsg, &errorLine, &errorCol ) ) { + kdDebug(8109) << "Cannot parse \"svn status -v --xml\" output for" + << filename << endl << "Line: " << errorLine << " Column: " + << errorCol << " Error: " << errorMsg << endl; + goto no_status_xml; + } + + // There should be only one "entry" element. If it doesn't exist, path + // isn't repo path at all. + nodelist = doc.elementsByTagName("entry"); + if (nodelist.count() < 1) + return NOT_IN_SVN; + + entry = nodelist.item(0).toElement(); + + // Shouldn't fail, but just in case there is some weird error. + if ( entry.attributeNode("path").value() != info.absFilePath() ) + return ERROR_IN_WC; + + for ( node = entry.firstChild(); !node.isNull(); node = node.nextSibling() ) { + if ( !node.isElement() ) + continue; + if (node.toElement().tagName() == "wc-status") + break; + } + + if ( node.isNull() ) + return ERROR_IN_WC; + + wcStatus = node.toElement(); + + if ( wcStatus.attributeNode("item").value() == "normal" ) + return UP_TO_DATE; + if ( wcStatus.attributeNode("item").value() == "modified" ) + return LOCALLY_MODIFIED; + if ( wcStatus.attributeNode("item").value() == "conflicted" ) + return CONFLICT; + if ( wcStatus.attributeNode("item").value() == "unversioned" ) + return NOT_IN_SVN; + // TODO Ignored entry should have separate return value probably. + if ( wcStatus.attributeNode("item").value() == "ignored" ) + return NOT_IN_SVN; + if ( wcStatus.attributeNode("item").value() == "added" ) + return LOCALLY_ADDED; + if ( wcStatus.attributeNode("item").value() == "deleted" ) + return LOCALLY_REMOVED; + // TODO What to do with "missing", "incomplete", "replaced", "merged", + // "obstructed", "external"? Can these appear at all in our case? + + return ERROR_IN_WC; + +no_status_xml: + if ( !entries.open( IO_ReadOnly ) ) + return ERROR_IN_WC; // we already know that it is a repository + + // Parse the entries file + if ( !doc.setContent( &entries, &errorMsg, &errorLine, &errorCol ) ) { + kdDebug() << "Cannot parse .svn/entries file for " << filename << endl + << "Line: " << errorLine << " Column: " << errorCol << " Error: " << errorMsg << endl; + return ERROR_IN_WC; + } + entries.close(); + + QDomElement element; + // File name that we are searching + const QString findName = info.fileName(); + // The entries are <entry> elements, so we have to check them + QDomNode child = doc.documentElement().firstChild(); + for ( ; !child.isNull() ; child = child.nextSibling() ) + { + if ( !child.isElement() ) + continue; + element = child.toElement(); + if ( element.tagName() != "entry" ) { + // We have another kind of element, so skip it + // Should not happend with svn 1.1.x + continue; + } + const QString name = element.attribute("name"); + if ( name == findName ) + break; + } + + if ( child.isNull() ) { + // We have not found an entry for the file + return NOT_IN_SVN; + } + + // ### TODO: should we check the attribute kind to be file and not dir? + + // ### TODO: what do copy and move add here? + const QString onSchedule = element.attribute( "schedule" ); + if ( onSchedule == "delete" ) + return LOCALLY_REMOVED; + else if ( onSchedule == "added" ) + return LOCALLY_ADDED; + + if ( element.hasAttribute( "conflict-new" ) || element.hasAttribute( "conflict-old" ) || element.hasAttribute( "conflict-wrk" ) ) { + return CONFLICT; + } + + // Note: we do not check the property time stamp + const QString textTimeStamp( element.attribute( "text-time" ) ); + + // calculate the UTC time from the file's last modified date + struct stat st; + lstat( QFile::encodeName(fn), &st ); + struct tm * tm_p = gmtime( &st.st_mtime ); + const int year = tm_p->tm_year + 1900; + const int month = tm_p->tm_mon + 1; + QString fileTime; + fileTime.sprintf( "%04i-%02i-%02iT%02i:%02i:%02i.000000Z", + year, month, tm_p->tm_mday, tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec ); + //kdDebug() << "File: " << filename << " SVN time: " << textTimeStamp << " File time: " << fileTime << endl; + if ( fileTime > textTimeStamp ) // ISO 8601 dates/times can be compared as strings if they have the exact same format. + return LOCALLY_MODIFIED; + + return UP_TO_DATE; + +} + +QString SVNHandler::svnStatus( const QString& filename ) const +{ + return map[filename]; +} + +void SVNHandler::execSVNCommand( QWidget* parent, SVN::Command cmd, const QString& filename, bool templates, KSharedConfig* config) +{ + // Unlike cvs, svn works also from outside the repository(as long as the path is in a repository of course!) + // ### FIXME: wrong, svn commit cannot work if the current directory is not a SVN one + execSVNCommand( parent, cmd, QStringList( filename ), templates, config ); +} + +void SVNHandler::execSVNCommand( QWidget* parent, SVN::Command cmd, const QStringList& files, bool templates, KSharedConfig* config ) +{ + if ( !_isPORepository ) { + // This message box should never be visible but who knows... ;-) + KMessageBox::sorry( parent, i18n( "This is not a valid SVN repository. " + "The SVN commands cannot be executed." ) ); + return; + } + + // ### TODO: instead of making a QString, use KProcess directly, so that it cares about quoting. + // ### TODO: use KProcess::setWorkingDirectory instead of using "cd" (therefore allowing to use KProcess without a shell.) + QString command("cd " + (templates ? _potBaseDir : _poBaseDir) + " && svn "); + switch ( cmd ) { + case SVN::Update: + command += "update --non-interactive"; + break; + case SVN::Commit: + // The svn client allows to choose the encoding, so we select UTF-8 + command += "commit -F @LOG@FILE@ --encoding UTF-8 --non-interactive"; + checkToAdd( files ); + break; + case SVN::StatusRemote: + command += "status -u --non-interactive"; + break; + case SVN::StatusLocal: + command += "status --non-interactive"; + break; + case SVN::Diff: + command += "diff --non-interactive"; + break; + case SVN::Info: + command += "info"; // Does not allow --non-interactive (at least svn 1.1.4). + } + + QRegExp rx; + if (templates) + rx.setPattern(_potBaseDir + "/?"); + else + rx.setPattern(_poBaseDir + "/?"); + + QStringList::ConstIterator it; + for ( it = files.begin( ); it != files.end( ); ++it ) { + QString temp = *it; + temp.remove(rx); + command += " \'" + temp + "\'"; + } + + showDialog( parent, cmd, files, command, config ); +} + +void SVNHandler::setAutoUpdateTemplates( bool update ) +{ + _autoUpdateTemplates = update; +} + +void SVNHandler::showDialog( QWidget* parent, SVN::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config ) +{ + SVNDialog * dia = new SVNDialog( cmd, parent, config ); + dia->setFiles( files ); + dia->setCommandLine( commandLine ); + if ( cmd == SVN::Commit ) { + dia->setAddCommand( _addCommand ); + } + + if ( dia->exec( ) == KDialog::Accepted ) { + if ( cmd == SVN::StatusLocal || cmd == SVN::StatusRemote ) + processStatusOutput( dia->statusOutput( ) ); + if ( cmd == SVN::Diff ) + processDiff( dia->statusOutput( ) ); + } + + delete dia; + + // file status display update necessary in Catalog Manager + if ( cmd == SVN::Commit ) + emit signalFilesCommitted( files ); +} + +bool SVNHandler::isInSvn( const QString& path ) +{ + if ( path.isEmpty() ) + return false; + + /* + * We need to check if a file is in a SVN repository. + * + * But as we want to do it quickly (because this function will be called for a few files in a row) + * we should avoid to parse the .svn/entries files + * + * Therefore we only check for the SVN auxilary files that are typical for a file controlled by SVN: + * - for a directory: checks if the directory has a .svn/entries file + * - for a file: check if there is a corresponding file in .svn/text-base/ + */ + + const QFileInfo info( path ); + if ( info.isDir() ) { + // It is a directory, so find a .svn/entries file + QDir dir( path ); + return dir.exists( ".svn/entries", true ); + } + else { + // It is a file, so find the corresponding file in .svn/text-base + QDir dir( info.dirPath() ); + if ( ! dir.cd( ".svn/text-base" ) ) { + // There is not even a .svn/text-base directory, so the file is not under control + return false; + } + const QString textBaseFilename( info.fileName() + ".svn-base" ); + return dir.exists( textBaseFilename, true ); + } +} + +void SVNHandler::checkToAdd( const QStringList& files ) +{ + if ( files.isEmpty( ) ) + return; + + QStringList toBeAdded; + + QStringList::ConstIterator it; + for ( it = files.begin( ); it != files.end( ); ++it ) { + // check for every entry if it needs to be added + if ( ! isInSvn( *it ) ) { + QFileInfo info( *it ); + QString temp; // will hold the dir path + if ( info.isDir( ) ) { + toBeAdded << *it; + temp = *it; + } else { + toBeAdded << *it; + temp = QFileInfo( *it ).dirPath( true ); + } + + // ### TODO: does SVN really needs this or does it do it automatically? + // check recursivlely if parent dirs have to be added as well + while ( ! isInSvn( temp ) && toBeAdded.findIndex( temp ) == -1 ) { + toBeAdded << temp; + temp = QFileInfo( temp ).dirPath( true ); + } + + } + } + + // remove an old command + _addCommand = QString(); + + // ### TODO: does SVN really need this? + // make sure the directories are added before the files + toBeAdded.sort( ); + + // ### TODO: try to make this better + // create a command line for adding the files and dirs + for ( it = toBeAdded.begin( ); it != toBeAdded.end( ); ++it ) { + QFileInfo info( *it ); + _addCommand += "cd " + info.dirPath( true ) + " && svn add " + info.fileName( ) + "; "; + } +} + +// ### TODO: convert to SVN +void SVNHandler::processStatusOutput( const QString& status ) +{ + if ( !_isPORepository ) + return; + +#if 0 + // at first we need to extract the name of the base directory on the server + QFile f( _poBaseDir + "/SVN/Root" ); // ### FIXME + if ( !f.open( IO_ReadOnly ) ) + return; + + QTextStream stream( &f ); + // extract the string after the last colon in the first line + QString basedir = stream.readLine( ).section( ':', -1 ); + + f.close( ); + + // divide the complete status output in little chunks for every file + QStringList entries = QStringList::split( QRegExp( "={67,67}" ), status ); + QStringList::Iterator it; + for ( it = entries.begin( ); it != entries.end( ); ++it ) { + QString entr = *it; + // translate the filename from repository to local + QRegExp rx( basedir + ".*,v" ); + int pos = entr.find( rx ); + QString file = _poBaseDir + entr.mid( pos + basedir.length( ), + rx.matchedLength( ) - basedir.length( ) - 2 ); + + entr = "<qt>" + entr + "</qt>"; + + // TODO: do some markup + + map.replace( file, entr ); + } +#endif +} + +void SVNHandler::processDiff( QString output ) +{ + output.remove( QRegExp( "\\[ .* \\]$" )); + output.remove( QRegExp( "^" + i18n("[ Starting command ]" ).replace("[","\\[").replace("]","\\]"))); + + KTempFile tmpFile; + *(tmpFile.textStream()) << output; + tmpFile.close(); + + QString error; + if ( KApplication::startServiceByName( "Kompare", tmpFile.name(), &error ) ) + KMessageBox::error( 0, error ); +} + +bool SVNHandler::isConsideredModified( const FileStatus status ) const +{ + /* + * A file is modified if it is either: + * - locally modified for SVN + * - directory under SVN control but not the file + */ + + // ### TODO: what about moved and copied? + return status == LOCALLY_MODIFIED || status == NOT_IN_SVN; +} + +SVNOutputCollector::SVNOutputCollector( KProcess* p ) + : m_process(0) +{ + setProcess( p ); +} + +void SVNOutputCollector::setProcess( KProcess* p ) +{ + if( m_process ) + m_process->disconnect( this ); + + m_process = p; + if( p ) { + connect( p, SIGNAL(receivedStdout(KProcess*, char*, int)), + this, SLOT(slotGatherStdout(KProcess*, char*, int)) ); + connect( p, SIGNAL(receivedStderr(KProcess*, char*, int)), + this, SLOT(slotGatherStderr(KProcess*, char*, int)) ); + } + + m_gatheredOutput.truncate( 0 ); + m_stderrOutput.truncate( 0 ); + m_stdoutOutput.truncate( 0 ); +} + +void SVNOutputCollector::slotGatherStderr( KProcess*, char* data, int len ) +{ + m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) ); + m_stderrOutput.append( QString::fromLocal8Bit( data, len ) ); +} + +void SVNOutputCollector::slotGatherStdout( KProcess*, char* data, int len ) +{ + m_gatheredOutput.append( QString::fromLocal8Bit( data, len ) ); + m_stdoutOutput.append( QString::fromLocal8Bit( data, len ) ); +} + +#include "svnhandler.moc" + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/kbabel/catalogmanager/libsvn/svnhandler.h b/kbabel/catalogmanager/libsvn/svnhandler.h new file mode 100644 index 00000000..67c86d73 --- /dev/null +++ b/kbabel/catalogmanager/libsvn/svnhandler.h @@ -0,0 +1,138 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005, 2006 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#ifndef SVNHANDLER_H +#define SVNHANDLER_H + +// Qt include files +#include <qmap.h> +#include <qobject.h> +// Project specific include files +#include "svndialog.h" +#include "svnresources.h" +// Forwarding Qt classes +class QString; +class QStringList; + +class KSharedConfig; + +/** + * This class is the backend for SVN support in Catalog Manager. + * + * @short Backend for SVN support in Catalog Manager + */ +class SVNHandler : public QObject +{ + Q_OBJECT + + public: + enum FileStatus { + NO_REPOSITORY, + NOT_IN_SVN, + LOCALLY_ADDED, + LOCALLY_REMOVED, + LOCALLY_MODIFIED, + CONFLICT, + UP_TO_DATE, + ERROR_IN_WC ///< The working copy has data that cannot be handled + }; + + SVNHandler( const QString& poBaseDir = QString::null, const QString& potBaseDir = QString::null ); + + void setPOBaseDir( const QString& dir ); + void setPOTBaseDir( const QString& dir ); + + FileStatus fstatus( const QString& filename ) const; + QString fileStatus( const FileStatus status ) const; + QString svnStatus( const QString& filename ) const; + + void execSVNCommand( QWidget* parent, SVN::Command cmd, const QString& filename, bool templates, KSharedConfig* config ); + void execSVNCommand( QWidget* parent, SVN::Command cmd, const QStringList& files, bool templates, KSharedConfig* config ); + + void setAutoUpdateTemplates( bool update ); + + /** + * True if the file was modified or has another status considered as a modification + */ + bool isConsideredModified( const FileStatus status ) const; + + signals: + void signalIsPORepository( bool ); + void signalIsPOTRepository( bool ); + void signalFilesCommitted( const QStringList& ); + + private: + void showDialog( QWidget* parent, SVN::Command cmd, const QStringList& files, const QString& commandLine, KSharedConfig* config ); + /// Check quickly if the file is part of a SVN repository + bool isInSvn( const QString& path ); + void checkToAdd( const QStringList& files ); + void processStatusOutput( const QString& status ); + void processDiff( QString output ); + + private: + QString _poBaseDir; + QString _potBaseDir; + bool _isPORepository; + bool _isPOTRepository; + bool _autoUpdateTemplates; + QString _addCommand; + + /** Mapping the output of 'svn status' against the filename. */ + QMap<QString,QString> map; +}; + +class SVNOutputCollector: public QObject +{ + Q_OBJECT + + public: + SVNOutputCollector( KProcess* ); + void setProcess( KProcess* ); + + const QString& getOutput() const { return m_gatheredOutput; } + const QString& getStderr() const { return m_stderrOutput; } + const QString& getStdout() const { return m_stdoutOutput; } + + private slots: + void slotGatherStderr( KProcess*, char*, int ); + void slotGatherStdout( KProcess*, char*, int ); + + private: + QString m_gatheredOutput; + QString m_stderrOutput; + QString m_stdoutOutput; + KProcess* m_process; +}; + +#endif // SVNHANDLER_H diff --git a/kbabel/catalogmanager/libsvn/svnresources.h b/kbabel/catalogmanager/libsvn/svnresources.h new file mode 100644 index 00000000..d9032a4f --- /dev/null +++ b/kbabel/catalogmanager/libsvn/svnresources.h @@ -0,0 +1,50 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Marco Wegner <mail@marcowegner.de> + Copyright (C) 2005 by Nicolas GOUTTE <goutte@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#ifndef SVNRESOURCES_H +#define SVNRESOURCES_H + +namespace SVN { + enum Command + { + Update, ///< svn update + Commit, ///< svn commit + StatusLocal, ///< svn status + StatusRemote, ///< svn status -u + Diff, ///< svn diff + Info ///< svn info + }; +} + +#endif // SVNRESOURCES_H diff --git a/kbabel/catalogmanager/lo16-app-catalogmanager.png b/kbabel/catalogmanager/lo16-app-catalogmanager.png Binary files differnew file mode 100644 index 00000000..27a7f453 --- /dev/null +++ b/kbabel/catalogmanager/lo16-app-catalogmanager.png diff --git a/kbabel/catalogmanager/lo32-app-catalogmanager.png b/kbabel/catalogmanager/lo32-app-catalogmanager.png Binary files differnew file mode 100644 index 00000000..eef514b4 --- /dev/null +++ b/kbabel/catalogmanager/lo32-app-catalogmanager.png diff --git a/kbabel/catalogmanager/main.cpp b/kbabel/catalogmanager/main.cpp new file mode 100644 index 00000000..868df92a --- /dev/null +++ b/kbabel/catalogmanager/main.cpp @@ -0,0 +1,232 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2001 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2001-2004 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#include "kbprojectmanager.h" +#include "catalogmanager.h" +#include "catalogmanageriface.h" +#include "catalog.h" +#include "catalogmanagerapp.h" +#include "poinfo.h" + +#include "version.h" +#include "resources.h" + +#include <dcopclient.h> +#include <kaboutdata.h> +#include <kcmdlineargs.h> +#include <kcursor.h> +#include <klocale.h> +#include <kiconloader.h> +#include <kmessagebox.h> +#include <kapplication.h> +#include <kwin.h> +#include <kmainwindow.h> + +#include <qfile.h> +#include <qfileinfo.h> +#include <qregexp.h> +#include <qtimer.h> + +CatalogManager *CatalogManagerApp::_view = 0; + +CatalogManagerApp::CatalogManagerApp() + : KApplication() +{ + kbInterface = new CatalogManagerInterface; + _view = 0; + _preferredWindow = 0; +} + +CatalogManagerApp::~CatalogManagerApp() +{ + delete kbInterface; + KBabel::PoInfo::cacheWrite(); +} + +void CatalogManagerApp::setPreferredWindow(WId id) +{ + _preferredWindow = id; + if( _view ) + { + _view->raise(); + KWin::activateWindow(_view->winId()); + } +} + +void CatalogManagerApp::updatedFile(QCString url) +{ + if( _view ) + _view->updateFile(url); +} + +QCString CatalogManagerApp::findNextFile() +{ + QString reply = ""; + if( !CatalogManager::_foundFilesList.isEmpty() ) + { + reply = CatalogManager::_foundFilesList.first(); + CatalogManager::_foundFilesList.pop_front(); + if( _view ) _view->decreaseNumberOfFound(); + } else + { + if( !CatalogManager::_toBeSearched.isEmpty() ) + reply = QString(""); // nothing found yet + else + return QCString(); // not found definitely + } + + return reply.utf8(); +} + +int CatalogManagerApp::newInstance() +{ + if( isRestored() ) + { + int n = 1; + while (KMainWindow::canBeRestored(n)){ + CatalogManager* cm = new CatalogManager(); + cm->restore(n); + n++; + + // this view will be used as DCOP dispatcher + if( !_view ) + _view = cm; + } + } + else + { + KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); + + QString configfile = args->getOption("project"); + + if( !configfile.isEmpty() ) + { + QFileInfo fi( configfile ); + configfile = fi.absFilePath(); + } + else + { + configfile = KBabel::ProjectManager::defaultProjectName(); + } + + _view=new CatalogManager(configfile); + + _view->setPreferredWindow( _preferredWindow ); + _view->show(); + _view->raise(); + KWin::activateWindow(_view->winId()); + + args->clear(); + } + + return 0; +} + +CatalogManagerInterface::CatalogManagerInterface() + : DCOPObject("CatalogManagerIFace") +{ +} + +void CatalogManagerInterface::setPreferredWindow( WId id ) +{ + CatalogManagerApp::setPreferredWindow(id); +} + +QCString CatalogManagerInterface::findNextFile() +{ + return CatalogManagerApp::findNextFile(); +} + +void CatalogManagerInterface::updatedFile( QCString url ) +{ + CatalogManagerApp::updatedFile(url); +} + +static KCmdLineOptions options[] = +{ + {"project <configfile>",I18N_NOOP("File to load configuration from"),0}, + KCmdLineLastOption +}; + + +int main(int argc, char **argv) +{ + KLocale::setMainCatalogue("kbabel"); + KAboutData about("catalogmanager",I18N_NOOP("KBabel - Catalog Manager"),VERSION, + I18N_NOOP("An advanced catalog manager for KBabel"),KAboutData::License_GPL, + I18N_NOOP("(c) 1999,2000,2001,2002,2003,2004,2005,2006 The KBabel developers"),0,"http://kbabel.kde.org"); + + about.addAuthor("Matthias Kiefer",I18N_NOOP("Original author"),"kiefer@kde.org"); + about.addAuthor("Stanislav Visnovsky",I18N_NOOP("Current maintainer, porting to KDE3/Qt3.") + ,"visnovsky@kde.org"); + about.addAuthor("Nicolas Goutte", I18N_NOOP("Current maintainer"), "goutte@kde.org"); + + about.addCredit("Claudiu Costin",I18N_NOOP("Wrote documentation and sent " + "many bug reports and suggestions for improvements.") + ,"claudiuc@kde.org"); + about.addCredit("Thomas Diehl",I18N_NOOP("Gave many suggestions for the GUI " + "and the behavior of KBabel. He also contributed the beautiful splash screen.") + ,"thd@kde.org"); + about.addCredit("Wolfram Diestel" + ,I18N_NOOP("Wrote diff algorithm, fixed KSpell and gave a lot " + "of useful hints."),"wolfram@steloj.de"); + about.addCredit("Stephan Kulow",I18N_NOOP("Helped keep KBabel up to date " + "with the KDE API and gave a lot of other help."),"coolo@kde.org"); + about.addCredit("Dwayne Bailey",I18N_NOOP("Various validation plugins.") + ,"dwayne@translate.org.za"); + about.addCredit("SuSE GmbH" + ,I18N_NOOP("Sponsored development of KBabel for a while.") + ,"suse@suse.de","http://www.suse.de"); + about.addCredit("Bram Schoenmakers",I18N_NOOP("Support for making diffs and some minor " + "improvements."),"bramschoenmakers@kde.nl"); + + about.addCredit("Trolltech", I18N_NOOP("KBabel contains code from Qt"), 0, "http://www.trolltech.com"); + + about.addCredit("GNU gettext", I18N_NOOP("KBabel contains code from GNU gettext"), 0, "http://www.gnu.org/software/gettext/"); + + // Initialize command line args + KCmdLineArgs::init(argc, argv, &about); + + // Tell which options are supported + KCmdLineArgs::addCmdLineOptions( options ); + + // Add options from other components + KApplication::addCmdLineOptions(); + + CatalogManagerApp app; + + app.newInstance(); + + return app.exec(); +} diff --git a/kbabel/catalogmanager/markpatterndialog.cpp b/kbabel/catalogmanager/markpatterndialog.cpp new file mode 100644 index 00000000..efe893a2 --- /dev/null +++ b/kbabel/catalogmanager/markpatterndialog.cpp @@ -0,0 +1,172 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2003 by Marco Wegner <mail@marcowegner.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#include <qcheckbox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qradiobutton.h> + +#include <kcombobox.h> +#include <kcompletion.h> +#include <kconfig.h> +#include <kglobal.h> +#include <klocale.h> +#include <kparts/componentfactory.h> +#include <kregexpeditorinterface.h> + +#include "markpatterndialog.h" +#include "markpatternwidget.h" + +MarkPatternDialog::MarkPatternDialog(QWidget * parent, const char * name) + : KDialogBase(parent, name, true, 0, Ok|Cancel, Ok) +{ + actionButton(Ok)->setEnabled(false); + + mainWidget = new MarkPatternWidget(this); + + connect (mainWidget->combo, SIGNAL(textChanged(const QString&)), + this, SLOT(slotComboTextChanged(const QString&))); + + comboCompletion = mainWidget->combo->completionObject( ); + + regexpEditDialog = 0; + if (!KTrader::self( )->query("KRegExpEditor/KRegExpEditor").isEmpty( )) { + connect(mainWidget->regexpButton, SIGNAL(clicked( )), this, SLOT(slotRegexpButtonClicked( ))); + } else { + disconnect(mainWidget->useRegExp, 0, mainWidget->regexpButton, 0); + delete mainWidget->regexpButton; + mainWidget->regexpButton = 0; + } + + restoreSettings( ); + + actionButton(Ok)->setEnabled(!mainWidget->combo->currentText( ).isEmpty( )); + mainWidget->combo->setFocus( ); + setMainWidget( mainWidget); +} + +void MarkPatternDialog::accept( ) +{ + // Update the list of patterns. + patternList.remove(mainWidget->combo->currentText( )); + patternList.prepend(mainWidget->combo->currentText( )); + while (patternList.count( ) > 10) + patternList.remove(patternList.last( )); + + saveSettings( ); + KDialogBase::accept( ); +} + +QString MarkPatternDialog::pattern( ) +{ + return mainWidget->combo->currentText( ); +} + +bool MarkPatternDialog::isCaseSensitive( ) +{ + return mainWidget->caseSensitive->isChecked( ); +} + +bool MarkPatternDialog::includeTemplates( ) +{ + return mainWidget->inclTemplates->isChecked( ); +} + +bool MarkPatternDialog::useRegExp( ) +{ + return mainWidget->useRegExp->isChecked( ); +} + +void MarkPatternDialog::setMode(bool markMode) +{ + if (markMode) { + mainWidget->mainLabel->setText(i18n("Ma&rk files which match the following pattern:")); + setButtonOKText(i18n("&Mark Files")); + } else { + mainWidget->mainLabel->setText(i18n("Unma&rk files which match the following pattern:")); + setButtonOKText(i18n("Un&mark Files")); + } +} + +void MarkPatternDialog::slotComboTextChanged(const QString& text) +{ + actionButton(Ok)->setEnabled(!text.isEmpty( )); +} + +void MarkPatternDialog::slotRegexpButtonClicked( ) +{ + if (!regexpEditDialog) + regexpEditDialog = KParts::ComponentFactory::createInstanceFromQuery<QDialog>( + "KRegExpEditor/KRegExpEditor", QString::null, this); + + KRegExpEditorInterface * iface = dynamic_cast<KRegExpEditorInterface *>(regexpEditDialog); + + if (iface) { + iface->setRegExp(mainWidget->combo->currentText( )); + if (regexpEditDialog->exec( ) == QDialog::Accepted) + mainWidget->combo->setCurrentText(iface->regExp( )); + } +} + +void MarkPatternDialog::restoreSettings( ) +{ + KConfig * config = KGlobal::config( ); + config->setGroup("MarkPatternDialog"); + + patternList = config->readListEntry("Patterns"); + mainWidget->combo->insertStringList(patternList); + comboCompletion->insertItems(patternList); + mainWidget->caseSensitive->setChecked(config->readBoolEntry("CaseSensitive", false)); + mainWidget->inclTemplates->setChecked(config->readBoolEntry("IncludeTemplates", false)); + + bool rx = config->readBoolEntry("UseRegExp", false); + if (rx) + mainWidget->useRegExp->setChecked(true); + else + mainWidget->useWildcards->setChecked(true); + if (mainWidget->regexpButton) + mainWidget->regexpButton->setEnabled(mainWidget->useRegExp->isChecked( )); +} + +void MarkPatternDialog::saveSettings( ) +{ + KConfig * config = KGlobal::config( ); + config->setGroup("MarkPatternDialog"); + + config->writeEntry("Patterns", patternList); + config->writeEntry("CaseSensitive", mainWidget->caseSensitive->isChecked( )); + config->writeEntry("IncludeTemplates", mainWidget->inclTemplates->isChecked( )); + config->writeEntry("UseRegExp", mainWidget->useRegExp->isChecked( )); +} + +#include "markpatterndialog.moc" diff --git a/kbabel/catalogmanager/markpatterndialog.h b/kbabel/catalogmanager/markpatterndialog.h new file mode 100644 index 00000000..c8ec1218 --- /dev/null +++ b/kbabel/catalogmanager/markpatterndialog.h @@ -0,0 +1,75 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2003 by Marco Wegner <mail@marcowegner.de> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ + + +#ifndef MARKPATTERNDIALOG_H +#define MARKPATTERNDIALOG_H + +#include <kdialogbase.h> + +class KCompletion; + +class MarkPatternWidget; + +class MarkPatternDialog : public KDialogBase +{ + Q_OBJECT + + public: + MarkPatternDialog(QWidget * parent, const char * name = 0); + + QString pattern( ); + bool isCaseSensitive( ); + bool useRegExp( ); + bool includeTemplates( ); + + void setMode(bool markMode); + + protected: + virtual void accept( ); + void restoreSettings( ); + void saveSettings( ); + + protected slots: + void slotComboTextChanged(const QString& text); + void slotRegexpButtonClicked( ); + + private: + MarkPatternWidget * mainWidget; + QDialog * regexpEditDialog; + + QStringList patternList; + + KCompletion * comboCompletion; +}; + +#endif // MARKPATTERNDIALOG_H diff --git a/kbabel/catalogmanager/markpatternwidget.ui b/kbabel/catalogmanager/markpatternwidget.ui new file mode 100644 index 00000000..b4b8745e --- /dev/null +++ b/kbabel/catalogmanager/markpatternwidget.ui @@ -0,0 +1,127 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>MarkPatternWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>MarkPatternWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>374</width> + <height>276</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>mainLabel</cstring> + </property> + <property name="text"> + <string>To be set dynamically:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>combo</cstring> + </property> + </widget> + <widget class="KComboBox"> + <property name="name"> + <cstring>combo</cstring> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + <widget class="QButtonGroup"> + <property name="name"> + <cstring>buttonGroup1</cstring> + </property> + <property name="title"> + <string>Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>caseSensitive</cstring> + </property> + <property name="text"> + <string>C&ase sensitive</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>inclTemplates</cstring> + </property> + <property name="text"> + <string>&Include templates</string> + </property> + </widget> + <widget class="QRadioButton" row="3" column="0"> + <property name="name"> + <cstring>useWildcards</cstring> + </property> + <property name="text"> + <string>Use &wildcards</string> + </property> + </widget> + <widget class="QPushButton" row="4" column="1"> + <property name="name"> + <cstring>regexpButton</cstring> + </property> + <property name="text"> + <string>&Edit</string> + </property> + </widget> + <widget class="QRadioButton" row="4" column="0"> + <property name="name"> + <cstring>useRegExp</cstring> + </property> + <property name="text"> + <string>Use regu&lar expression</string> + </property> + </widget> + <widget class="Line" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>useRegExp</sender> + <signal>toggled(bool)</signal> + <receiver>regexpButton</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<includes> + <include location="global" impldecl="in implementation">kcombobox.h</include> +</includes> +<forwards> + <forward>class KComboBox;</forward> +</forwards> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>klineedit.h</includehint> +</includehints> +</UI> diff --git a/kbabel/catalogmanager/multiroughtransdlg.cpp b/kbabel/catalogmanager/multiroughtransdlg.cpp new file mode 100644 index 00000000..874b9c3e --- /dev/null +++ b/kbabel/catalogmanager/multiroughtransdlg.cpp @@ -0,0 +1,148 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 1999-2001 by Matthias Kiefer + <matthias.kiefer@gmx.de> + 2002 by Stanislav Visnovsky <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#include "catalog.h" +#include "catmanlistitem.h" +#include "multiroughtransdlg.h" + +#include <qlabel.h> +#include <qlayout.h> + +#include <kdebug.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprogress.h> +#include <kurl.h> + +using namespace KBabel; + +MultiRoughTransDlg::MultiRoughTransDlg(KBabelDictBox *dict, QPtrList<CatManListItem> files + , QWidget *parent,const char *name) + : RoughTransDlg(dict, new Catalog(), parent, name ) + ,_fileList(files) +{ + QWidget* bars = static_cast<QWidget*>(progressbar->parent()); + QLabel* label = new QLabel( i18n("Files:"), bars ); + filesProgressbar = new KProgress(bars,"files progressbar"); + filesProgressbar->setTextEnabled(true); + filesProgressbar->setFormat("%v/%m (%p%)"); + filesProgressbar->setTotalSteps(files.count()); + QHBoxLayout* mylayout= new QHBoxLayout(bars->layout()); + mylayout->add(label); + mylayout->add(filesProgressbar); + + msgButtonClicked(0); +} + +void MultiRoughTransDlg::msgButtonClicked(int id) +{ + RoughTransDlg::msgButtonClicked(id); + + enableButton(User1,true); +} + +void MultiRoughTransDlg::translate() +{ + for ( CatManListItem* it = _fileList.first(); it ; it = _fileList.next() ) + { + if( it->hasPo() ) + { + KURL url( it->poFile() ); + if( catalog->openURL( url ) != OK ) + { + KMessageBox::error(this, i18n("Error while trying to read file:\n %1\n" + "Maybe it is not a valid PO file.").arg(url.prettyURL())); + filesProgressbar->advance(1); + continue; + } + } else + if( it->hasPot() ) + { + KURL url( it->poFile() ); + KURL poturl( it->potFile() ); + if( catalog->openURL( poturl, url ) != OK ) + { + KMessageBox::error(this, i18n("Error while trying to read file:\n %1\n" + "Maybe it is not a valid PO file.").arg(poturl.prettyURL())); + filesProgressbar->advance(1); + continue; + } + } + + RoughTransDlg::translate(); + + if( stop || cancel ) break; + + if( catalog->isModified() ) catalog->saveFile(); + + it->forceUpdate(); + filesProgressbar->advance(1); + } + + filesProgressbar->setValue(_fileList.count()); + + showAllStatistics(); +} + +void MultiRoughTransDlg::showAllStatistics() +{ + int tt, ptc, etc; + + statistics( tt, ptc, etc); + + // sanity check + if( tt == 0 ) tt = 1; + + int nothing=tt-ptc-etc; + KLocale *locale = KGlobal::locale(); + QString statMsg = i18n("Result of the translation:\n" + "Edited entries: %1\n" + "Exact translations: %2 (%3%)\n" + "Approximate translations: %4 (%5%)\n" + "Nothing found: %6 (%7%)") + .arg( locale->formatNumber(tt,0) ) + .arg( locale->formatNumber(etc,0) ) + .arg( locale->formatNumber( ((double)(10000*etc/tt))/100) ) + .arg( locale->formatNumber(ptc,0) ) + .arg( locale->formatNumber(((double)(10000*ptc/tt))/100) ) + .arg( locale->formatNumber(nothing,0) ) + .arg( locale->formatNumber(((double)(10000*nothing/tt)/100) ) ); + + KMessageBox::information(this, statMsg + , i18n("Rough Translation Statistics")); + + accept(); +} + +#include "multiroughtransdlg.moc" diff --git a/kbabel/catalogmanager/multiroughtransdlg.h b/kbabel/catalogmanager/multiroughtransdlg.h new file mode 100644 index 00000000..8bda58e2 --- /dev/null +++ b/kbabel/catalogmanager/multiroughtransdlg.h @@ -0,0 +1,63 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef MULTIROUGHTRANSDLG_H +#define MULTIROUGHTRANSDLG_H + +#include <roughtransdlg.h> + +class CatManListItem; + +class MultiRoughTransDlg : public RoughTransDlg +{ + Q_OBJECT + +public: + MultiRoughTransDlg(KBabelDictBox* dictBox, QPtrList<CatManListItem> list, QWidget *parent + , const char *name=0); + +protected slots: + virtual void translate(); + // we show statistics at different point + virtual void showStatistics() {} + virtual void showAllStatistics(); + + // we need to enable Start button at different conditions + virtual void msgButtonClicked(int); + +private: + + QPtrList<CatManListItem> _fileList; + KProgress *filesProgressbar; +}; + +#endif // ROUGHTRANSDLG_H diff --git a/kbabel/catalogmanager/validateprogress.cpp b/kbabel/catalogmanager/validateprogress.cpp new file mode 100644 index 00000000..9075f24e --- /dev/null +++ b/kbabel/catalogmanager/validateprogress.cpp @@ -0,0 +1,313 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-2003 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#include "validateprogress.h" +#include "validateprogresswidget.h" +#include "catmanlistitem.h" +#include "catmanresource.h" + +#include <kdebug.h> +#include <kdatatool.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> +#include <kprogress.h> +#include <ksqueezedtextlabel.h> + +#include <qlistbox.h> +#include <qtimer.h> + +#define ID_ERROR_OPEN 1 +#define ID_ERROR_IGNORE 2 + +// version identification for validation ignores +#define IGNOREFILE_VERSION 0x00 + +ValidateProgressDialog::ValidateProgressDialog(const QString& ignoreURL, QWidget *parent,const char *name) + : KDialogBase(parent,name,true,i18n("Caption of dialog","Validation") + , Close, Close) + , _ignoreURL(ignoreURL), _tool(0), _stopped(false) + , _ignoreFuzzy(false), _setAsFuzzy(false) + +{ + _mainWidget = new ValidateProgressWidget(this); + setMainWidget(_mainWidget); + setInitialSize( QSize(400, 300) ); + + _errors.clear(); + _ignores.clear(); + + readIgnores(); + + _errorMenu = new KPopupMenu(this); + _errorMenu->insertItem(i18n("&Open"),ID_ERROR_OPEN); + _errorMenu->insertItem(i18n("&Ignore"),ID_ERROR_IGNORE); + + connect( this, SIGNAL(closeClicked()), this, SLOT(stop())); + connect( _mainWidget->_errorList, SIGNAL( doubleClicked(QListBoxItem *)), + this, SLOT( errorItemDoubleClicked(QListBoxItem *))); + + connect( _mainWidget->_errorList, SIGNAL( contextMenuRequested(QListBoxItem *, const QPoint &)), + this, SLOT( showContextMenu(QListBoxItem *, const QPoint &))); +} + +ValidateProgressDialog::~ValidateProgressDialog() +{ + writeIgnores(); +} + +void ValidateProgressDialog::validate( const KDataToolInfo &tool, const QPtrList<CatManListItem> files ) +{ + if( files.isEmpty() ) return; + + _errors.clear(); + + KDataTool* t = tool.createTool(); + + if( !t ) + { + KMessageBox::error( this, i18n("Cannot instantiate a validation tool.\n" + "Please check your installation."), i18n("Validation Tool Error") ); + return; + } + + _tool = t; + _toolID = tool.service()->library(); + _files = files; + + _mainWidget->_errorList->clear(); + _mainWidget->_currentTool->setText(*(tool.userCommands().at(0))); + _mainWidget->_overallProgress->setTotalSteps(files.count()); + _mainWidget->_overallProgress->setValue(0); + + _stopped = false; + + QTimer::singleShot( 0, this, SLOT(validate_internal()) ); + + exec(); + + _stopped = true; +} + +void ValidateProgressDialog::validate_internal() +{ + uint checked=0; + uint errors=0; + uint ignorederrors=0; + + for( CatManListItem* it=_files.first() ; it && !_stopped ; it = _files.next() ) + { + _mainWidget->_currentFile->setText( it->poFile() ); + + checked++; + + _mainWidget->_currentFileProgress->setTotalSteps(100); + _mainWidget->_currentFileProgress->setValue(0); + + it->checkErrors(_tool,_mainWidget, _ignoreFuzzy, _setAsFuzzy); + + bool noHeader = true; + + if( it->hasErrors() ) + { + QValueList<IgnoreItem> err = it->errors(); + + for( QValueList<IgnoreItem>::Iterator errit = err.begin(); errit!=err.end() ; ++errit ) + { + IgnoreItem item = (*errit); + + QValueList<IgnoreItem>::Iterator ig; + for( ig = _ignores.begin() ; ig != _ignores.end() ; ++ig ) + { + if( (*ig).validationTool == _toolID && + (*ig).msgid == item.msgid && + (*ig).msgstr == item.msgstr && + (*ig).fileURL == item.fileURL ) break; + } + + if( ig != _ignores.end() ) + { + ++ignorederrors; + continue; + } ++errors; + + if( noHeader ) + { + _mainWidget->_errorList->insertItem( ICON_ERROR, it->package() ); + _errors.insert( it->package(), err.first() ); + noHeader = false; + } + + QString errortext=QString::number(item.index+1)+": " + item.msgid.first().left(50); + errortext.replace("\n"," "); + if( item.msgid.first().length() > 50 ) errortext+="..."; + _mainWidget->_errorList->insertItem( errortext); + + _errors.insert( errortext, item ); + } + } + + _mainWidget->_currentFileProgress->setValue(100); + + _mainWidget->_overallProgress->advance(1); + } + + if( !_stopped ) + { + KMessageBox::information(this, i18n("Validation done.\n" + "\n" + "Checked files: %1\n" + "Number of errors: %2\n" + "Number of ignored errors: %3").arg(checked).arg(errors).arg(ignorederrors),i18n("Validation Done")); + } + + delete _tool; + _tool = 0; + _files.clear(); +} + +void ValidateProgressDialog::stop() +{ + _stopped = true; +} + +void ValidateProgressDialog::errorItemDoubleClicked(QListBoxItem * item) +{ + QString it = item->text(); + + bool ok =false; + int offset = it.find(":"); + + int num; + if( offset < -1 ) num = 0; + else + { + num = it.left(offset).toInt(&ok); + if( !ok ) num = 0; + } + + QListBoxItem* package=item; + + while( package && !package->text().startsWith("/") ) package=package->prev(); + + if( !package ) + { + kdWarning() << "Unable to find the package for the error" << endl; + return; + } + + emit errorDoubleClicked(package->text(), num-1 ); +} + +void ValidateProgressDialog::showContextMenu(QListBoxItem * item, const QPoint & pos) +{ + // disable ignore for whole package + _errorMenu->setItemEnabled(ID_ERROR_IGNORE, item->pixmap()==0 ); + int result = _errorMenu->exec(pos); + switch( result ) + { + case ID_ERROR_OPEN: + errorItemDoubleClicked( item ); + break; + case ID_ERROR_IGNORE: + IgnoreItem it = _errors.find(item->text()).data(); + + // if there is no pixmap, it's the whole file + if( !item->pixmap() ) + { + it.validationTool = _toolID; + _ignores.append( it ); + } + break; + } +} + +void ValidateProgressDialog::readIgnores() +{ + IgnoreItem item; + + QFile ignoreFile( _ignoreURL ); + if( ignoreFile.open( IO_ReadOnly ) ) { + QDataStream s( &ignoreFile ); + QString url; + int version; + + s >> version; + if( version == IGNOREFILE_VERSION ) // Only read if correct versi + { + _ignores.clear(); + + while( !s.atEnd() ) { + s >> item; + _ignores.append(item); + } + } + ignoreFile.close(); + } +} + +void ValidateProgressDialog::writeIgnores() +{ + QFile ignoreFile( _ignoreURL ); + if( ignoreFile.open( IO_WriteOnly ) ) { + QDataStream s( &ignoreFile ); + QString url; + int version = IGNOREFILE_VERSION; + + s << version; + + for( QValueList<IgnoreItem>::Iterator it = _ignores.begin(); it!=_ignores.end(); ++it) + { + s << (*it); + } + ignoreFile.close(); + } +} + +QDataStream & operator<<( QDataStream & stream, const IgnoreItem & i ) +{ + return stream << i.fileURL + << i.msgid + << i.msgstr + << i.index + << i.validationTool; +} + +QDataStream & operator>>( QDataStream & stream, IgnoreItem & i ) { + return stream >> i.fileURL + >> i.msgid + >> i.msgstr + >> i.index + >> i.validationTool; +} + +#include "validateprogress.moc" diff --git a/kbabel/catalogmanager/validateprogress.h b/kbabel/catalogmanager/validateprogress.h new file mode 100644 index 00000000..05133889 --- /dev/null +++ b/kbabel/catalogmanager/validateprogress.h @@ -0,0 +1,109 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2002-203 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +**************************************************************************** */ +#ifndef VALIDATEDLG_H +#define VALIDATEDLG_H + +#include <qmap.h> + +#include <kdialogbase.h> +#include <kurl.h> + +class CatManListItem; +class ValidateProgressWidget; +class KDataToolInfo; +class KDataTool; +class KPopupMenu; + +struct IgnoreItem +{ + KURL fileURL; + QStringList msgid; + QStringList msgstr; + uint index; + QString validationTool; +}; + +QDataStream & operator<<( QDataStream & stream, const IgnoreItem &ident ); +QDataStream & operator>>( QDataStream & stream, IgnoreItem & ident); + +class ValidateProgressDialog : public KDialogBase +{ + Q_OBJECT + +public: + ValidateProgressDialog(const QString& ignoreURL, QWidget* parent, const char *name=0); + virtual ~ValidateProgressDialog(); + + void setIgnoreFuzzy(bool enable) { _ignoreFuzzy = enable; } + void setMarkAsFuzzy(bool enable) { _setAsFuzzy = enable; } + +public slots: + void validate(const KDataToolInfo &tool, const QPtrList<CatManListItem> files); + +signals: + void errorDoubleClicked(const QString file, const int messageNumber); + +private slots: + /** implementation of the validation itself */ + void validate_internal(); + + /** call this to stop current validation*/ + void stop(); + + /** If user doubleclicked an item, this slot will be invoked. + * It emits errorDoubleClicked signal for corresponding error*/ + void errorItemDoubleClicked(QListBoxItem * item); + + /** show our context menu */ + void showContextMenu(QListBoxItem * item, const QPoint & pos); + +private: + void readIgnores(); + void writeIgnores(); + + ValidateProgressWidget *_mainWidget; + QString _ignoreURL; + KDataTool* _tool; + QString _toolID; + QPtrList<CatManListItem> _files; + bool _stopped; + KPopupMenu* _errorMenu; + + bool _ignoreFuzzy; + bool _setAsFuzzy; + + QValueList<IgnoreItem> _ignores; + QMap<QString,IgnoreItem> _errors; +}; + +#endif // VALIDATEDLG_H diff --git a/kbabel/catalogmanager/validateprogresswidget.ui b/kbabel/catalogmanager/validateprogresswidget.ui new file mode 100644 index 00000000..a181806b --- /dev/null +++ b/kbabel/catalogmanager/validateprogresswidget.ui @@ -0,0 +1,129 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>ValidateProgressWidget</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ValidateProgressWidget</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>448</width> + <height>295</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout2</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>_currentAction</cstring> + </property> + <property name="minimumSize"> + <size> + <width>92</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Current:</string> + </property> + </widget> + <widget class="KProgress" row="3" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>_overallProgress</cstring> + </property> + </widget> + <widget class="KSqueezedTextLabel" row="0" column="2"> + <property name="name"> + <cstring>_currentTool</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Overall:</string> + </property> + </widget> + <widget class="KProgress" row="2" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>_currentFileProgress</cstring> + </property> + </widget> + <widget class="KSqueezedTextLabel" row="1" column="2"> + <property name="name"> + <cstring>_currentFile</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>_currentLabel</cstring> + </property> + <property name="text"> + <string>Current file:</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel3_2</cstring> + </property> + <property name="text"> + <string>Validation:</string> + </property> + </widget> + </grid> + </widget> + <widget class="QListBox"> + <item> + <property name="text"> + <string>New Item</string> + </property> + </item> + <property name="name"> + <cstring>_errorList</cstring> + </property> + </widget> + </vbox> +</widget> +<connections> + <connection> + <sender>ValidateProgressWidget</sender> + <signal>setValidationProgressBar(int)</signal> + <receiver>_currentFileProgress</receiver> + <slot>setValue(int)</slot> + </connection> +</connections> +<includes> + <include location="local" impldecl="in implementation">validateprogresswidget.ui.h</include> +</includes> +<signals> + <signal>setValidationProgressBar(int)</signal> +</signals> +<slots> + <slot>setupFileProgressBar( QString text, int maxvalue )</slot> +</slots> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kprogress.h</includehint> + <includehint>ksqueezedtextlabel.h</includehint> + <includehint>kprogress.h</includehint> + <includehint>ksqueezedtextlabel.h</includehint> +</includehints> +</UI> diff --git a/kbabel/catalogmanager/validateprogresswidget.ui.h b/kbabel/catalogmanager/validateprogresswidget.ui.h new file mode 100644 index 00000000..88f36d60 --- /dev/null +++ b/kbabel/catalogmanager/validateprogresswidget.ui.h @@ -0,0 +1,48 @@ +/* **************************************************************************** + This file is part of KBabel + + Copyright (C) 2004 by Stanislav Visnovsky + <visnovsky@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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + In addition, as a special exception, the copyright holders give + permission to link the code of this program with any edition of + the Qt library by Trolltech AS, Norway (or with modified versions + of Qt that use the same license as Qt), and distribute linked + combinations including the two. You must obey the GNU General + Public License in all respects for all of the code used other than + Qt. If you modify this file, you may extend this exception to + your version of the file, but you are not obligated to do so. If + you do not wish to do so, delete this exception statement from + your version. + +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void ValidateProgressWidget::setupFileProgressBar( QString text, int maxvalue ) +{ + _currentFileProgress->setTotalSteps(maxvalue); + + QString t = text[0].upper()+text.mid(1)+":"; + + _currentAction->setText(t); + _currentAction->repaint(); +} diff --git a/kbabel/catalogmanager/validationoptions.ui b/kbabel/catalogmanager/validationoptions.ui new file mode 100644 index 00000000..61079ff3 --- /dev/null +++ b/kbabel/catalogmanager/validationoptions.ui @@ -0,0 +1,60 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>ValidationOptions</class> +<widget class="QWidget"> + <property name="name"> + <cstring>ValidationOptions</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>174</width> + <height>70</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout1</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>markAsFuzzy</cstring> + </property> + <property name="text"> + <string>Mark invalid as &fuzzy</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><p><b>Mark invalid as fuzzy</b><p> +<p>If you select this option, all items, +which identifies the tool as invalid, will be +marked as fuzzy and the resulting file +will be saved.</p></qt></string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>ignoreFuzzy</cstring> + </property> + <property name="text"> + <string>&Do not validate fuzzy</string> + </property> + <property name="whatsThis" stdset="0"> + <string><qt><p><b>Do not validate fuzzy</b><p> +<p>If you select this option, all items +marked as fuzzy will not be validated at all.</p></qt></string> + </property> + </widget> + </vbox> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +</UI> |