summaryrefslogtreecommitdiffstats
path: root/kdict
diff options
context:
space:
mode:
Diffstat (limited to 'kdict')
-rw-r--r--kdict/AUTHORS25
-rw-r--r--kdict/ChangeLog79
-rw-r--r--kdict/LICENSE125
-rw-r--r--kdict/Makefile.am33
-rw-r--r--kdict/README47
-rw-r--r--kdict/TODO2
-rw-r--r--kdict/actions.cpp335
-rw-r--r--kdict/actions.h111
-rw-r--r--kdict/applet/Makefile.am19
-rw-r--r--kdict/applet/kdictapplet.cpp405
-rw-r--r--kdict/applet/kdictapplet.desktop147
-rw-r--r--kdict/applet/kdictapplet.h101
-rw-r--r--kdict/application.cpp71
-rw-r--r--kdict/application.h39
-rw-r--r--kdict/dcopinterface.h54
-rw-r--r--kdict/dict.cpp1632
-rw-r--r--kdict/dict.h204
-rw-r--r--kdict/hi128-app-kdict.pngbin0 -> 14431 bytes
-rw-r--r--kdict/hi16-app-kdict.pngbin0 -> 779 bytes
-rw-r--r--kdict/hi32-app-kdict.pngbin0 -> 2101 bytes
-rw-r--r--kdict/hi48-app-kdict.pngbin0 -> 3891 bytes
-rw-r--r--kdict/hi64-app-kdict.pngbin0 -> 5901 bytes
-rw-r--r--kdict/hisc-app-kdict.svgzbin0 -> 5220 bytes
-rw-r--r--kdict/kdict.desktop153
-rw-r--r--kdict/kdictui.rc59
-rw-r--r--kdict/main.cpp56
-rw-r--r--kdict/matchview.cpp473
-rw-r--r--kdict/matchview.h105
-rw-r--r--kdict/options.cpp947
-rw-r--r--kdict/options.h229
-rw-r--r--kdict/pics/Makefile.am2
-rw-r--r--kdict/pics/cr16-action-define_clip.pngbin0 -> 917 bytes
-rw-r--r--kdict/pics/cr16-action-query_erase.pngbin0 -> 396 bytes
-rw-r--r--kdict/pics/cr22-action-define_clip.pngbin0 -> 1228 bytes
-rw-r--r--kdict/pics/cr32-action-define_clip.pngbin0 -> 2109 bytes
-rw-r--r--kdict/queryview.cpp618
-rw-r--r--kdict/queryview.h178
-rw-r--r--kdict/sets.cpp326
-rw-r--r--kdict/sets.h68
-rw-r--r--kdict/toplevel.cpp778
-rw-r--r--kdict/toplevel.h149
41 files changed, 7570 insertions, 0 deletions
diff --git a/kdict/AUTHORS b/kdict/AUTHORS
new file mode 100644
index 00000000..b81599fe
--- /dev/null
+++ b/kdict/AUTHORS
@@ -0,0 +1,25 @@
+Developers:
+Christian Gebauer <gebauer@kde.org>
+Matthias Hoelzer-Kluepfel <hoelzer@kde.org>
+
+Documentation:
+Christian Gebauer <gebauer@kde.org>
+
+Translators:
+Wolfram Diestel <wolfram@steloj.de>
+Otto Bruggeman <otto.bruggeman@home.nl>
+Mattias Newzella <newzella@linux.nu>
+Andris Maziks <andris.m@delfi.lv>
+Jaime Robles <jaime@kde.org>
+Pedro Morais <morais@kde.org>
+Andrey S. Cherepanov <andrey_tiger@i.am>
+Claudiu Costin <claudiuc@geocities.com>
+Erik Kjær Pedersen <erik@binghamton.edu>
+Stanislav Visnovsky <visnovsky@nenya.ms.mff.cuni.cz>
+Andy Rysin <arysin@yahoo.com>
+Dimitris Kamenopoulos <el97146@mail.ntua.gr>
+Meni Livne <meni@mail.com>
+Matthias Kiefer <kiefer@kde.org>
+Sinohara <shinobo@leo.bekkoame.ne.jp>
+Tamas Szanto <tszanto@mol.hu>
+Görkem Çetin <gorkem@kde.org> \ No newline at end of file
diff --git a/kdict/ChangeLog b/kdict/ChangeLog
new file mode 100644
index 00000000..d9513c75
--- /dev/null
+++ b/kdict/ChangeLog
@@ -0,0 +1,79 @@
+0.5.3
+ + recognize http and ftp urls in cross references
+ + convert characters that are incompatible with html
+ like <,>,& into &amp, etc.
+
+0.5.2
+ + Kdict is now part of the offical kdenetwork package
+ + support for IPv6 and socks-proxies
+ + up-to-date docbook-handbook
+ + code cleanup
+
+0.5
+ + dcop interface
+ + panel applet
+ + bugfixes: session management, small problems
+ with the toolbar editor
+
+0.4.1
+ + fixed CSS-issues with KDE 2.0.x
+ + fixed saving of results as html file
+
+0.4
+ + ported to KDE2
+ + full unicode support
+ + improved portability, should work in non-linux environments now
+ + the german gui-translation is missing in this release,
+ I will add it later on
+ + documentation is not yet converted to docbook
+
+0.3.1
+ + essential bugfix for older, libc5-based linux systems
+ (Thanks to Osvaldo Fornaro for testing)
+ + mini-howto for installing a local DICT-server
+
+0.3
+ + integrated implementation of the DICT-protocol,
+ dict(1) is no longer needed.
+ + match mode: At first all matches for a query are
+ displayed in a separate list, the user can then
+ choose the most interesting definitions.
+ + database sets: The user can create individual
+ compilations of the available databases and use
+ them in the same way as a single database.
+ + nicer/more configurable html-layout
+ + find dialog for locating text in the definitions
+ + the user can paste text into Kdict with the middle
+ mouse button. Kdict starts a new query with the pasted text
+ (analogue to Netscape).
+ + command to show detailed database information is
+ implemented ("show info")
+ + speed improvements:
+ * faster html-generation
+ * results are stored in a local cache, so they
+ are displayed instantly when the users wants to
+ browse back.
+ * Kdict holds the connection to the server
+ for a configurable amount of time.
+ + various gui improvements:
+ * improved statusbar
+ * unified preferences dialog
+ * all toolbars are now removable and remember
+ their position.
+ * new toolbar icons
+ + ...
+
+0.2
+ fixed some bugs (and introduced new ones ;-)
+ added various features:
+ + saving/printing of the queryresult
+ + query history
+ + improved html output
+ + improved command line interface
+ + html help
+ + Preferences dialogbox for fonts, colors, etc.
+ + Synonyms get displayed and handled like hyperlinks
+ + Automatically lookup of a word in the X clipboard
+ + ...
+
+0.1 Initial release
diff --git a/kdict/LICENSE b/kdict/LICENSE
new file mode 100644
index 00000000..4def90fc
--- /dev/null
+++ b/kdict/LICENSE
@@ -0,0 +1,125 @@
+kdict - The KDE Dictionary Client
+
+Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+copyright (C) 1998 by Matthias Hoelzer <hoelzer@kde.org>
+
+
+ Preamble
+
+ The intent of this document is to state the conditions under which a
+ Package may be copied, such that the Copyright Holder maintains some
+ semblance of artistic control over the development of the package,
+ while giving the users of the package the right to use and
+ distribute the Package in a more-or-less customary fashion, plus the
+ right to make reasonable modifications.
+
+ Definitions:
+
+ * "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+
+ * "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes of
+ the Copyright Holder.
+
+ * "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+
+ * "You" is you, if you're thinking about copying or distributing
+ this Package.
+
+ * "Reasonable copying fee" is whatever you can justify on the
+ basis of media cost, duplication charges, time of people
+ involved, and so on. (You will not be required to justify it to
+ the Copyright Holder, but only to the computing community at
+ large as a market that must bear the fee.)
+
+ * "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item.
+ It also means that recipients of the item may redistribute it
+ under the same conditions they received it.
+
+ 1. You may make and give away verbatim copies of the source form of
+ the Standard Version of this Package without restriction, provided
+ that you duplicate all of the original copyright notices and
+ associated disclaimers.
+
+ 2. You may apply bug fixes, portability fixes and other
+ modifications derived from the Public Domain or from the Copyright
+ Holder. A Package modified in such a way shall still be considered
+ the Standard Version.
+
+ 3. You may otherwise modify your copy of this Package in any way,
+ provided that you insert a prominent notice in each changed file
+ stating how and when you changed that file, and provided that you do
+ at least ONE of the following:
+
+ a) place your modifications in the Public Domain or
+ otherwise make them Freely Available, such as by posting
+ said modifications to Usenet or an equivalent medium, or
+ placing the modifications on a major archive site such as
+ ftp.uu.net, or by allowing the Copyright Holder to include
+ your modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation
+ or organization.
+
+ c) rename any non-standard executables so the names do not
+ conflict with standard executables, which must also be
+ provided, and provide a separate manual page for each
+ non-standard executable that clearly documents how it
+ differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright
+ Holder.
+
+ 4. You may distribute the programs of this Package in object code or
+ executable form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and
+ library files, together with instructions (in the manual
+ page or equivalent) on where to get the Standard Version.
+
+ b) accompany the distribution with the machine-readable
+ source of the Package with your modifications.
+
+ c) accompany any non-standard executables with their
+ corresponding Standard Version executables, giving the
+ non-standard executables non-standard names, and clearly
+ documenting the differences in manual pages (or
+ equivalent), together with instructions on where to get
+ the Standard Version.
+
+ d) make other distribution arrangements with the Copyright
+ Holder.
+
+ 5. You may charge a reasonable copying fee for any distribution of
+ this Package. You may charge any fee you choose for support of this
+ Package. You may not charge a fee for this Package itself. However,
+ you may distribute this Package in aggregate with other (possibly
+ commercial) programs as part of a larger (possibly commercial)
+ software distribution provided that you do not advertise this
+ Package as a product of your own.
+
+ 6. The scripts and library files supplied as input to or produced as
+ output from the programs of this Package do not automatically fall
+ under the copyright of this Package, but belong to whomever
+ generated them, and may be sold commercially, and may be aggregated
+ with this Package.
+
+ 7. C or perl subroutines supplied by you and linked into this
+ Package shall not be considered part of this Package.
+
+ 8. The name of the Copyright Holder may not be used to endorse or
+ promote products derived from this software without specific prior
+ written permission.
+
+ 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+ The End
+
+
+
diff --git a/kdict/Makefile.am b/kdict/Makefile.am
new file mode 100644
index 00000000..5cb60755
--- /dev/null
+++ b/kdict/Makefile.am
@@ -0,0 +1,33 @@
+## Makefile.am for kdict
+
+KDE_CXXFLAGS = $(USE_THREADS)
+
+SUBDIRS = applet pics
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = kdict.la
+
+# set the include path for X, qt and KDE
+AM_CPPFLAGS = $(all_includes)
+
+kdict_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -module $(KDE_PLUGIN)
+kdict_la_LIBADD = $(LIB_KFILE) $(LIB_KHTML) $(LIBPTHREAD) $(LIBRESOLV)
+kdict_la_SOURCES = dcopinterface.skel main.cpp actions.cpp dict.cpp options.cpp \
+ queryview.cpp toplevel.cpp sets.cpp matchview.cpp application.cpp
+
+# these are the headers for your project
+noinst_HEADERS = actions.h dict.h options.h queryview.h toplevel.h sets.h matchview.h application.h
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kdict.pot
+
+KDE_ICON = AUTO
+
+# this is where the kdelnk file will go
+xdg_apps_DATA = kdict.desktop
+
+rcdir = $(kde_datadir)/kdict
+rc_DATA = kdictui.rc
diff --git a/kdict/README b/kdict/README
new file mode 100644
index 00000000..894983ab
--- /dev/null
+++ b/kdict/README
@@ -0,0 +1,47 @@
+Kdict - The KDE Dictionary Client
+Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+copyright (c) 1998 by Matthias Hoelzer <hoelzer@kde.org>
+
+maintained by Christian Gebauer <gebauer@kde.org>
+
+Homepage: http://www.rhrk.uni-kl.de/~gebauerc/kdict/
+
+See LICENSE for the license of this programm.
+
+**************************************************************************
+
+Kdict is a graphical client for the DICT Protocol.
+It enables you to search through dictionary-like databases
+for a word or phrase, then displays suitable definitions.
+
+Kdict trys to ease basic as well as advanced queries. A separate list
+offers a convenient way to deal with the enormous number of matching
+words that a advanced query can return.
+
+The remainder of Kdict's user interface resembles a web browser:
+For instance, you can jump to the definition of a synonym by
+simply clicking on the highlighted word. The back/forward functionality
+is also implemented, enabling you to quickly go back to the result of
+previous queries.
+
+Kdict is able to process the content of the X clipboard, so it's easy
+to combine Kdict with your web browser or text editor.
+
+Kdict is now a real client, no additional software is needed.
+
+If your machine is behind a firewall, has no permanent internet
+connection or the server of dict.org is too slow for you, you can
+set up your own local server, all you need is available at
+http://www.dict.org.
+The advantages of a local server are optimal performance and
+the ability to install additional databases of your choice.
+The handbook contains a small tutorial for installation
+and links to databases.
+
+**************************************************************************
+
+For installing Kdict you need:
+
+- KDE 3.x
+- POSIX Threads
+
diff --git a/kdict/TODO b/kdict/TODO
new file mode 100644
index 00000000..5a1d2446
--- /dev/null
+++ b/kdict/TODO
@@ -0,0 +1,2 @@
+* offline-support:
+ accessing local database-files without running a dictd-server \ No newline at end of file
diff --git a/kdict/actions.cpp b/kdict/actions.cpp
new file mode 100644
index 00000000..5ca1aade
--- /dev/null
+++ b/kdict/actions.cpp
@@ -0,0 +1,335 @@
+/* -------------------------------------------------------------
+
+ actions.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ DictComboAction, special KAction subclasses used
+ DictLabelAction, in the toolbar
+ DictButtonAction
+
+ ------------------------------------------------------------- */
+
+#include "actions.h"
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+
+#include <kcombobox.h>
+#include <ktoolbar.h>
+
+
+DictComboAction::DictComboAction( const QString &text, QObject *parent, const char *name,
+ bool editable, bool autoSized )
+ : KAction( text, 0, parent, name ), m_editable(editable), m_autoSized(autoSized), m_compMode(KGlobalSettings::completionMode())
+{
+}
+
+
+DictComboAction::~DictComboAction()
+{
+}
+
+
+int DictComboAction::plug( QWidget *widget, int index )
+{
+ if ( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar* bar = static_cast<KToolBar*>( widget );
+ int id_ = KAction::getToolButtonID();
+
+ m_combo = new KComboBox(m_editable,bar);
+ m_combo->setCompletionMode(m_compMode);
+
+ bar->insertWidget( id_, m_combo->sizeHint().width(), m_combo, index );
+ bar->setItemAutoSized(id_,m_autoSized);
+
+ if ( m_combo ) {
+ connect(bar->getCombo(id_), SIGNAL(activated(const QString&)), SLOT(slotComboActivated(const QString&)));
+ connect(bar->getCombo(id_), SIGNAL(activated(int)), SLOT(slotComboActivated(int)));
+
+ if (m_editable)
+ m_combo->setInsertionPolicy( QComboBox::NoInsertion );
+ }
+
+ addContainer( bar, id_ );
+ connect( bar, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
+ return containerCount() - 1;
+ }
+
+ return -1;
+}
+
+
+void DictComboAction::unplug( QWidget *widget )
+{
+ if ( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar *bar = (KToolBar *)widget;
+
+ int idx = findContainer( bar );
+
+ if ( idx != -1 )
+ {
+ bar->removeItem( itemId( idx ) );
+ removeContainer( idx );
+ }
+
+ return;
+ }
+}
+
+
+QWidget* DictComboAction::widget()
+{
+ return m_combo;
+}
+
+
+void DictComboAction::setFocus()
+{
+ if (m_combo)
+ m_combo->setFocus();
+}
+
+
+QString DictComboAction::currentText() const
+{
+ if (m_combo)
+ return m_combo->currentText();
+ else
+ return QString::null;
+}
+
+void DictComboAction::selectAll()
+{
+ if (m_combo)
+ {
+ m_combo->lineEdit()->selectAll();
+ m_combo->lineEdit()->setFocus();
+ }
+}
+
+
+void DictComboAction::setEditText(const QString &s)
+{
+ if (m_combo && m_editable)
+ m_combo->setEditText(s);
+}
+
+
+void DictComboAction::setCurrentItem(int index)
+{
+ if (m_combo)
+ m_combo->setCurrentItem(index);
+}
+
+
+void DictComboAction::clearEdit()
+{
+ if (m_combo && m_editable)
+ m_combo->clearEdit();
+}
+
+
+void DictComboAction::clear()
+{
+ if (m_combo) {
+ m_combo->clear();
+ if (m_editable && m_combo->completionObject())
+ m_combo->completionObject()->clear();
+ }
+}
+
+
+void DictComboAction::setList(QStringList items)
+{
+ if (m_combo) {
+ m_combo->clear();
+ m_combo->insertStringList(items);
+ if (m_editable && m_combo->completionObject())
+ m_combo->completionObject()->setItems(items);
+ if (!m_autoSized)
+ m_combo->setFixedWidth(m_combo->sizeHint().width());
+ }
+}
+
+
+KGlobalSettings::Completion DictComboAction::completionMode()
+{
+ if (m_combo)
+ return m_combo->completionMode();
+ else
+ return m_compMode;
+ }
+
+
+void DictComboAction::setCompletionMode(KGlobalSettings::Completion mode)
+{
+ if (m_combo)
+ m_combo->setCompletionMode(mode);
+ else
+ m_compMode = mode;
+}
+
+
+void DictComboAction::slotComboActivated(int i)
+{
+ emit(activated(i));
+}
+
+
+void DictComboAction::slotComboActivated(const QString &s)
+{
+ emit(activated(s));
+}
+
+
+//*********************************************************************************
+
+
+DictLabelAction::DictLabelAction( const QString &text, QObject *parent, const char *name )
+ : KAction( text, 0, parent, name )
+{
+}
+
+
+DictLabelAction::~DictLabelAction()
+{
+}
+
+
+int DictLabelAction::plug( QWidget *widget, int index )
+{
+ if ( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar *tb = (KToolBar *)widget;
+
+ int id = KAction::getToolButtonID();
+
+ QLabel *label = new QLabel( text(), widget, "kde toolbar widget" );
+ label->setMinimumWidth(label->sizeHint().width());
+ label->setBackgroundMode( Qt::PaletteButton );
+ label->setAlignment(AlignCenter | AlignVCenter);
+ label->adjustSize();
+
+ tb->insertWidget( id, label->width(), label, index );
+
+ addContainer( tb, id );
+
+ connect( tb, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
+
+ m_label = label;
+
+ return containerCount() - 1;
+ }
+
+ return -1;
+}
+
+
+void DictLabelAction::unplug( QWidget *widget )
+{
+ if ( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar *bar = (KToolBar *)widget;
+
+ int idx = findContainer( bar );
+
+ if ( idx != -1 )
+ {
+ bar->removeItem( itemId( idx ) );
+ removeContainer( idx );
+ }
+
+ return;
+ }
+}
+
+
+void DictLabelAction::setBuddy(QWidget *buddy)
+{
+ if (m_label && buddy)
+ m_label->setBuddy(buddy);
+}
+
+
+//*********************************************************************************
+
+
+DictButtonAction::DictButtonAction( const QString& text, QObject* receiver,
+ const char* slot, QObject* parent, const char* name )
+ : KAction( text, 0, receiver, slot, parent, name )
+{
+}
+
+
+DictButtonAction::~DictButtonAction()
+{
+}
+
+
+int DictButtonAction::plug( QWidget *widget, int index )
+{
+ if ( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar *tb = (KToolBar *)widget;
+
+ int id = KAction::getToolButtonID();
+
+ QPushButton *button = new QPushButton( text(), widget );
+ button->adjustSize();
+ connect(button,SIGNAL(clicked()),this,SLOT(activate()));
+ tb->insertWidget( id, button->width(), button, index );
+
+ addContainer( tb, id );
+
+ connect( tb, SIGNAL( destroyed() ), this, SLOT( slotDestroyed() ) );
+
+ m_button = button;
+
+ return containerCount() - 1;
+ }
+
+ return -1;
+}
+
+
+void DictButtonAction::unplug( QWidget *widget )
+{
+ if ( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar *bar = (KToolBar *)widget;
+
+ int idx = findContainer( bar );
+
+ if ( idx != -1 )
+ {
+ bar->removeItem( itemId( idx ) );
+ removeContainer( idx );
+ }
+ }
+}
+
+
+int DictButtonAction::widthHint()
+{
+ if (m_button)
+ return m_button->sizeHint().width();
+ else
+ return 0;
+}
+
+
+void DictButtonAction::setWidth(int width)
+{
+ if (m_button)
+ m_button->setFixedWidth(width);
+}
+
+#include "actions.moc"
diff --git a/kdict/actions.h b/kdict/actions.h
new file mode 100644
index 00000000..568a9f7c
--- /dev/null
+++ b/kdict/actions.h
@@ -0,0 +1,111 @@
+/* -------------------------------------------------------------
+
+ actions.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ DictComboAction, special KAction subclasses used
+ DictLabelAction, in the toolbar
+ DictButtonAction
+
+ ------------------------------------------------------------- */
+
+#ifndef _ACTIONS_H_
+#define _ACTIONS_H_
+
+#include <qguardedptr.h>
+#include <qptrlist.h>
+#include <kaction.h>
+#include <kglobalsettings.h>
+
+class KComboBox;
+class QLabel;
+class QPushButton;
+
+
+class DictComboAction : public KAction
+{
+ Q_OBJECT
+
+ public:
+ DictComboAction( const QString& text, QObject* parent,
+ const char* name, bool editable, bool autoSized );
+ ~DictComboAction();
+
+ virtual int plug( QWidget *w, int index = -1 );
+ virtual void unplug( QWidget *w );
+
+ QWidget* widget();
+ void setFocus();
+
+ QString currentText() const;
+ void selectAll();
+ void setEditText(const QString &s);
+ void setCurrentItem(int index);
+ void clearEdit();
+
+ void clear();
+ void setList(QStringList items);
+
+ KGlobalSettings::Completion completionMode();
+ void setCompletionMode(KGlobalSettings::Completion mode);
+
+ signals:
+ void activated(int);
+ void activated(const QString&);
+
+ private slots:
+ void slotComboActivated(int);
+ void slotComboActivated(const QString&);
+
+ private:
+ QGuardedPtr<KComboBox> m_combo;
+ bool m_editable, m_autoSized;
+ KGlobalSettings::Completion m_compMode;
+};
+
+
+class DictLabelAction : public KAction
+{
+ Q_OBJECT
+
+ public:
+ DictLabelAction( const QString &text, QObject *parent = 0, const char *name = 0 );
+ ~DictLabelAction();
+
+ virtual int plug( QWidget *widget, int index = -1 );
+ virtual void unplug( QWidget *widget );
+
+ void setBuddy(QWidget *buddy);
+
+ private:
+ QGuardedPtr<QLabel> m_label;
+
+};
+
+
+class DictButtonAction : public KAction
+{
+ Q_OBJECT
+
+ public:
+ DictButtonAction( const QString& text, QObject* receiver,
+ const char* slot, QObject* parent, const char* name );
+ ~DictButtonAction();
+
+ virtual int plug( QWidget *w, int index = -1 );
+ virtual void unplug( QWidget *w );
+
+ int widthHint();
+ void setWidth(int width);
+
+ private:
+ QGuardedPtr<QPushButton> m_button;
+};
+
+#endif
diff --git a/kdict/applet/Makefile.am b/kdict/applet/Makefile.am
new file mode 100644
index 00000000..db1f4bc2
--- /dev/null
+++ b/kdict/applet/Makefile.am
@@ -0,0 +1,19 @@
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = kdict_panelapplet.la
+
+kdict_panelapplet_la_SOURCES = kdictapplet.cpp
+
+METASOURCES = AUTO
+noinst_HEADERS = kdictapplet.h
+
+lnkdir = $(kde_datadir)/kicker/applets
+lnk_DATA = kdictapplet.desktop
+
+EXTRA_DIST = $(lnk_DATA)
+
+kdict_panelapplet_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+kdict_panelapplet_la_LIBADD = $(LIB_KSYCOCA) $(LIB_KDEUI)
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kdictapplet.pot
diff --git a/kdict/applet/kdictapplet.cpp b/kdict/applet/kdictapplet.cpp
new file mode 100644
index 00000000..ad907864
--- /dev/null
+++ b/kdict/applet/kdictapplet.cpp
@@ -0,0 +1,405 @@
+/* -------------------------------------------------------------
+
+ kdictapplet.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2001 Christian Gebauer <gebauer@kde.org>
+
+ The applet is loosely based on the "Run" applet included in KDE.
+ Copyright (c) 2000 Matthias Elter <elter@kde.org> (Artistic License)
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ PopupBox helper class
+ DictApplet a small kicker-applet
+
+ ------------------------------------------------------------- */
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qtimer.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+
+#include <kconfig.h>
+#include <kcombobox.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kprocess.h>
+
+#include "kdictapplet.h"
+
+//********* PopupBox ********************************************
+
+PopupBox::PopupBox()
+ : QHBox(0, 0, WStyle_Customize | WType_Popup ), popupEnabled(true)
+{
+}
+
+
+PopupBox::~PopupBox()
+{}
+
+
+bool PopupBox::showBox()
+{
+ if (!popupEnabled) // prevents that the popup is shown again immediatly
+ return false;
+ else {
+ show();
+ return true;
+ }
+}
+
+
+void PopupBox::hideEvent(QHideEvent *)
+{
+ emit(hidden());
+ popupEnabled = false;
+ QTimer::singleShot(100, this, SLOT(enablePopup()));
+}
+
+
+void PopupBox::enablePopup()
+{
+ popupEnabled = true;
+}
+
+
+//********* DictApplet ********************************************
+
+extern "C"
+{
+ KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile)
+ {
+ KGlobal::locale()->insertCatalogue("kdictapplet");
+ return new DictApplet(configFile, KPanelApplet::Stretch, 0, parent, "kdictapplet");
+ }
+}
+
+
+DictApplet::DictApplet(const QString& configFile, Type type, int actions, QWidget *parent, const char *name)
+ : KPanelApplet(configFile, type, actions, parent, name), waiting(0)
+{
+ // first the widgets for a horizontal panel
+ baseWidget = new QWidget(this);
+ QGridLayout *baseLay = new QGridLayout(baseWidget,2,6,0,1);
+
+ textLabel = new QLabel(i18n("Dictionary:"), baseWidget);
+ textLabel->setBackgroundOrigin(AncestorOrigin);
+ QFont f(textLabel->font());
+ f.setPixelSize(12);
+ textLabel->setFont(f);
+ baseLay->addWidget(textLabel,0,1);
+ QToolTip::add(textLabel,i18n("Look up a word or phrase with Kdict"));
+
+ iconLabel = new QLabel(baseWidget);
+ iconLabel->setBackgroundOrigin(AncestorOrigin);
+ QPixmap pm = KGlobal::iconLoader()->loadIcon("kdict", KIcon::Panel, KIcon::SizeSmall, KIcon::DefaultState, 0L, true);
+ iconLabel->setPixmap(pm);
+ baseLay->addWidget(iconLabel,1,0);
+ iconLabel->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
+ iconLabel->setFixedWidth(pm.width()+4);
+ QToolTip::add(iconLabel,i18n("Look up a word or phrase with Kdict"));
+
+ f.setPixelSize(10);
+ clipboardBtn = new QPushButton(i18n("C"),baseWidget);
+ clipboardBtn->setBackgroundOrigin(AncestorOrigin);
+ clipboardBtn->setFont(f);
+ clipboardBtn->setFixedSize(16,16);
+ connect(clipboardBtn, SIGNAL(clicked()), SLOT(queryClipboard()));
+ baseLay->addWidget(clipboardBtn,0,3);
+ QToolTip::add(clipboardBtn,i18n("Define selected text"));
+
+ defineBtn = new QPushButton(i18n("D"),baseWidget);
+ defineBtn->setBackgroundOrigin(AncestorOrigin);
+ defineBtn->setFont(f);
+ defineBtn->setFixedSize(16,16);
+ defineBtn->setEnabled(false);
+ connect(defineBtn, SIGNAL(clicked()), SLOT(startDefine()));
+ baseLay->addWidget(defineBtn,0,4);
+ QToolTip::add(defineBtn,i18n("Define word/phrase"));
+
+ matchBtn = new QPushButton(i18n("M"),baseWidget);
+ matchBtn->setBackgroundOrigin(AncestorOrigin);
+ matchBtn->setFont(f);
+ matchBtn->setFixedSize(16,16);
+ matchBtn->setEnabled(false);
+ connect(matchBtn, SIGNAL(clicked()), SLOT(startMatch()));
+ baseLay->addWidget(matchBtn,0,5);
+ QToolTip::add(matchBtn,i18n("Find matching definitions"));
+
+ completionObject = new KCompletion();
+
+ internalCombo = new KHistoryCombo(baseWidget);
+ internalCombo->setBackgroundOrigin(AncestorOrigin);
+ internalCombo->setCompletionObject(completionObject);
+ internalCombo->setFocus();
+ internalCombo->clearEdit();
+ internalCombo->lineEdit()->installEventFilter( this );
+ connect(internalCombo, SIGNAL(returnPressed(const QString&)), SLOT(startQuery(const QString&)));
+ connect(internalCombo, SIGNAL(textChanged(const QString&)), SLOT(comboTextChanged(const QString&)));
+ QToolTip::add(internalCombo,i18n("Look up a word or phrase with Kdict"));
+
+ baseLay->addMultiCellWidget(internalCombo,1,1,1,5);
+
+ baseLay->setColStretch(2,1);
+
+ // widgets for a vertical panel
+ verticalBtn = new QPushButton(this);
+ connect(verticalBtn, SIGNAL(pressed()), SLOT(showExternalCombo()));
+ QToolTip::add(verticalBtn,i18n("Look up a word or phrase with Kdict"));
+
+ popupBox = new PopupBox();
+ popupBox->setFixedSize(160, 22);
+ connect(popupBox, SIGNAL(hidden()), SLOT(externalComboHidden()));
+ externalCombo = new KHistoryCombo(popupBox);
+ externalCombo->setCompletionObject(completionObject);
+ connect(externalCombo, SIGNAL(returnPressed(const QString&)), SLOT(startQuery(const QString&)));
+ externalCombo->setFixedSize(160, externalCombo->sizeHint().height());
+
+ connect(internalCombo, SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
+ this, SLOT(updateCompletionMode(KGlobalSettings::Completion)));
+ connect(externalCombo, SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
+ this, SLOT(updateCompletionMode(KGlobalSettings::Completion)));
+
+ // restore history and completion list
+ KConfig *c = config();
+ c->setGroup("General");
+
+ QStringList list = c->readListEntry("Completion list");
+ completionObject->setItems(list);
+ int mode = c->readNumEntry("Completion mode",
+ KGlobalSettings::completionMode());
+ internalCombo->setCompletionMode((KGlobalSettings::Completion)mode);
+ externalCombo->setCompletionMode((KGlobalSettings::Completion)mode);
+
+ list = c->readListEntry("History list");
+ internalCombo->setHistoryItems(list);
+ externalCombo->setHistoryItems(list);
+}
+
+
+DictApplet::~DictApplet()
+{
+ // save history and completion list
+ KConfig *c = config();
+ c->setGroup("General");
+
+ QStringList list = completionObject->items();
+ c->writeEntry("Completion list", list);
+ c->writeEntry("Completion mode", (int) internalCombo->completionMode());
+
+ list = internalCombo->historyItems();
+ c->writeEntry("History list", list);
+ c->sync();
+
+ delete completionObject;
+}
+
+
+int DictApplet::widthForHeight(int height) const
+{
+ if (height >= 38)
+ return textLabel->sizeHint().width()+55;
+ else
+ return textLabel->sizeHint().width()+25;
+}
+
+
+int DictApplet::heightForWidth(int width) const
+{
+ return width;
+}
+
+
+void DictApplet::resizeEvent(QResizeEvent*)
+{
+ if (orientation() == Horizontal) {
+ verticalBtn->hide();
+ baseWidget->show();
+ baseWidget->setFixedSize(width(),height());
+
+ if (height() < internalCombo->sizeHint().height())
+ internalCombo->setFixedHeight(height());
+ else
+ internalCombo->setFixedHeight(internalCombo->sizeHint().height());
+
+ if (height() >= 38) {
+ textLabel->show();
+ clipboardBtn->show();
+ defineBtn->show();
+ matchBtn->show();
+ iconLabel->hide();
+ internalCombo->setFixedWidth(width());
+ } else {
+ textLabel->hide();
+ clipboardBtn->hide();
+ defineBtn->hide();
+ matchBtn->hide();
+ iconLabel->show();
+ internalCombo->setFixedWidth(width()-iconLabel->width()-1);
+ }
+
+ baseWidget->updateGeometry();
+ } else { // orientation() == Vertical
+ verticalBtn->show();
+ baseWidget->hide();
+ verticalBtn->setFixedSize(width(),width());
+
+ KIcon::StdSizes sz = width() < 32 ? KIcon::SizeSmall : (width() < 48 ? KIcon::SizeMedium : KIcon::SizeLarge);
+ QPixmap pm = KGlobal::iconLoader()->loadIcon("kdict", KIcon::Panel, sz, KIcon::DefaultState, 0L, true);
+ verticalBtn->setPixmap(pm);
+ }
+}
+
+
+bool DictApplet::eventFilter( QObject *o, QEvent * e)
+{
+ if (e->type() == QEvent::MouseButtonRelease)
+ emit requestFocus();
+
+ return KPanelApplet::eventFilter(o, e);
+}
+
+
+void DictApplet::sendCommand(const QCString &fun, const QString &data)
+{
+ if (waiting > 0) {
+ waiting = 1;
+ delayedFunc = fun.copy();
+ delayedData = data;
+ return;
+ }
+
+ DCOPClient *client = kapp->dcopClient();
+ if (!client->isApplicationRegistered("kdict")) {
+ KApplication::startServiceByDesktopName("kdict");
+ waiting = 1;
+ delayedFunc = fun.copy();
+ delayedData = data;
+ QTimer::singleShot(100, this, SLOT(sendDelayedCommand()));
+ return;
+ } else {
+ QCStringList list = client->remoteObjects("kdict");
+ if (list.findIndex("KDictIface")==-1) {
+ waiting = 1;
+ delayedFunc = fun.copy();
+ delayedData = data;
+ QTimer::singleShot(100, this, SLOT(sendDelayedCommand()));
+ return;
+ }
+ }
+
+ client->send("kdict","default",fun,data);
+}
+
+
+void DictApplet::sendDelayedCommand()
+{
+ if (waiting > 100) { // timeout after ten seconds
+ waiting = 0;
+ return;
+ }
+
+ DCOPClient *client = kapp->dcopClient();
+ if (!client->isApplicationRegistered("kdict")) {
+ waiting++;
+ QTimer::singleShot(100, this, SLOT(sendDelayedCommand()));
+ return;
+ } else {
+ QCStringList list = client->remoteObjects("kdict");
+ if (list.findIndex("KDictIface")==-1) {
+ waiting++;
+ QTimer::singleShot(100, this, SLOT(sendDelayedCommand()));
+ return;
+ }
+ }
+
+ client->send("kdict","default",delayedFunc,delayedData);
+ waiting = 0;
+}
+
+
+void DictApplet::startQuery(const QString &s)
+{
+ QString query = s.stripWhiteSpace();
+ if (query.isEmpty())
+ return;
+
+ internalCombo->addToHistory(query);
+ externalCombo->addToHistory(query);
+ internalCombo->clearEdit();
+ externalCombo->clearEdit();
+
+ sendCommand("definePhrase(QString)",query);
+
+ if (orientation() == Vertical)
+ popupBox->hide();
+}
+
+
+void DictApplet::comboTextChanged(const QString &s)
+{
+ defineBtn->setEnabled(!s.isEmpty());
+ matchBtn->setEnabled(!s.isEmpty());
+}
+
+
+void DictApplet::queryClipboard()
+{
+ sendCommand("defineClipboardContent()",QString::null);
+}
+
+
+void DictApplet::startDefine()
+{
+ startQuery(internalCombo->currentText());
+}
+
+
+void DictApplet::startMatch()
+{
+ QString query = internalCombo->currentText().stripWhiteSpace();
+ internalCombo->addToHistory(query);
+ externalCombo->addToHistory(query);
+ internalCombo->clearEdit();
+ externalCombo->clearEdit();
+
+ sendCommand("matchPhrase(QString)",query);
+}
+
+
+void DictApplet::showExternalCombo()
+{
+ QPoint p;
+ if (position() == pLeft)
+ p = mapToGlobal(QPoint(-popupBox->width()-1, 0));
+ else
+ p = mapToGlobal(QPoint(width()+1, 0));
+ popupBox->move(p);
+ if (popupBox->showBox())
+ externalCombo->setFocus();
+ else
+ verticalBtn->setDown(false);
+}
+
+
+void DictApplet::externalComboHidden()
+{
+ verticalBtn->setDown(false);
+}
+
+void DictApplet::updateCompletionMode(KGlobalSettings::Completion mode)
+{
+ internalCombo->setCompletionMode(mode);
+ externalCombo->setCompletionMode(mode);
+}
+
+//--------------------------------
+
+#include "kdictapplet.moc"
diff --git a/kdict/applet/kdictapplet.desktop b/kdict/applet/kdictapplet.desktop
new file mode 100644
index 00000000..23d26f3f
--- /dev/null
+++ b/kdict/applet/kdictapplet.desktop
@@ -0,0 +1,147 @@
+[Desktop Entry]
+Comment=Lookup phrases in a dictionary
+Comment[af]=Opkyk frases in 'n woordeboek
+Comment[ar]=ابحث عن الكلمات ÙÙŠ القاموس
+Comment[az]=Lüğətdən kəlimələrə baxın
+Comment[be]=Пошук выразаў у Ñлоўніку
+Comment[bg]=ТърÑене на фрази в речника
+Comment[bn]=à¦à¦•à¦Ÿà¦¿ অভিধানে শবà§à¦¦à¦¸à¦®à¦·à§à¦Ÿà¦¿à¦° খোà¦à¦œ করো
+Comment[bs]=Potražite fraze u rjeÄniku
+Comment[ca]=Cerca expressions en un diccionari
+Comment[cs]=VyhledávaÄ pojmů ve slovníku
+Comment[cy]=Edrych am ddywediadau mewn geiriadur
+Comment[da]=Slå sætninger op i en ordbog
+Comment[de]=Ausdrücke in einem Lexikon nachschlagen
+Comment[el]=Αναζήτηση φÏάσεων σε λεξικό
+Comment[eo]=Serĉi kapvortojn en vortaroj
+Comment[es]=Busca expresiones en un diccionario
+Comment[et]=Fraaside otsimine sõnaraamatust
+Comment[eu]=Bilatu esaldiak hiztegi batean
+Comment[fa]=مراجعه به واژه‌نامه برای عبارتها
+Comment[fi]=Hae lauseita sanakirjasta
+Comment[fr]=Recherche de phrases dans un dictionnaire
+Comment[ga]=Cuardaigh frásaí i bhfoclóir
+Comment[gl]=Buscar expresións no diccionario
+Comment[he]=חיפוש ×‘×™×˜×•×™×™× ×‘×ž×™×œ×•×Ÿ
+Comment[hi]=शबà¥à¤¦à¤•à¥‹à¤¶ में वाकà¥à¤¯à¤¾à¤‚शों को देखे
+Comment[hr]=Potraži fraze u rjeÄniku
+Comment[hu]=Szótárkezelő alkalmazás
+Comment[is]=Fletta upp í orðabók
+Comment[it]=Cerca frasi in un dizionario
+Comment[ja]=辞書ã§èªžå¥ã‚’検索
+Comment[ka]=ფრáƒáƒ–ების ლექსიკáƒáƒœáƒ¨áƒ˜ ძებნáƒ
+Comment[kk]=Сөздікте іздеу
+Comment[km]=រក​មើល​ប្រយោគ​នៅ​ក្នុង​វចនានុក្រម​មួយ
+Comment[ko]=사전ì—ì„œ 글귀를 찾아ì¤ë‹ˆë‹¤
+Comment[lt]=Ieškoti frazių žodyne
+Comment[lv]=SkatÄ«t frÄzes vÄrdnÄ«cÄ
+Comment[mk]=Барајте за изрази во речник
+Comment[mn]=Толь бичигÑÑÑ Ò¯Ð³ харах
+Comment[ms]=Mencari frasa di dalam kamus
+Comment[mt]=Fittex frażijiet fid-dizzjunarju
+Comment[nb]=Finn fraser i en ordbok
+Comment[nds]=Begrepen in en Wöörbook nakieken
+Comment[ne]=शबà¥à¤¦à¤•à¥‹à¤¶à¤®à¤¾ वाकà¥à¤¯à¤¾à¤‚श खोजी गरà¥à¤¨à¥à¤¹à¥‹à¤¸à¥
+Comment[nl]=Zoek bepaalde uitdrukkingen op in een woordenboek
+Comment[nn]=Slå opp ord i ei ordboka
+Comment[nso]=Nyaka mantsu ka gare ga pukuntsu
+Comment[pl]=Szukanie zwrotów w słowniku
+Comment[pt]=Procura por frases num dicionário
+Comment[pt_BR]=Busca frases em um dicionário
+Comment[ro]=Caută fraze într-un dicţionar
+Comment[ru]=ПоиÑк Ñлов в Ñловаре
+Comment[se]=Oza sániid sátnegirjjis
+Comment[sk]=Hľadanie fráz v slovníku
+Comment[sl]=Iskanje Izrazov v slovarju
+Comment[sr]=Потражите фразе у речнику
+Comment[sr@Latn]=Potražite fraze u reÄniku
+Comment[sv]=Leta upp fraser i en ordlista
+Comment[ta]=ஒர௠அகராதியிலà¯à®³à¯à®³ தேடறà¯à®šà¯Šà®±à¯à®¤à¯Šà®Ÿà®°à¯à®•à®³à¯
+Comment[tg]=ҶуÑтуҷӯи ибораҳо дар луғат
+Comment[th]=ค้นหาวลีในพจนานุà¸à¸£à¸¡
+Comment[tr]=Sözlükten kelimelere bakın
+Comment[uk]=Пошук фраз у Ñловнику
+Comment[ven]=Todani fhungo kha bugu talutshedza maipfi
+Comment[wa]=Cweri des fråzes dins on diccionaire
+Comment[xh]=Jonga amabinzana kwincwadi enekcazelo zamagama
+Comment[zh_CN]=在字典中查找短语
+Comment[zh_HK]=在字典中尋找片語
+Comment[zh_TW]=在字典中尋找片語
+Comment[zu]=Bheka amagama kwisichazamagama
+Icon=
+Name=Dictionary
+Name[af]=Woordeboek
+Name[ar]=القاموس
+Name[az]=Lüğət
+Name[be]=Слоўнік
+Name[bg]=Речник
+Name[bn]=অভিধান
+Name[br]=Geriadur
+Name[bs]=RjeÄnik
+Name[ca]=Diccionari
+Name[cs]=Slovník
+Name[cy]=Geiriadur
+Name[da]=Ordbog
+Name[de]=Lexikon
+Name[el]=Λεξικό
+Name[eo]=Vortaro
+Name[es]=Diccionario
+Name[et]=Sõnaraamat
+Name[eu]=Hiztegia
+Name[fa]=واژه‌نامه
+Name[fi]=Sanakirja
+Name[fr]=Dictionnaire
+Name[ga]=Foclóir
+Name[gl]=Diccionario
+Name[he]=מילון
+Name[hi]=शबà¥à¤¦à¤•à¥‹à¤¶
+Name[hr]=RjeÄnik
+Name[hu]=Szótár
+Name[is]=Orðabók
+Name[it]=Dizionario
+Name[ja]=辞書
+Name[ka]=ლექსიკáƒáƒœáƒ˜
+Name[kk]=Сөздік
+Name[km]=វចនានុក្រម
+Name[ko]=사전
+Name[lt]=Žodynas
+Name[lv]=VÄrdnÄ«ca
+Name[mk]=Речник
+Name[mn]=Толь бичиг
+Name[ms]=Kamus
+Name[mt]=Dizzjunarju
+Name[nb]=Ordbok
+Name[nds]=Wöörbook
+Name[ne]=शबà¥à¤¦à¤•à¥‹à¤¶
+Name[nl]=Woordenboek
+Name[nn]=Ordbok
+Name[nso]=Pukuntsu
+Name[pa]=ਸ਼ਬਦ-ਕੋਸ਼
+Name[pl]=SÅ‚ownik
+Name[pt]=Dicionário
+Name[pt_BR]=Dicionário
+Name[ro]=Dicţionar
+Name[ru]=Словарь
+Name[se]=Sátnegirji
+Name[sk]=Slovník
+Name[sl]=Slovar
+Name[sr]=Речник
+Name[sr@Latn]=ReÄnik
+Name[sv]=Ordlista
+Name[ta]=அகராதி
+Name[tg]=Луғат
+Name[th]=พจนานุà¸à¸£à¸¡
+Name[tr]=Sözlük
+Name[uk]=Словник
+Name[uz]=Lugʻat
+Name[uz@cyrillic]=Луғат
+Name[ven]=Bugu yau talutshedza maipfi
+Name[wa]=Motî
+Name[xh]=Incwadi eneenkcazelo zamagama
+Name[zh_CN]=å­—å…¸
+Name[zh_HK]=å­—å…¸
+Name[zh_TW]=å­—å…¸
+Name[zu]=Isichazamagama
+Icon=kdict
+X-KDE-Library=kdict_panelapplet
+X-KDE-UniqueApplet=true
diff --git a/kdict/applet/kdictapplet.h b/kdict/applet/kdictapplet.h
new file mode 100644
index 00000000..a9738148
--- /dev/null
+++ b/kdict/applet/kdictapplet.h
@@ -0,0 +1,101 @@
+/* -------------------------------------------------------------
+
+ kdictapplet.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2001 Christian Gebauer <gebauer@kde.org>
+
+ The applet is loosely based on the "Run" applet included in KDE.
+ Copyright (c) 2000 Matthias Elter <elter@kde.org> (Artistic License)
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ PopupBox helper class
+ DictApplet a small kicker-applet
+
+ ------------------------------------------------------------- */
+
+#ifndef _DICTAPPLET_H_
+#define _DICTAPPLET_H_
+
+#include <qhbox.h>
+#include <kpanelapplet.h>
+
+class QLabel;
+class QPushButton;
+class KHistoryCombo;
+
+
+//********* PopupBox ********************************************
+
+class PopupBox : public QHBox
+{
+ Q_OBJECT
+
+public:
+ PopupBox();
+ ~PopupBox();
+
+ bool showBox();
+
+signals:
+ void hidden();
+
+public slots:
+ void enablePopup();
+
+protected:
+ void hideEvent(QHideEvent *);
+
+private:
+ bool popupEnabled;
+
+};
+
+//********* DictApplet ********************************************
+
+class DictApplet : public KPanelApplet
+{
+ Q_OBJECT
+
+public:
+ DictApplet(const QString& configFile, Type t = Stretch, int actions = 0, QWidget *parent = 0, const char *name = 0);
+ virtual ~DictApplet();
+
+ int widthForHeight(int height) const;
+ int heightForWidth(int width) const;
+
+protected:
+ void resizeEvent(QResizeEvent*);
+ bool eventFilter( QObject *, QEvent * );
+
+ void sendCommand(const QCString &fun, const QString &data);
+
+protected slots:
+ void sendDelayedCommand();
+ void startQuery(const QString&);
+ void comboTextChanged(const QString&);
+ void queryClipboard();
+ void startDefine();
+ void startMatch();
+ void showExternalCombo();
+ void externalComboHidden();
+ void updateCompletionMode(KGlobalSettings::Completion mode);
+
+private:
+ KHistoryCombo *internalCombo, *externalCombo;
+ KCompletion *completionObject;
+ QLabel *textLabel, *iconLabel;
+ QPushButton *verticalBtn, *clipboardBtn, *defineBtn, *matchBtn;
+ QWidget *baseWidget;
+ PopupBox *popupBox;
+
+ int waiting;
+ QCString delayedFunc;
+ QString delayedData;
+
+};
+
+#endif
diff --git a/kdict/application.cpp b/kdict/application.cpp
new file mode 100644
index 00000000..28e3a398
--- /dev/null
+++ b/kdict/application.cpp
@@ -0,0 +1,71 @@
+/* -------------------------------------------------------------
+
+ application.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ ------------------------------------------------------------- */
+
+#include <kwin.h>
+#include <kdebug.h>
+#include <kcmdlineargs.h>
+
+#include "application.h"
+#include "toplevel.h"
+
+
+Application::Application()
+ : KUniqueApplication()
+{
+ m_mainWindow = new TopLevel( 0, "mainWindow" );
+}
+
+
+Application::~Application()
+{
+ delete m_mainWindow;
+}
+
+
+int Application::newInstance()
+{
+ kdDebug(5004) << "Application::newInstance()" << endl;
+ KUniqueApplication::newInstance();
+
+ // process parameters...
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ m_mainWindow->show();
+
+ if (args->isSet("clipboard"))
+ {
+ m_mainWindow->defineClipboard();
+ }
+ else
+ {
+ if (args->count()>0)
+ {
+ QString phrase;
+ for (int i=0;i<args->count();i++)
+ {
+ phrase += QString::fromLocal8Bit(args->arg(i));
+ if (i+1 < args->count())
+ phrase += " ";
+ }
+ m_mainWindow->define(phrase);
+ }
+ else
+ {
+ m_mainWindow->normalStartup();
+ }
+ }
+
+ return 0;
+}
+
+//--------------------------------
+
+#include "application.moc"
diff --git a/kdict/application.h b/kdict/application.h
new file mode 100644
index 00000000..eddb7f44
--- /dev/null
+++ b/kdict/application.h
@@ -0,0 +1,39 @@
+/* -------------------------------------------------------------
+
+ application.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ ------------------------------------------------------------- */
+
+#ifndef APPLICATION_H
+#define APPLICATION_H
+
+#include <kuniqueapplication.h>
+#include <qguardedptr.h>
+
+#define KDICT_VERSION "0.6"
+
+class TopLevel;
+
+class Application : public KUniqueApplication
+{
+ Q_OBJECT
+
+ public:
+ Application();
+ ~Application();
+
+ /** Create new instance of Kdict. Make the existing
+ main window active if Kdict is already running */
+ int newInstance();
+
+ private:
+ QGuardedPtr<TopLevel> m_mainWindow;
+
+};
+
+#endif
diff --git a/kdict/dcopinterface.h b/kdict/dcopinterface.h
new file mode 100644
index 00000000..f088a842
--- /dev/null
+++ b/kdict/dcopinterface.h
@@ -0,0 +1,54 @@
+/* -------------------------------------------------------------
+
+ dcopinterface.h (part of The KDE Dictionary Client)
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ KDictDCOPInterface abstract base class that defines the
+ DCOP interface of Kdict
+
+ ------------------------------------------------------------- */
+
+#ifndef _DCOPINTERFACE_H
+#define _DCOPINTERFACE_H
+
+#include <dcopobject.h>
+#include <qstringlist.h>
+
+class KDictIface : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+
+ /** Quit Kdict **/
+ virtual void quit() = 0;
+ virtual void makeActiveWindow() = 0;
+
+ /** define/match a word/phrase **/
+ virtual void definePhrase(QString phrase) = 0;
+ virtual void matchPhrase(QString phrase) = 0;
+ virtual void defineClipboardContent() = 0;
+ virtual void matchClipboardContent() = 0;
+
+ /** get info **/
+ virtual QStringList getDatabases() = 0;
+ virtual QString currentDatabase() = 0;
+ virtual QStringList getStrategies() = 0;
+ virtual QString currentStrategy() = 0;
+
+ /** set current database/strategy (returns true on success) **/
+ virtual bool setDatabase(QString db) = 0;
+ virtual bool setStrategy(QString strategy) = 0;
+
+ /** navigate in history **/
+ virtual bool historyGoBack() = 0;
+ virtual bool historyGoForward() = 0;
+
+};
+
+#endif
diff --git a/kdict/dict.cpp b/kdict/dict.cpp
new file mode 100644
index 00000000..b36f1ac1
--- /dev/null
+++ b/kdict/dict.cpp
@@ -0,0 +1,1632 @@
+/* -------------------------------------------------------------
+
+ dict.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+ (C) by Matthias Hölzer 1998
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ JobData used for data transfer between Client and Interface
+ DictAsyncClient all network related stuff happens here in asynchrous thread
+ DictInterface interface for DictAsyncClient, job management
+
+ ------------------------------------------------------------- */
+
+#include <config.h>
+
+#include "application.h"
+#include "options.h"
+#include "dict.h"
+
+#include <qregexp.h>
+#include <qtextcodec.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kmdcodec.h>
+#include <kextsock.h>
+#include <ksocks.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+
+//********* JobData ******************************************
+
+
+JobData::JobData(QueryType Ntype,bool NnewServer,QString const& Nserver,int Nport,
+ int NidleHold, int Ntimeout, int NpipeSize, QString const& Nencoding, bool NAuthEnabled,
+ QString const& Nuser, QString const& Nsecret, unsigned int NheadLayout)
+ : type(Ntype), error(ErrNoErr), canceled(false), numFetched(0), newServer(NnewServer),server(Nserver), port(Nport),
+ timeout(Ntimeout), pipeSize(NpipeSize), idleHold(NidleHold), encoding(Nencoding), authEnabled(NAuthEnabled),
+ user(Nuser), secret(Nsecret), headLayout(NheadLayout)
+{}
+
+
+//********* DictAsyncClient *************************************
+
+DictAsyncClient::DictAsyncClient(int NfdPipeIn, int NfdPipeOut)
+: job(0L), inputSize(10000), fdPipeIn(NfdPipeIn),
+ fdPipeOut(NfdPipeOut), tcpSocket(-1), idleHold(0)
+{
+ input = new char[inputSize];
+}
+
+
+DictAsyncClient::~DictAsyncClient()
+{
+ if (-1!=tcpSocket)
+ doQuit();
+ delete [] input;
+}
+
+
+void* DictAsyncClient::startThread(void* pseudoThis)
+{
+ DictAsyncClient* newthis = (DictAsyncClient*) (pseudoThis);
+
+ if (0!=pthread_setcanceltype(PTHREAD_CANCEL_ENABLE,NULL))
+ qWarning("pthread_setcanceltype failed!");
+ if (0!= pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL))
+ qWarning("pthread_setcanceltype failed!");
+
+ signal(SIGPIPE,SIG_IGN); // ignore sigpipe
+
+ newthis->waitForWork();
+ return NULL;
+}
+
+
+void DictAsyncClient::insertJob(JobData *newJob)
+{
+ if (!job) // don't overwrite existing job pointer
+ job = newJob;
+}
+
+
+void DictAsyncClient::removeJob()
+{
+ job = 0L;
+}
+
+
+void DictAsyncClient::waitForWork()
+{
+ fd_set fdsR,fdsE;
+ timeval tv;
+ int selectRet;
+ char buf;
+
+ while (true) {
+ if (tcpSocket != -1) { // we are connected, hold the connection for xx secs
+ FD_ZERO(&fdsR);
+ FD_SET(fdPipeIn, &fdsR);
+ FD_SET(tcpSocket, &fdsR);
+ FD_ZERO(&fdsE);
+ FD_SET(tcpSocket, &fdsE);
+ tv.tv_sec = idleHold;
+ tv.tv_usec = 0;
+ selectRet = KSocks::self()->select(FD_SETSIZE, &fdsR, NULL, &fdsE, &tv);
+ if (selectRet == 0) {
+ doQuit(); // nothing happend...
+ } else {
+ if (((selectRet > 0)&&(!FD_ISSET(fdPipeIn,&fdsR)))||(selectRet == -1))
+ closeSocket();
+ }
+ }
+
+ do {
+ FD_ZERO(&fdsR);
+ FD_SET(fdPipeIn, &fdsR);
+ } while (select(FD_SETSIZE, &fdsR, NULL, NULL, NULL)<0); // don't get tricked by signals
+
+ clearPipe();
+
+ if (job) {
+ if ((tcpSocket!=-1)&&(job->newServer))
+ doQuit();
+
+ codec = QTextCodec::codecForName(job->encoding.latin1());
+ input[0] = 0; //terminate string
+ thisLine = input;
+ nextLine = input;
+ inputEnd = input;
+ timeout = job->timeout;
+ idleHold = job->idleHold;
+
+ if (tcpSocket==-1)
+ openConnection();
+
+ if (tcpSocket!=-1) { // connection is ready
+ switch (job->type) {
+ case JobData::TDefine :
+ define();
+ break;
+ case JobData::TGetDefinitions :
+ getDefinitions();
+ break;
+ case JobData::TMatch :
+ match();
+ break;
+ case JobData::TShowDatabases :
+ showDatabases();
+ break;
+ case JobData::TShowDbInfo :
+ showDbInfo();
+ break;
+ case JobData::TShowStrategies :
+ showStrategies();
+ break;
+ case JobData::TShowInfo :
+ showInfo();
+ break;
+ case JobData::TUpdate :
+ update();
+ }
+ }
+ clearPipe();
+ }
+ if (write(fdPipeOut,&buf,1) == -1) // emit stopped signal
+ ::perror( "waitForJobs()" );
+ }
+}
+
+
+void DictAsyncClient::define()
+{
+ QString command;
+
+ job->defines.clear();
+ QStringList::iterator it;
+ for (it = job->databases.begin(); it != job->databases.end(); ++it) {
+ command = "define ";
+ command += *it;
+ command += " \"";
+ command += job->query;
+ command += "\"\r\n";
+ job->defines.append(command);
+ }
+
+ if (!getDefinitions())
+ return;
+
+ if (job->numFetched == 0) {
+ job->strategy = ".";
+ if (!match())
+ return;
+ job->result = QString::null;
+ if (job->numFetched == 0) {
+ resultAppend("<body>\n<p class=\"heading\">\n");
+ resultAppend(i18n("No definitions found for \'%1'.").arg(job->query));
+ resultAppend("</p>\n</html></body>");
+ } else {
+ // html header...
+ resultAppend("<body>\n<p class=\"heading\">\n");
+ resultAppend(i18n("No definitions found for \'%1\'. Perhaps you mean:").arg(job->query));
+ resultAppend("</p>\n<table width=\"100%\" cols=2>\n");
+
+ QString lastDb;
+ QStringList::iterator it;
+ for (it = job->matches.begin(); it != job->matches.end(); ++it) {
+ int pos = (*it).find(' ');
+ if (pos != -1) {
+ if (lastDb != (*it).left(pos)) {
+ if (lastDb.length() > 0)
+ resultAppend("</pre></td></tr>\n");
+ lastDb = (*it).left(pos);
+ resultAppend("<tr valign=top><td width=25%><pre><b>");
+ resultAppend(lastDb);
+ resultAppend(":</b></pre></td><td width=75%><pre>");
+ }
+ if ((*it).length() > (unsigned int)pos+2) {
+ resultAppend("<a href=\"http://define/");
+ resultAppend((*it).mid(pos+2, (*it).length()-pos-3));
+ resultAppend("\">");
+ resultAppend((*it).mid(pos+2, (*it).length()-pos-3));
+ resultAppend("</a> ");
+ }
+ }
+ }
+ resultAppend("\n</pre></td></tr></table>\n</body></html>");
+ job->numFetched = 0;
+ }
+ }
+}
+
+
+QString htmlString(const QString &raw)
+{
+ unsigned int len=raw.length();
+ QString ret;
+
+ for (unsigned int i=0; i<len; i++) {
+ switch (raw[i]) {
+ case '&' : ret += "&amp"; break;
+ case '<' : ret+="&lt;"; break;
+ case '>' : ret+="&gt;"; break;
+ default : ret+=raw[i];
+ }
+ }
+
+ return ret;
+}
+
+
+QString generateDefineLink(const QString &raw)
+{
+ QRegExp http("http://[^\\s<>()\"|\\[\\]{}]+");
+ QRegExp ftp("ftp://[^\\s<>()\"|\\[\\]{}]+");
+ int matchPos=0, matchLen=0;
+ bool httpMatch=false;
+ QString ret;
+
+ matchPos = http.search(raw);
+ matchLen = http.matchedLength();
+ if (-1 != matchPos) {
+ httpMatch = true;
+ } else {
+ matchPos = ftp.search(raw);
+ matchLen = ftp.matchedLength();
+ httpMatch = false;
+ }
+
+ if (-1 != matchPos) {
+ ret = htmlString(raw.left(matchPos));
+ ret += "<a href=\"http://";
+ if (httpMatch) {
+ ret += "realhttp/";
+ ret += raw.mid(matchPos+7, matchLen-7);
+ } else {
+ ret += "realftp/";
+ ret += raw.mid(matchPos+6, matchLen-6);
+ }
+ ret += "\">";
+ ret += htmlString(raw.mid(matchPos, matchLen));
+ ret += "</a>";
+ ret += htmlString(raw.right(raw.length()-matchLen-matchPos));
+ } else {
+ ret = "<a href=\"http://define/";
+ ret += raw;
+ ret += "\">";
+ ret += htmlString(raw);
+ ret += "</a>";
+ }
+
+ return ret;
+}
+
+
+bool DictAsyncClient::getDefinitions()
+{
+ QCString lastDb,bracketBuff;
+ QStrList hashList;
+ char *s;
+ int defCount,response;
+
+ // html header...
+ resultAppend("<body>\n");
+
+ while (job->defines.count()>0) {
+ defCount = 0;
+ cmdBuffer = "";
+ do {
+ QStringList::iterator it = job->defines.begin();
+ cmdBuffer += codec->fromUnicode(*it);
+ defCount++;
+ job->defines.remove(it);
+ } while ((job->defines.count()>0)&&((int)cmdBuffer.length()<job->pipeSize));
+
+ if (!sendBuffer())
+ return false;
+
+ for (;defCount > 0;defCount--) {
+ if (!getNextResponse(response))
+ return false;
+ switch (response) {
+ case 552: // define: 552 No match
+ break;
+ case 150: { // define: 150 n definitions retrieved - definitions follow
+ bool defineDone = false;
+ while (!defineDone) {
+ if (!getNextResponse(response))
+ return false;
+ switch (response) {
+ case 151: { // define: 151 word database name - text follows
+ char *db = strchr(thisLine, '\"');
+ if (db)
+ db = strchr(db+1, '\"');
+ char *dbdes = 0;
+ if (db) {
+ db+=2; // db points now on database name
+ dbdes = strchr(db,' ');
+ if (dbdes) {
+ dbdes[0] = 0; // terminate database name
+ dbdes+=2; // dbdes points now on database description
+ }
+ } else {
+ job->error = JobData::ErrServerError;
+ job->result = QString::null;
+ resultAppend(thisLine);
+ doQuit();
+ return false;
+ }
+
+ int oldResPos = job->result.length();
+
+ if (((job->headLayout<2)&&(lastDb!=db))||(job->headLayout==2)) {
+ lastDb = db;
+ resultAppend("<p class=\"heading\">\n");
+ if (dbdes)
+ resultAppend(codec->toUnicode(dbdes,strlen(dbdes)-1));
+ resultAppend(" [<a href=\"http://dbinfo/");
+ resultAppend(db);
+ resultAppend("\">");
+ resultAppend(db);
+ resultAppend("</a>]</p>\n");
+ } else
+ if (job->headLayout==1)
+ resultAppend("<hr>\n");
+
+ resultAppend("<pre><p class=\"definition\">\n");
+
+ KMD5 context;
+ bool bodyDone = false;
+ while (!bodyDone) {
+ if (!getNextLine())
+ return false;
+ char *line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double periode into one
+ else
+ if (line[1]==0)
+ bodyDone = true;
+ }
+ if (!bodyDone) {
+ context.update(QCString(line));
+ if (!bracketBuff.isEmpty()) {
+ s = strchr(line,'}');
+ if (!s)
+ resultAppend(bracketBuff.data());
+ else {
+ s[0] = 0;
+ bracketBuff.remove(0,1); // remove '{'
+ bracketBuff += line;
+ line = s+1;
+ resultAppend(generateDefineLink(codec->toUnicode(bracketBuff)));
+ }
+ bracketBuff = "";
+ }
+ s = strchr(line,'{');
+ while (s) {
+ resultAppend(htmlString(codec->toUnicode(line,s-line)));
+ line = s;
+ s = strchr(line,'}');
+ if (s) {
+ s[0] = 0;
+ line++;
+ resultAppend(generateDefineLink(codec->toUnicode(line)));
+ line = s+1;
+ s = strchr(line,'{');
+ } else {
+ bracketBuff = line;
+ bracketBuff += "\n";
+ line = 0;
+ s = 0;
+ }
+ }
+ if (line) {
+ resultAppend(htmlString(codec->toUnicode(line)));
+ resultAppend("\n");
+ }
+ }
+ }
+ resultAppend("</p></pre>\n");
+
+ if (hashList.find(context.hexDigest())>=0) // duplicate??
+ job->result.truncate(oldResPos); // delete the whole definition
+ else {
+ hashList.append(context.hexDigest());
+ job->numFetched++;
+ }
+
+ break; }
+ case 250: { // define: 250 ok (optional timing information here)
+ defineDone = true;
+ break; }
+ default: {
+ handleErrors();
+ return false; }
+ }
+ }
+ break; }
+ default:
+ handleErrors();
+ return false;
+ }
+ }
+ }
+
+ resultAppend("</body></html>\n");
+ return true;
+}
+
+
+bool DictAsyncClient::match()
+{
+ QStringList::iterator it = job->databases.begin();
+ int response;
+ cmdBuffer = "";
+
+ while (it != job->databases.end()) {
+ int send = 0;
+ do {
+ cmdBuffer += "match ";
+ cmdBuffer += codec->fromUnicode(*(it));
+ cmdBuffer += " ";
+ cmdBuffer += codec->fromUnicode(job->strategy);
+ cmdBuffer += " \"";
+ cmdBuffer += codec->fromUnicode(job->query);
+ cmdBuffer += "\"\r\n";
+ send++;
+ ++it;
+ } while ((it != job->databases.end())&&((int)cmdBuffer.length()<job->pipeSize));
+
+ if (!sendBuffer())
+ return false;
+
+ for (;send > 0;send--) {
+ if (!getNextResponse(response))
+ return false;
+ switch (response) {
+ case 552: // match: 552 No match
+ break;
+ case 152: { // match: 152 n matches found - text follows
+ bool matchDone = false;
+ while (!matchDone) {
+ if (!getNextLine())
+ return false;
+ char *line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double period into one
+ else
+ if (line[1]==0)
+ matchDone = true;
+ }
+ if (!matchDone) {
+ job->numFetched++;
+ job->matches.append(codec->toUnicode(line));
+ }
+ }
+ if (!nextResponseOk(250)) // match: "250 ok ..."
+ return false;
+ break; }
+ default:
+ handleErrors();
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+void DictAsyncClient::showDatabases()
+{
+ cmdBuffer = "show db\r\n";
+
+ if (!sendBuffer())
+ return;
+
+ if (!nextResponseOk(110)) // show db: "110 n databases present - text follows "
+ return;
+
+ // html header...
+ resultAppend("<body>\n<p class=\"heading\">\n");
+ resultAppend(i18n("Available Databases:"));
+ resultAppend("\n</p>\n<table width=\"100%\" cols=2>\n");
+
+ bool done(false);
+ char *line;
+ while (!done) {
+ if (!getNextLine())
+ return;
+ line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double periode into one
+ else
+ if (line[1]==0)
+ done = true;
+ }
+ if (!done) {
+ resultAppend("<tr valign=top><td width=25%><pre><a href=\"http://dbinfo/");
+ char *space = strchr(line,' ');
+ if (space) {
+ resultAppend(codec->toUnicode(line,space-line));
+ resultAppend("\">");
+ resultAppend(codec->toUnicode(line,space-line));
+ resultAppend("</a></pre></td><td width=75%><pre>");
+ line = space+1;
+ if (line[0]=='"') {
+ line++; // remove double quote
+ char *quote = strchr(line, '\"');
+ if (quote)
+ quote[0]=0;
+ }
+ } else { // hmmm, malformated line...
+ resultAppend("\"></a></pre></td><td width=75%>");
+ }
+ resultAppend(line);
+ resultAppend("</pre></td></tr>\n");
+ }
+ }
+ resultAppend("</table>\n</body></html>");
+
+ if (!nextResponseOk(250)) // end of transmission: "250 ok ..."
+ return;
+}
+
+
+void DictAsyncClient::showDbInfo()
+{
+ cmdBuffer = "show info ";
+ cmdBuffer += codec->fromUnicode(job->query);
+ cmdBuffer += "\r\n";
+
+ if (!sendBuffer())
+ return;
+
+ if (!nextResponseOk(112)) // show info db: "112 database information follows"
+ return;
+
+ // html header...
+ resultAppend("<body>\n<p class=\"heading\">\n");
+ resultAppend(i18n("Database Information [%1]:").arg(job->query));
+ resultAppend("</p>\n<pre><p class=\"definition\">\n");
+
+ bool done(false);
+ char *line;
+ while (!done) {
+ if (!getNextLine())
+ return;
+ line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double periode into one
+ else
+ if (line[1]==0)
+ done = true;
+ }
+ if (!done) {
+ resultAppend(line);
+ resultAppend("\n");
+ }
+ }
+
+ resultAppend("</p></pre>\n</body></html>");
+
+ if (!nextResponseOk(250)) // end of transmission: "250 ok ..."
+ return;
+}
+
+
+void DictAsyncClient::showStrategies()
+{
+ cmdBuffer = "show strat\r\n";
+
+ if (!sendBuffer())
+ return;
+
+ if (!nextResponseOk(111)) // show strat: "111 n strategies present - text follows "
+ return;
+
+ // html header...
+ resultAppend("<body>\n<p class=\"heading\">\n");
+ resultAppend(i18n("Available Strategies:"));
+ resultAppend("\n</p>\n<table width=\"100%\" cols=2>\n");
+
+ bool done(false);
+ char *line;
+ while (!done) {
+ if (!getNextLine())
+ return;
+ line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double periode into one
+ else
+ if (line[1]==0)
+ done = true;
+ }
+ if (!done) {
+ resultAppend("<tr valign=top><td width=25%><pre>");
+ char *space = strchr(line,' ');
+ if (space) {
+ resultAppend(codec->toUnicode(line,space-line));
+ resultAppend("</pre></td><td width=75%><pre>");
+ line = space+1;
+ if (line[0]=='"') {
+ line++; // remove double quote
+ char *quote = strchr(line, '\"');
+ if (quote)
+ quote[0]=0;
+ }
+ } else { // hmmm, malformated line...
+ resultAppend("</pre></td><td width=75%><pre>");
+ }
+ resultAppend(line);
+ resultAppend("</pre></td></tr>\n");
+ }
+ }
+ resultAppend("</table>\n</body></html>");
+
+ if (!nextResponseOk(250)) // end of transmission: "250 ok ..."
+ return;
+}
+
+
+void DictAsyncClient::showInfo()
+{
+ cmdBuffer = "show server\r\n";
+
+ if (!sendBuffer())
+ return;
+
+ if (!nextResponseOk(114)) // show server: "114 server information follows"
+ return;
+
+ // html header...
+ resultAppend("<body>\n<p class=\"heading\">\n");
+ resultAppend(i18n("Server Information:"));
+ resultAppend("\n</p>\n<pre><p class=\"definition\">\n");
+
+ bool done(false);
+ char *line;
+ while (!done) {
+ if (!getNextLine())
+ return;
+ line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double periode into one
+ else
+ if (line[1]==0)
+ done = true;
+ }
+ if (!done) {
+ resultAppend(line);
+ resultAppend("\n");
+ }
+ }
+
+ resultAppend("</p></pre>\n</body></html>");
+
+ if (!nextResponseOk(250)) // end of transmission: "250 ok ..."
+ return;
+}
+
+
+void DictAsyncClient::update()
+{
+ cmdBuffer = "show strat\r\nshow db\r\n";
+
+ if (!sendBuffer())
+ return;
+
+ if (!nextResponseOk(111)) // show strat: "111 n strategies present - text follows "
+ return;
+
+ bool done(false);
+ char *line;
+ while (!done) {
+ if (!getNextLine())
+ return;
+ line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double periode into one
+ else
+ if (line[1]==0)
+ done = true;
+ }
+ if (!done) {
+ char *space = strchr(line,' ');
+ if (space) space[0] = 0; // terminate string, hack ;-)
+ job->strategies.append(codec->toUnicode(line));
+ }
+ }
+
+ if (!nextResponseOk(250)) // end of transmission: "250 ok ..."
+ return;
+
+ if (!nextResponseOk(110)) // show db: "110 n databases present - text follows "
+ return;
+
+ done = false;
+ while (!done) {
+ if (!getNextLine())
+ return;
+ line = thisLine;
+ if (line[0]=='.') {
+ if (line[1]=='.')
+ line++; // collapse double periode into one
+ else
+ if (line[1]==0)
+ done = true;
+ }
+ if (!done) {
+ char *space = strchr(line,' ');
+ if (space) space[0] = 0; // terminate string, hack ;-)
+ job->databases.append(codec->toUnicode(line));
+ }
+ }
+
+ if (!nextResponseOk(250)) // end of transmission: "250 ok ..."
+ return;
+}
+
+
+// connect, handshake and authorization
+void DictAsyncClient::openConnection()
+{
+ if (job->server.isEmpty()) {
+ job->error = JobData::ErrBadHost;
+ return;
+ }
+
+ KExtendedSocket ks;
+
+ ks.setAddress(job->server, job->port);
+ ks.setTimeout(job->timeout);
+ if (ks.connect() < 0) {
+ if (ks.status() == IO_LookupError)
+ job->error = JobData::ErrBadHost;
+ else if (ks.status() == IO_ConnectError) {
+ job->result = QString::null;
+ resultAppend(KExtendedSocket::strError(ks.status(), errno));
+ job->error = JobData::ErrConnect;
+ } else if (ks.status() == IO_TimeOutError)
+ job->error = JobData::ErrTimeout;
+ else {
+ job->result = QString::null;
+ resultAppend(KExtendedSocket::strError(ks.status(), errno));
+ job->error = JobData::ErrCommunication;
+ }
+
+ closeSocket();
+ return;
+ }
+ tcpSocket = ks.fd();
+ ks.release();
+
+ if (!nextResponseOk(220)) // connect: "220 text capabilities msg-id"
+ return;
+
+ cmdBuffer = "client \"Kdict ";
+ cmdBuffer += KDICT_VERSION;
+ cmdBuffer += "\"\r\n";
+
+ if (job->authEnabled)
+ if (strstr(thisLine,"auth")) { // skip auth if not supported
+ char *msgId = strrchr(thisLine,'<');
+
+ if ((!msgId)||(!job->user.length())) {
+ job->error = JobData::ErrAuthFailed;
+ closeSocket();
+ return;
+ }
+
+ KMD5 context;
+ context.update(QCString(msgId));
+ context.update(job->secret.local8Bit());
+
+ cmdBuffer += "auth " + job->user.local8Bit() + " ";
+ cmdBuffer += context.hexDigest();
+ cmdBuffer += "\r\n";
+ }
+
+ if (!sendBuffer())
+ return;
+
+ if (!nextResponseOk(250)) // client: "250 ok ..."
+ return;
+
+ if (job->authEnabled)
+ if (!nextResponseOk(230)) // auth: "230 Authentication successful"
+ return;
+}
+
+
+void DictAsyncClient::closeSocket()
+{
+ if (-1 != tcpSocket) {
+ ::close(tcpSocket);
+ tcpSocket = -1;
+ }
+}
+
+
+// send "quit" without timeout, without checks, close connection
+void DictAsyncClient::doQuit()
+{
+ fd_set fdsW;
+ timeval tv;
+
+ FD_ZERO(&fdsW);
+ FD_SET(tcpSocket, &fdsW);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ int ret = KSocks::self()->select(FD_SETSIZE, NULL, &fdsW, NULL, &tv);
+
+ if (ret > 0) { // we can write...
+ cmdBuffer = "quit\r\n";
+ int todo = cmdBuffer.length();
+ KSocks::self()->write(tcpSocket,&cmdBuffer.data()[0],todo);
+ }
+ closeSocket();
+}
+
+
+// used by getNextLine()
+bool DictAsyncClient::waitForRead()
+{
+ fd_set fdsR,fdsE;
+ timeval tv;
+
+ int ret;
+ do {
+ FD_ZERO(&fdsR);
+ FD_SET(fdPipeIn, &fdsR);
+ FD_SET(tcpSocket, &fdsR);
+ FD_ZERO(&fdsE);
+ FD_SET(tcpSocket, &fdsE);
+ FD_SET(fdPipeIn, &fdsE);
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ ret = KSocks::self()->select(FD_SETSIZE, &fdsR, NULL, &fdsE, &tv);
+ } while ((ret<0)&&(errno==EINTR)); // don't get tricked by signals
+
+ if (ret == -1) { // select failed
+ if (job) {
+ job->result = QString::null;
+ resultAppend(strerror(errno));
+ job->error = JobData::ErrCommunication;
+ }
+ closeSocket();
+ return false;
+ }
+ if (ret == 0) { // Nothing happend, timeout
+ if (job)
+ job->error = JobData::ErrTimeout;
+ doQuit();
+ return false;
+ }
+ if (ret > 0) {
+ if (FD_ISSET(fdPipeIn,&fdsR)) { // stop signal
+ doQuit();
+ return false;
+ }
+ if (FD_ISSET(tcpSocket,&fdsE)||FD_ISSET(fdPipeIn,&fdsE)) { // broken pipe, etc
+ if (job) {
+ job->result = QString::null;
+ resultAppend(i18n("The connection is broken."));
+ job->error = JobData::ErrCommunication;
+ }
+ closeSocket();
+ return false;
+ }
+ if (FD_ISSET(tcpSocket,&fdsR)) // all ok
+ return true;
+ }
+
+ if (job) {
+ job->result = QString::null;
+ job->error = JobData::ErrCommunication;
+ }
+ closeSocket();
+ return false;
+}
+
+
+// used by sendBuffer() & connect()
+bool DictAsyncClient::waitForWrite()
+{
+ fd_set fdsR,fdsW,fdsE;
+ timeval tv;
+
+ int ret;
+ do {
+ FD_ZERO(&fdsR);
+ FD_SET(fdPipeIn, &fdsR);
+ FD_SET(tcpSocket, &fdsR);
+ FD_ZERO(&fdsW);
+ FD_SET(tcpSocket, &fdsW);
+ FD_ZERO(&fdsE);
+ FD_SET(tcpSocket, &fdsE);
+ FD_SET(fdPipeIn, &fdsE);
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ ret = KSocks::self()->select(FD_SETSIZE, &fdsR, &fdsW, &fdsE, &tv);
+ } while ((ret<0)&&(errno==EINTR)); // don't get tricked by signals
+
+ if (ret == -1) { // select failed
+ if (job) {
+ job->result = QString::null;
+ resultAppend(strerror(errno));
+ job->error = JobData::ErrCommunication;
+ }
+ closeSocket();
+ return false;
+ }
+ if (ret == 0) { // nothing happend, timeout
+ if (job)
+ job->error = JobData::ErrTimeout;
+ closeSocket();
+ return false;
+ }
+ if (ret > 0) {
+ if (FD_ISSET(fdPipeIn,&fdsR)) { // stop signal
+ doQuit();
+ return false;
+ }
+ if (FD_ISSET(tcpSocket,&fdsR)||FD_ISSET(tcpSocket,&fdsE)||FD_ISSET(fdPipeIn,&fdsE)) { // broken pipe, etc
+ if (job) {
+ job->result = QString::null;
+ resultAppend(i18n("The connection is broken."));
+ job->error = JobData::ErrCommunication;
+ }
+ closeSocket();
+ return false;
+ }
+ if (FD_ISSET(tcpSocket,&fdsW)) // all ok
+ return true;
+ }
+ if (job) {
+ job->result = QString::null;
+ job->error = JobData::ErrCommunication;
+ }
+ closeSocket();
+ return false;
+}
+
+
+// remove start/stop signal
+void DictAsyncClient::clearPipe()
+{
+ fd_set fdsR;
+ timeval tv;
+ int selectRet;
+ char buf;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ do {
+ FD_ZERO(&fdsR);
+ FD_SET(fdPipeIn,&fdsR);
+ if (1==(selectRet=select(FD_SETSIZE,&fdsR,NULL,NULL,&tv)))
+ if ( ::read(fdPipeIn, &buf, 1 ) == -1 )
+ ::perror( "clearPipe()" );
+ } while (selectRet == 1);
+}
+
+
+bool DictAsyncClient::sendBuffer()
+{
+ int ret;
+ int todo = cmdBuffer.length();
+ int done = 0;
+
+ while (todo > 0) {
+ if (!waitForWrite())
+ return false;
+ ret = KSocks::self()->write(tcpSocket,&cmdBuffer.data()[done],todo);
+ if (ret <= 0) {
+ if (job) {
+ job->result = QString::null;
+ resultAppend(strerror(errno));
+ job->error = JobData::ErrCommunication;
+ }
+ closeSocket();
+ return false;
+ } else {
+ done += ret;
+ todo -= ret;
+ }
+ }
+ return true;
+}
+
+
+// set thisLine to next complete line of input
+bool DictAsyncClient::getNextLine()
+{
+ thisLine = nextLine;
+ nextLine = strstr(thisLine,"\r\n");
+ if (nextLine) { // there is another full line in the inputbuffer
+ nextLine[0] = 0; // terminate string
+ nextLine[1] = 0;
+ nextLine+=2;
+ return true;
+ }
+ unsigned int div = inputEnd-thisLine+1; // hmmm, I need to fetch more input from the server...
+ memmove(input,thisLine,div); // save last, incomplete line
+ thisLine = input;
+ inputEnd = input+div-1;
+ do {
+ if ((inputEnd-input) > 9000) {
+ job->error = JobData::ErrMsgTooLong;
+ closeSocket();
+ return false;
+ }
+ if (!waitForRead())
+ return false;
+
+ int received;
+ do {
+ received = KSocks::self()->read(tcpSocket, inputEnd, inputSize-(inputEnd-input)-1);
+ } while ((received<0)&&(errno==EINTR)); // don't get tricked by signals
+
+ if (received <= 0) {
+ job->result = QString::null;
+ resultAppend(i18n("The connection is broken."));
+ job->error = JobData::ErrCommunication;
+ closeSocket();
+ return false;
+ }
+ inputEnd += received;
+ inputEnd[0] = 0; // terminate *char
+ } while (!(nextLine = strstr(thisLine,"\r\n")));
+ nextLine[0] = 0; // terminate string
+ nextLine[1] = 0;
+ nextLine+=2;
+ return true;
+}
+
+
+// reads next line and checks the response code
+bool DictAsyncClient::nextResponseOk(int code)
+{
+ if (!getNextLine())
+ return false;
+ if (strtol(thisLine,0L,0)!=code) {
+ handleErrors();
+ return false;
+ }
+ return true;
+}
+
+
+// reads next line and returns the response code
+bool DictAsyncClient::getNextResponse(int &code)
+{
+ if (!getNextLine())
+ return false;
+ code = strtol(thisLine,0L,0);
+ return true;
+}
+
+
+void DictAsyncClient::handleErrors()
+{
+ int len = strlen(thisLine);
+ if (len>80)
+ len = 80;
+ job->result = QString::null;
+ resultAppend(codec->toUnicode(thisLine,len));
+
+ switch (strtol(thisLine,0L,0)) {
+ case 420:
+ case 421:
+ job->error = JobData::ErrNotAvailable; // server unavailable
+ break;
+ case 500:
+ case 501:
+ job->error = JobData::ErrSyntax; // syntax error
+ break;
+ case 502:
+ case 503:
+ job->error = JobData::ErrCommandNotImplemented; // command not implemented
+ break;
+ case 530:
+ job->error = JobData::ErrAccessDenied; // access denied
+ break;
+ case 531:
+ job->error = JobData::ErrAuthFailed; // authentication failed
+ break;
+ case 550:
+ case 551:
+ job->error = JobData::ErrInvalidDbStrat; // invalid strategy/database
+ break;
+ case 554:
+ job->error = JobData::ErrNoDatabases; // no databases
+ break;
+ case 555:
+ job->error = JobData::ErrNoStrategies; // no strategies
+ break;
+ default:
+ job->error = JobData::ErrServerError;
+ }
+ doQuit();
+}
+
+
+void DictAsyncClient::resultAppend(const char* str)
+{
+ if (job)
+ job->result += codec->toUnicode(str);
+}
+
+
+void DictAsyncClient::resultAppend(QString str)
+{
+ if (job)
+ job->result += str;
+}
+
+
+
+//********* DictInterface ******************************************
+
+DictInterface::DictInterface()
+: newServer(false), clientDoneInProgress(false)
+{
+ if (::pipe(fdPipeIn ) == -1 ) {
+ perror( "Creating in pipe" );
+ KMessageBox::error(global->topLevel, i18n("Internal error:\nFailed to open pipes for internal communication."));
+ kapp->exit(1);
+ }
+ if (::pipe(fdPipeOut ) == -1 ) {
+ perror( "Creating out pipe" );
+ KMessageBox::error(global->topLevel, i18n("Internal error:\nFailed to open pipes for internal communication."));
+ kapp->exit(1);
+ }
+
+ if (-1 == fcntl(fdPipeIn[0],F_SETFL,O_NONBLOCK)) { // make socket non-blocking
+ perror("fcntl()");
+ KMessageBox::error(global->topLevel, i18n("Internal error:\nFailed to open pipes for internal communication."));
+ kapp->exit(1);
+ }
+
+ if (-1 == fcntl(fdPipeOut[0],F_SETFL,O_NONBLOCK)) { // make socket non-blocking
+ perror("fcntl()");
+ KMessageBox::error(global->topLevel, i18n("Internal error:\nFailed to open pipes for internal communication."));
+ kapp->exit(1);
+ }
+
+ notifier = new QSocketNotifier(fdPipeIn[0],QSocketNotifier::Read,this);
+ connect(notifier,SIGNAL(activated(int)),this,SLOT(clientDone()));
+
+ // initialize the KSocks stuff in the main thread, otherwise we get
+ // strange effects on FreeBSD
+ (void) KSocks::self();
+
+ client = new DictAsyncClient(fdPipeOut[0],fdPipeIn[1]);
+ if (0!=pthread_create(&threadID,0,&(client->startThread),client)) {
+ KMessageBox::error(global->topLevel, i18n("Internal error:\nUnable to create thread."));
+ kapp->exit(1);
+ }
+
+ jobList.setAutoDelete(true);
+}
+
+
+DictInterface::~DictInterface()
+{
+ disconnect(notifier,SIGNAL(activated(int)),this,SLOT(clientDone()));
+
+ if (0!=pthread_cancel(threadID))
+ kdWarning() << "pthread_cancel failed!" << endl;
+ if (0!=pthread_join(threadID,NULL))
+ kdWarning() << "pthread_join failed!" << endl;
+ delete client;
+
+ if ( ::close( fdPipeIn[0] ) == -1 ) {
+ perror( "Closing fdPipeIn[0]" );
+ }
+ if ( ::close( fdPipeIn[1] ) == -1 ) {
+ perror( "Closing fdPipeIn[1]" );
+ }
+ if ( ::close( fdPipeOut[0] ) == -1 ) {
+ perror( "Closing fdPipeOut[0]" );
+ }
+ if ( ::close( fdPipeOut[1] ) == -1 ) {
+ perror( "Closing fdPipeOut[1]" );
+ }
+}
+
+
+// inform the client when server settings get changed
+void DictInterface::serverChanged()
+{
+ newServer = true;
+}
+
+
+// cancel all pending jobs
+void DictInterface::stop()
+{
+ if (jobList.isEmpty()) {
+ return;
+ } else {
+ while (jobList.count()>1) // not yet started jobs can be deleted directly
+ jobList.removeLast();
+
+ if (!clientDoneInProgress) {
+ jobList.getFirst()->canceled = true; // clientDone() now ignores the results of this job
+ char buf; // write one char in the pipe to the async thread
+ if (::write(fdPipeOut[1],&buf,1) == -1)
+ ::perror( "stop()" );
+ }
+ }
+}
+
+
+void DictInterface::define(const QString &query)
+{
+ JobData *newJob = generateQuery(JobData::TDefine,query);
+ if (newJob)
+ insertJob(newJob);
+}
+
+
+void DictInterface::getDefinitions(QStringList query)
+{
+ JobData *newjob = new JobData(JobData::TGetDefinitions,newServer,global->server,global->port,
+ global->idleHold,global->timeout,global->pipeSize, global->encoding,global->authEnabled,
+ global->user,global->secret,global->headLayout);
+ newjob->defines = query;
+ newServer = false;
+ insertJob(newjob);
+}
+
+
+void DictInterface::match(const QString &query)
+{
+ JobData *newJob = generateQuery(JobData::TMatch,query);
+
+ if (newJob) {
+ if (global->currentStrategy == 0)
+ newJob->strategy = "."; // spell check strategy
+ else
+ newJob->strategy = global->strategies[global->currentStrategy].utf8();
+
+ insertJob(newJob);
+ }
+}
+
+
+// fetch detailed db info
+void DictInterface::showDbInfo(const QString &db)
+{
+ QString ndb = db.simplifyWhiteSpace(); // cleanup query string
+ if (ndb.isEmpty())
+ return;
+ if (ndb.length()>100) // shorten if necessary
+ ndb.truncate(100);
+ JobData *newjob = new JobData(JobData::TShowDbInfo,newServer,global->server,global->port,
+ global->idleHold,global->timeout,global->pipeSize, global->encoding,global->authEnabled,
+ global->user,global->secret,global->headLayout);
+ newServer = false;
+ newjob->query = ndb; // construct job...
+ insertJob(newjob);
+}
+
+
+void DictInterface::showDatabases()
+{
+ insertJob( new JobData(JobData::TShowDatabases,newServer,global->server,global->port,
+ global->idleHold,global->timeout,global->pipeSize, global->encoding,global->authEnabled,
+ global->user,global->secret,global->headLayout));
+ newServer = false;
+}
+
+
+void DictInterface::showStrategies()
+{
+ insertJob( new JobData(JobData::TShowStrategies,newServer,global->server,global->port,
+ global->idleHold,global->timeout,global->pipeSize, global->encoding,global->authEnabled,
+ global->user,global->secret,global->headLayout));
+ newServer = false;
+}
+
+
+void DictInterface::showInfo()
+{
+ insertJob( new JobData(JobData::TShowInfo,newServer,global->server,global->port,
+ global->idleHold,global->timeout,global->pipeSize, global->encoding,global->authEnabled,
+ global->user,global->secret,global->headLayout));
+ newServer = false;
+}
+
+
+// get info about databases & stratgies the server knows
+void DictInterface::updateServer()
+{
+ insertJob( new JobData(JobData::TUpdate,newServer,global->server,global->port,
+ global->idleHold,global->timeout,global->pipeSize, global->encoding,global->authEnabled,
+ global->user,global->secret,global->headLayout));
+ newServer = false;
+}
+
+
+// client-thread ended
+void DictInterface::clientDone()
+{
+ QString message;
+
+ cleanPipes(); // read from pipe so that notifier doesn´t fire again
+
+ if (jobList.isEmpty()) {
+ kdDebug(5004) << "This shouldn´t happen, the client-thread signaled termination, but the job list is empty" << endl;
+ return; // strange..
+ }
+
+ clientDoneInProgress = true;
+ QStringList::iterator it;
+ JobData* job = jobList.getFirst();
+ if (!job->canceled) { // non-interupted job?
+ if (JobData::ErrNoErr == job->error) {
+ switch (job->type) {
+ case JobData::TUpdate :
+ global->serverDatabases.clear();
+ for (it = job->databases.begin(); it != job->databases.end(); ++it)
+ global->serverDatabases.append(*it);
+ global->databases = global->serverDatabases;
+ for (int i = global->databaseSets.count()-1;i>=0;i--)
+ global->databases.prepend(global->databaseSets.at(i)->first());
+ global->databases.prepend(i18n("All Databases"));
+ global->currentDatabase = 0;
+
+ global->strategies.clear();
+ for (it = job->strategies.begin(); it != job->strategies.end(); ++it)
+ global->strategies.append(*it);
+ global->strategies.prepend(i18n("Spell Check"));
+ global->currentStrategy = 0;
+ message = i18n(" Received database/strategy list ");
+ emit stopped(message);
+ emit infoReady();
+ break;
+ case JobData::TDefine:
+ case JobData::TGetDefinitions:
+ if (job->type == JobData::TDefine) {
+ switch (job->numFetched) {
+ case 0:
+ message = i18n("No definitions found");
+ break;
+ case 1:
+ message = i18n("One definition found");
+ break;
+ default:
+ message = i18n("%1 definitions found").arg(job->numFetched);
+ }
+ } else {
+ switch (job->numFetched) {
+ case 0:
+ message = i18n(" No definitions fetched ");
+ break;
+ case 1:
+ message = i18n(" One definition fetched ");
+ break;
+ default:
+ message = i18n(" %1 definitions fetched ").arg(job->numFetched);
+ }
+ }
+ emit stopped(message);
+ emit resultReady(job->result, job->query);
+ break;
+ case JobData::TMatch:
+ switch (job->numFetched) {
+ case 0:
+ message = i18n(" No matching definitions found ");
+ break;
+ case 1:
+ message = i18n(" One matching definition found ");
+ break;
+ default:
+ message = i18n(" %1 matching definitions found ").arg(job->numFetched);
+ }
+ emit stopped(message);
+ emit matchReady(job->matches);
+ break;
+ default :
+ message = i18n(" Received information ");
+ emit stopped(message);
+ emit resultReady(job->result, job->query);
+ }
+ } else {
+ QString errMsg;
+ switch (job->error) {
+ case JobData::ErrCommunication:
+ errMsg = i18n("Communication error:\n\n");
+ errMsg += job->result;
+ break;
+ case JobData::ErrTimeout:
+ errMsg = i18n("A delay occurred which exceeded the\ncurrent timeout limit of %1 seconds.\nYou can modify this limit in the Preferences Dialog.").arg(global->timeout);
+ break;
+ case JobData::ErrBadHost:
+ errMsg = i18n("Unable to connect to:\n%1:%2\n\nCannot resolve hostname.").arg(job->server).arg(job->port);
+ break;
+ case JobData::ErrConnect:
+ errMsg = i18n("Unable to connect to:\n%1:%2\n\n").arg(job->server).arg(job->port);
+ errMsg += job->result;
+ break;
+ case JobData::ErrRefused:
+ errMsg = i18n("Unable to connect to:\n%1:%2\n\nThe server refused the connection.").arg(job->server).arg(job->port);
+ break;
+ case JobData::ErrNotAvailable:
+ errMsg = i18n("The server is temporarily unavailable.");
+ break;
+ case JobData::ErrSyntax:
+ errMsg = i18n("The server reported a syntax error.\nThis shouldn't happen -- please consider\nwriting a bug report.");
+ break;
+ case JobData::ErrCommandNotImplemented:
+ errMsg = i18n("A command that Kdict needs isn't\nimplemented on the server.");
+ break;
+ case JobData::ErrAccessDenied:
+ errMsg = i18n("Access denied.\nThis host is not allowed to connect.");
+ break;
+ case JobData::ErrAuthFailed:
+ errMsg = i18n("Authentication failed.\nPlease enter a valid username and password.");
+ break;
+ case JobData::ErrInvalidDbStrat:
+ errMsg = i18n("Invalid database/strategy.\nYou probably need to use Server->Get Capabilities.");
+ break;
+ case JobData::ErrNoDatabases:
+ errMsg = i18n("No databases available.\nIt is possible that you need to authenticate\nwith a valid username/password combination to\ngain access to any databases.");
+ break;
+ case JobData::ErrNoStrategies:
+ errMsg = i18n("No strategies available.");
+ break;
+ case JobData::ErrServerError:
+ errMsg = i18n("The server sent an unexpected reply:\n\"%1\"\nThis shouldn't happen, please consider\nwriting a bug report").arg(job->result);
+ break;
+ case JobData::ErrMsgTooLong:
+ errMsg = i18n("The server sent a response with a text line\nthat was too long.\n(RFC 2229: max. 1024 characters/6144 octets)");
+ break;
+ case JobData::ErrNoErr: // make compiler happy
+ errMsg = i18n("No Errors");
+ }
+ message = i18n(" Error ");
+ emit stopped(message);
+ KMessageBox::error(global->topLevel, errMsg);
+ }
+ } else {
+ message = i18n(" Stopped ");
+ emit stopped(message);
+ }
+
+ clientDoneInProgress = false;
+
+ client->removeJob();
+ jobList.removeFirst(); // this job is now history
+ if (!jobList.isEmpty()) // work to be done?
+ startClient(); // => restart client
+}
+
+
+JobData* DictInterface::generateQuery(JobData::QueryType type, QString query)
+{
+ query = query.simplifyWhiteSpace(); // cleanup query string
+ if (query.isEmpty())
+ return 0L;
+ if (query.length()>300) // shorten if necessary
+ query.truncate(300);
+ query = query.replace(QRegExp("[\"\\]"), ""); // remove remaining illegal chars...
+ if (query.isEmpty())
+ return 0L;
+
+ JobData *newjob = new JobData(type,newServer,global->server,global->port,
+ global->idleHold,global->timeout,global->pipeSize, global->encoding, global->authEnabled,
+ global->user,global->secret,global->headLayout);
+ newServer = false;
+ newjob->query = query; // construct job...
+
+ if (global->currentDatabase == 0) // all databases
+ newjob->databases.append("*");
+ else {
+ if ((global->currentDatabase > 0)&& // database set
+ (global->currentDatabase < global->databaseSets.count()+1)) {
+ for (int i = 0;i<(int)global->serverDatabases.count();i++)
+ if ((global->databaseSets.at(global->currentDatabase-1))->findIndex(global->serverDatabases[i])>0)
+ newjob->databases.append(global->serverDatabases[i].utf8().data());
+ if (newjob->databases.count()==0) {
+ KMessageBox::sorry(global->topLevel, i18n("Please select at least one database."));
+ delete newjob;
+ return 0L;
+ }
+ } else { // one database
+ newjob->databases.append(global->databases[global->currentDatabase].utf8().data());
+ }
+ }
+
+ return newjob;
+}
+
+
+void DictInterface::insertJob(JobData* job)
+{
+ if (jobList.isEmpty()) { // Client has nothing to do, start directly
+ jobList.append(job);
+ startClient();
+ } else { // there are other pending jobs...
+ stop();
+ jobList.append(job);
+ }
+}
+
+
+// start client-thread
+void DictInterface::startClient()
+{
+ cleanPipes();
+ if (jobList.isEmpty()) {
+ kdDebug(5004) << "This shouldn´t happen, startClient called, but clientList is empty" << endl;
+ return;
+ }
+
+ client->insertJob(jobList.getFirst());
+ char buf; // write one char in the pipe to the async thread
+ if (::write(fdPipeOut[1],&buf,1) == -1)
+ ::perror( "startClient()" );
+
+ QString message;
+ switch (jobList.getFirst()->type) {
+ case JobData::TDefine:
+ case JobData::TGetDefinitions:
+ case JobData::TMatch:
+ message = i18n(" Querying server... ");
+ break;
+ case JobData::TShowDatabases:
+ case JobData::TShowStrategies:
+ case JobData::TShowInfo:
+ case JobData::TShowDbInfo:
+ message = i18n(" Fetching information... ");
+ break;
+ case JobData::TUpdate:
+ message = i18n(" Updating server information... ");
+ break;
+ }
+ emit started(message);
+}
+
+
+// empty the pipes, so that notifier stops firing
+void DictInterface::cleanPipes()
+{
+ fd_set rfds;
+ struct timeval tv;
+ int ret;
+ char buf;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ do {
+ FD_ZERO(&rfds);
+ FD_SET(fdPipeIn[0],&rfds);
+ if (1==(ret=select(FD_SETSIZE,&rfds,NULL,NULL,&tv)))
+ if ( ::read(fdPipeIn[0], &buf, 1 ) == -1 )
+ ::perror( "cleanPipes" );
+ } while (ret == 1);
+
+ do {
+ FD_ZERO(&rfds);
+ FD_SET(fdPipeOut[0],&rfds);
+ if (1==(ret=select(FD_SETSIZE,&rfds,NULL,NULL,&tv)))
+ if ( ::read(fdPipeOut[0], &buf, 1 ) == -1 )
+ ::perror( "cleanPipes" );
+ } while (ret == 1);
+}
+
+//--------------------------------
+
+#include "dict.moc"
diff --git a/kdict/dict.h b/kdict/dict.h
new file mode 100644
index 00000000..adb87ed9
--- /dev/null
+++ b/kdict/dict.h
@@ -0,0 +1,204 @@
+/* -------------------------------------------------------------
+
+ dict.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+ (C) by Matthias Hölzer 1998
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ JobData used for data transfer between Client and Interface
+ DictAsyncClient all network related stuff happens here in an asynchrous thread
+ DictInterface interface for DictAsyncClient, job management
+
+ -------------------------------------------------------------*/
+
+#ifndef _DICT_H_
+#define _DICT_H_
+
+#include <pthread.h>
+#include <qptrlist.h>
+#include <qsocketnotifier.h>
+
+class QSocketNotifier;
+struct in_addr;
+
+
+//********* JobData ******************************************
+
+
+class JobData
+{
+
+public:
+
+ enum QueryType { //type of transaction
+ TDefine=0,
+ TGetDefinitions,
+ TMatch,
+ TShowDatabases,
+ TShowDbInfo,
+ TShowStrategies,
+ TShowInfo,
+ TUpdate
+ };
+
+ enum ErrType { // error codes
+ ErrNoErr=0,
+ ErrCommunication, // display result!
+ ErrTimeout,
+ ErrBadHost,
+ ErrConnect, // display result!
+ ErrRefused,
+ ErrNotAvailable,
+ ErrSyntax,
+ ErrCommandNotImplemented,
+ ErrAccessDenied,
+ ErrAuthFailed,
+ ErrInvalidDbStrat,
+ ErrNoDatabases,
+ ErrNoStrategies,
+ ErrServerError, // display result!
+ ErrMsgTooLong
+ };
+
+ JobData(QueryType Ntype,bool NnewServer,QString const& Nserver,int Nport,
+ int NidleHold, int Ntimeout, int NpipeSize, QString const& Nencoding, bool NAuthEnabled,
+ QString const& Nuser, QString const& Nsecret, unsigned int NheadLayout);
+
+ QueryType type;
+ ErrType error;
+
+ bool canceled;
+ int numFetched;
+ QString result;
+ QStringList matches;
+
+ QString query;
+ QStringList defines;
+
+ bool newServer;
+ QString server;
+ int port, timeout, pipeSize, idleHold;
+ QString encoding;
+ bool authEnabled;
+ QString user, secret;
+ QStringList databases,strategies;
+ QString strategy;
+ unsigned int headLayout;
+};
+
+
+//********* DictAsyncClient ******************************************
+
+
+class DictAsyncClient
+{
+
+public:
+
+ DictAsyncClient(int NfdPipeIn, int NfdPipeOut);
+ ~DictAsyncClient();
+
+ static void* startThread(void* pseudoThis);
+
+ void insertJob(JobData *newJob);
+ void removeJob();
+
+private:
+
+ void waitForWork(); // main loop
+ void define();
+ bool getDefinitions();
+ bool match();
+ void showDatabases();
+ void showDbInfo();
+ void showStrategies();
+ void showInfo();
+ void update();
+
+ void openConnection(); // connect, handshake and authorization
+ void closeSocket();
+ void doQuit(); // send "quit" without timeout, without checks, close connection
+ bool waitForRead(); // used by getNextIntoBuffer()
+ bool waitForWrite(); // used by sendBuffer() & connect()
+ void clearPipe(); // remove start/stop signal
+
+ bool sendBuffer(); // send cmdBuffer to the server
+ bool getNextLine(); // set thisLine to next complete line of input
+ bool nextResponseOk(int code); // reads next line and checks the response code
+ bool getNextResponse(int &code); // reads next line and returns the response code
+ void handleErrors();
+
+ void resultAppend(const char* str);
+ void resultAppend(QString str);
+
+ JobData *job;
+ char *input;
+ QCString cmdBuffer;
+ const unsigned int inputSize;
+ char *thisLine, *nextLine, *inputEnd;
+ int fdPipeIn,fdPipeOut; //IPC-Pipes to/from async thread
+ int tcpSocket,timeout,idleHold;
+ QTextCodec *codec;
+};
+
+
+//********* DictInterface *************************************************
+
+class DictInterface : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ DictInterface();
+ ~DictInterface();
+
+public slots:
+
+ void serverChanged(); // inform the client when server settings get changed
+ void stop(); // cancel all pending jobs
+
+ void define(const QString &query);
+ void getDefinitions(QStringList query);
+ void match(const QString &query);
+ void showDbInfo(const QString &db); // fetch detailed db info
+ void showDatabases(); // fetch misc. info...
+ void showStrategies();
+ void showInfo();
+ void updateServer(); // get info about databases & strategies the server knows
+
+signals:
+
+ void infoReady(); // updateServer done
+ void resultReady(const QString &result, const QString &query); // define done
+ void matchReady(const QStringList &result); // match done
+ void started(const QString &message); // Client is active now, activate indicator
+ void stopped(const QString &message); // Client is now halted, deactivate indicator
+
+private slots:
+
+ void clientDone();
+
+private:
+
+ JobData* generateQuery(JobData::QueryType type, QString query);
+ void insertJob(JobData* job); // insert in job list, if nesscary cancel/remove previous jobs
+ void startClient(); // send start signal
+ void cleanPipes(); // empty the pipes, so that notifier stops firing
+
+ QSocketNotifier *notifier;
+ int fdPipeIn[2],fdPipeOut[2]; //IPC-Pipes to/from async thread
+ pthread_t threadID;
+ DictAsyncClient *client;
+ QPtrList<JobData> jobList;
+ bool newServer,clientDoneInProgress;
+};
+
+extern DictInterface *interface;
+
+#endif
diff --git a/kdict/hi128-app-kdict.png b/kdict/hi128-app-kdict.png
new file mode 100644
index 00000000..fd57f9ab
--- /dev/null
+++ b/kdict/hi128-app-kdict.png
Binary files differ
diff --git a/kdict/hi16-app-kdict.png b/kdict/hi16-app-kdict.png
new file mode 100644
index 00000000..643500fc
--- /dev/null
+++ b/kdict/hi16-app-kdict.png
Binary files differ
diff --git a/kdict/hi32-app-kdict.png b/kdict/hi32-app-kdict.png
new file mode 100644
index 00000000..fa3a0537
--- /dev/null
+++ b/kdict/hi32-app-kdict.png
Binary files differ
diff --git a/kdict/hi48-app-kdict.png b/kdict/hi48-app-kdict.png
new file mode 100644
index 00000000..40efecd0
--- /dev/null
+++ b/kdict/hi48-app-kdict.png
Binary files differ
diff --git a/kdict/hi64-app-kdict.png b/kdict/hi64-app-kdict.png
new file mode 100644
index 00000000..ba6ed634
--- /dev/null
+++ b/kdict/hi64-app-kdict.png
Binary files differ
diff --git a/kdict/hisc-app-kdict.svgz b/kdict/hisc-app-kdict.svgz
new file mode 100644
index 00000000..584e1968
--- /dev/null
+++ b/kdict/hisc-app-kdict.svgz
Binary files differ
diff --git a/kdict/kdict.desktop b/kdict/kdict.desktop
new file mode 100644
index 00000000..d274d233
--- /dev/null
+++ b/kdict/kdict.desktop
@@ -0,0 +1,153 @@
+[Desktop Entry]
+Type=Application
+Exec=kdict -caption "%c" %i %m
+Icon=kdict
+Terminal=false
+Name=Dictionary
+Name[af]=Woordeboek
+Name[ar]=القاموس
+Name[az]=Lüğət
+Name[be]=Слоўнік
+Name[bg]=Речник
+Name[bn]=অভিধান
+Name[br]=Geriadur
+Name[bs]=RjeÄnik
+Name[ca]=Diccionari
+Name[cs]=Slovník
+Name[cy]=Geiriadur
+Name[da]=Ordbog
+Name[de]=Lexikon
+Name[el]=Λεξικό
+Name[eo]=Vortaro
+Name[es]=Diccionario
+Name[et]=Sõnaraamat
+Name[eu]=Hiztegia
+Name[fa]=واژه‌نامه
+Name[fi]=Sanakirja
+Name[fr]=Dictionnaire
+Name[ga]=Foclóir
+Name[gl]=Diccionario
+Name[he]=מילון
+Name[hi]=शबà¥à¤¦à¤•à¥‹à¤¶
+Name[hr]=RjeÄnik
+Name[hu]=Szótár
+Name[is]=Orðabók
+Name[it]=Dizionario
+Name[ja]=辞書
+Name[ka]=ლექსიკáƒáƒœáƒ˜
+Name[kk]=Сөздік
+Name[km]=វចនានុក្រម
+Name[ko]=사전
+Name[lt]=Žodynas
+Name[lv]=VÄrdnÄ«ca
+Name[mk]=Речник
+Name[mn]=Толь бичиг
+Name[ms]=Kamus
+Name[mt]=Dizzjunarju
+Name[nb]=Ordbok
+Name[nds]=Wöörbook
+Name[ne]=शबà¥à¤¦à¤•à¥‹à¤¶
+Name[nl]=Woordenboek
+Name[nn]=Ordbok
+Name[nso]=Pukuntsu
+Name[pa]=ਸ਼ਬਦ-ਕੋਸ਼
+Name[pl]=SÅ‚ownik
+Name[pt]=Dicionário
+Name[pt_BR]=Dicionário
+Name[ro]=Dicţionar
+Name[ru]=Словарь
+Name[se]=Sátnegirji
+Name[sk]=Slovník
+Name[sl]=Slovar
+Name[sr]=Речник
+Name[sr@Latn]=ReÄnik
+Name[sv]=Ordlista
+Name[ta]=அகராதி
+Name[tg]=Луғат
+Name[th]=พจนานุà¸à¸£à¸¡
+Name[tr]=Sözlük
+Name[uk]=Словник
+Name[uz]=Lugʻat
+Name[uz@cyrillic]=Луғат
+Name[ven]=Bugu yau talutshedza maipfi
+Name[wa]=Motî
+Name[xh]=Incwadi eneenkcazelo zamagama
+Name[zh_CN]=å­—å…¸
+Name[zh_HK]=å­—å…¸
+Name[zh_TW]=å­—å…¸
+Name[zu]=Isichazamagama
+GenericName=Online Dictionary
+GenericName[af]=Aan-lyn Woordeboek
+GenericName[ar]=قاموس على الإنترنت
+GenericName[be]=Сеткавы Ñлоўнік
+GenericName[bg]=Мрежови речник
+GenericName[bn]=অনলাইন অভিধান
+GenericName[br]=Geriaoueg enlinenn
+GenericName[bs]=Online rjeÄnik
+GenericName[ca]=Diccionari en línia
+GenericName[cs]=Online slovník
+GenericName[cy]=Geiriadur Ar-lein
+GenericName[da]=Online-ordbog
+GenericName[de]=Online-Lexikon
+GenericName[el]=Διαδικτυακό λεξικό
+GenericName[eo]=Vortaro
+GenericName[es]=Diccionario en la red
+GenericName[et]=Võrgusõnaraamat
+GenericName[eu]=On line hiztegia
+GenericName[fa]=واژه‌نامۀ برخط
+GenericName[fi]=Sanakirja
+GenericName[fr]=Dictionnaire électronique
+GenericName[ga]=Foclóir ar líne
+GenericName[gl]=Diccionario en liña
+GenericName[he]=מילון מקוון
+GenericName[hi]=ऑनलाइन शबà¥à¤¦à¤•à¥‹à¤¶
+GenericName[hr]=Online rjeÄnik
+GenericName[hu]=Szótárkezelő
+GenericName[is]=Orðabók á Netinu
+GenericName[it]=Dizionario in linea
+GenericName[ja]=オンライン辞書
+GenericName[ka]=ხáƒáƒ–ის ლექსიკáƒáƒœáƒ˜
+GenericName[kk]=Онлайн Ñөздік
+GenericName[km]=វចនានុក្រម​លើ​បណ្ដាញ
+GenericName[lt]=Žodynas tinkle
+GenericName[lv]=TieÅ¡saites VÄrdnÄ«ca
+GenericName[mk]=Речник на линија
+GenericName[mn]=Онлайн-Толь бичиг
+GenericName[ms]=Kamus Talian
+GenericName[mt]=Dizzjunarju online
+GenericName[nb]=Ordbok på nettet
+GenericName[nds]=Online-Wöörbook
+GenericName[ne]=अनलाइन शबà¥à¤¦à¤•à¥‹à¤¶
+GenericName[nl]=Online woordenboek
+GenericName[nn]=Internettordbok
+GenericName[nso]=Pukuntsu ya Online
+GenericName[pa]=ਆਨਲਾਇਨ ਡਿਕਸ਼ਨਰੀ
+GenericName[pl]=SÅ‚ownik w sieci
+GenericName[pt]=Dicionário na Rede
+GenericName[pt_BR]= Dicionário On-line
+GenericName[ro]=Dicţionar on-line
+GenericName[ru]=Онлайн-Ñловарь
+GenericName[se]=Fierpmádatsátnegirji
+GenericName[sk]=On-line slovník
+GenericName[sl]=Spletni slovar
+GenericName[sr]=Онлајн речник
+GenericName[sr@Latn]=Onlajn reÄnik
+GenericName[sv]=Online-ordlista
+GenericName[ta]=இணைய அகராதி
+GenericName[tg]=Луғати Шабакавӣ
+GenericName[th]=พจนานุà¸à¸£à¸¡à¹à¸šà¸šà¸­à¸­à¸™à¹„ลน์
+GenericName[tr]=Çevrimiçi Sözlük
+GenericName[uk]=Словник в мережі
+GenericName[uz]=Internet lugʻat
+GenericName[uz@cyrillic]=Интернет луғат
+GenericName[ven]=Bugu talutshedza maipfi ine yavha kha mutevhe wau tshimbila
+GenericName[wa]=Motî so les fyis
+GenericName[xh]=Incwadi eneenkcazelo zamagama Esemgceni
+GenericName[zh_CN]=在线字典
+GenericName[zh_HK]=線上字典
+GenericName[zh_TW]=線上字典
+GenericName[zu]=Isichaza magama esixhumekile
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Unique
+DocPath=kdict/index.html
+Categories=Qt;KDE;Network;X-KDE-More;Office;Dictionary;
diff --git a/kdict/kdictui.rc b/kdict/kdictui.rc
new file mode 100644
index 00000000..15b3c414
--- /dev/null
+++ b/kdict/kdictui.rc
@@ -0,0 +1,59 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="Kdict" version="4">
+
+<MenuBar>
+ <Menu noMerge="1" name="file"><text>&amp;File</text>
+ <Action name="file_save"/>
+ <Action name="file_print"/>
+ <Separator/>
+ <Action name="start_query"/>
+ <Action name="stop_query"/>
+ <Separator/>
+ <Action name="file_quit"/>
+ </Menu>
+ <Menu noMerge="1" name="edit"><text>&amp;Edit</text>
+ <Action name="edit_copy"/>
+ <Action name="edit_select_all"/>
+ <Separator/>
+ <Action name="define_clipboard"/>
+ <Action name="match_clipboard"/>
+ <Separator/>
+ <Action name="edit_find"/>
+ </Menu>
+ <Menu name="history"><text>Hist&amp;ory</text>
+ <Action name="browse_back"/>
+ <Action name="browse_forward"/>
+ <Separator />
+ <Action name="clear_history"/>
+ <Separator />
+ <ActionList name="history_items"/>
+ </Menu>
+ <Menu name="server"><text>Ser&amp;ver</text>
+ <Action name="get_capabilities"/>
+ <Action name="edit_sets"/>
+ <Separator />
+ <Menu name="database_sub"><text>Database &amp;Information</text>
+ <Action name="db_summary"/>
+ <Separator />
+ <ActionList name="db_detail"/>
+ </Menu>
+ <Action name="strategy_info"/>
+ <Action name="server_info"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="show_match" append="show_merge"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar fullWidth="true" newline="true" noMerge="1" name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="clear_query"/>
+ <Action name="look_label"/>
+ <Action name="query_combo"/>
+ <Separator/>
+ <Action name="define_btn"/>
+ <Action name="match_btn"/>
+</ToolBar>
+
+<StatusBar/>
+
+</kpartgui>
diff --git a/kdict/main.cpp b/kdict/main.cpp
new file mode 100644
index 00000000..235f9048
--- /dev/null
+++ b/kdict/main.cpp
@@ -0,0 +1,56 @@
+/* -------------------------------------------------------------
+
+ main.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+ (C) by Matthias H�zer 1998
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ ------------------------------------------------------------- */
+
+#include <config.h>
+
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kdelibs_export.h>
+
+#include "application.h"
+#include "toplevel.h"
+
+static KCmdLineOptions knoptions[] =
+{
+ { "c", 0, 0 },
+ { "clipboard", I18N_NOOP("Define X11-clipboard content (selected text)"), 0 },
+ { "+[word/phrase]", I18N_NOOP("Lookup the given word/phrase"), 0 },
+ KCmdLineLastOption
+};
+
+
+extern "C" KDE_EXPORT int kdemain(int argc, char* argv[])
+{
+ KAboutData aboutData("kdict",
+ I18N_NOOP("Dictionary"),
+ KDICT_VERSION,
+ I18N_NOOP("The KDE Dictionary Client"),
+ KAboutData:: License_Artistic,
+ "Copyright (c) 1999-2001, Christian Gebauer\nCopyright (c) 1998, Matthias Hoelzer",
+ 0,
+ 0);
+
+ aboutData.addAuthor("Christian Gebauer",I18N_NOOP("Maintainer"),"gebauer@kde.org");
+ aboutData.addAuthor("Matthias Hoelzer",I18N_NOOP("Original Author"),"hoelzer@kde.org");
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( knoptions );
+ KUniqueApplication::addCmdLineOptions();
+
+ if (!Application::start())
+ return 0;
+
+ Application app;
+
+ return app.exec();
+}
diff --git a/kdict/matchview.cpp b/kdict/matchview.cpp
new file mode 100644
index 00000000..32cd04dd
--- /dev/null
+++ b/kdict/matchview.cpp
@@ -0,0 +1,473 @@
+/* -------------------------------------------------------------
+
+ matchview.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ MatchView This widget contains the list of matching definitions
+
+ ------------------------------------------------------------- */
+
+#include <qclipboard.h>
+#include <qcombobox.h>
+#include <qpushbutton.h>
+#include <qheader.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qregexp.h>
+
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+#include "dict.h"
+#include "options.h"
+#include "matchview.h"
+
+
+//********* MatchViewItem ********************************************
+
+
+MatchViewItem::MatchViewItem(QListView *view, const QString &text)
+ : QListViewItem(view,text)
+{
+}
+
+
+MatchViewItem::MatchViewItem(QListView *view,QListViewItem *after,const QString &text)
+ : QListViewItem(view,after,text)
+{
+}
+
+
+MatchViewItem::MatchViewItem(QListViewItem *item,const QString &text,const QString &commandStr)
+: QListViewItem(item,text), command(commandStr)
+{
+}
+
+
+MatchViewItem::MatchViewItem(QListViewItem *item,QListViewItem *after,const QString &text,const QString &commandStr)
+: QListViewItem(item,after,text), command(commandStr)
+{
+}
+
+
+MatchViewItem::~MatchViewItem()
+{
+}
+
+
+void MatchViewItem::setOpen(bool o)
+{
+ if (o && !childCount()) {
+ listView()->setUpdatesEnabled(false);
+
+ MatchViewItem *sub=0;
+ QString command, label;
+ QRegExp exp("\"*\"", true, true);
+ QStringList::iterator it;
+ for (it = subEntrys.begin(); it != subEntrys.end(); ++it) {
+ command = "define ";
+ command += (*it);
+ command += "\r\n";
+ exp.search((*it));
+ label = exp.cap();
+ label = label.mid(1, label.length()-2); // remove quotes
+ if (sub)
+ sub = new MatchViewItem(this, sub, label, command);
+ else
+ sub = new MatchViewItem(this, label, command);
+ }
+
+ subEntrys.clear();
+
+ listView()->setUpdatesEnabled(true);
+ }
+
+ if (childCount())
+ QListViewItem::setOpen(o);
+}
+
+
+void MatchViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment)
+{
+ if(command.isEmpty()) {
+ QFont font=p->font();
+ font.setBold(true);
+ p->setFont(font);
+ }
+ QListViewItem::paintCell(p,cg,column,width,alignment);
+}
+
+
+//********* MatchView ******************************************
+
+
+MatchView::MatchView(QWidget *parent, const char *name)
+ : QWidget(parent,name),getOn(false),getAllOn(false)
+{
+ setCaption(kapp->makeStdCaption(i18n("Match List")));
+
+ QVBoxLayout * boxLayout = new QVBoxLayout(this, 1, 0);
+
+ boxLayout->addSpacing(1);
+ w_strat = new QComboBox(false,this);
+ w_strat->setFixedHeight(w_strat->sizeHint().height());
+ connect(w_strat,SIGNAL(activated(int)),this,SLOT(strategySelected(int)));
+ boxLayout->addWidget(w_strat,0);
+ boxLayout->addSpacing(1);
+
+ w_list = new QListView(this);
+ w_list->setFocusPolicy(QWidget::StrongFocus);
+ w_list->header()->hide();
+ w_list->addColumn("foo");
+ w_list->setColumnWidthMode(0,QListView::Maximum);
+ w_list->setColumnWidth(0,0);
+ w_list->setSelectionMode(QListView::Extended);
+ w_list->setTreeStepSize(18);
+ w_list->setSorting(-1); // disable sorting
+ w_list->setMinimumHeight(w_strat->sizeHint().height());
+ connect(w_list,SIGNAL(selectionChanged()),SLOT(enableGetButton()));
+ connect(w_list,SIGNAL(returnPressed(QListViewItem *)),SLOT(returnPressed(QListViewItem *)));
+ connect(w_list,SIGNAL(doubleClicked(QListViewItem *)),SLOT(getOneItem(QListViewItem *)));
+ connect(w_list,SIGNAL(mouseButtonPressed(int, QListViewItem *, const QPoint &, int)),
+ SLOT(mouseButtonPressed(int, QListViewItem *, const QPoint &, int)));
+ connect(w_list,SIGNAL(rightButtonPressed(QListViewItem *,const QPoint &,int)),SLOT(buildPopupMenu(QListViewItem *,const QPoint &,int)));
+ boxLayout->addWidget(w_list,1);
+
+ boxLayout->addSpacing(1);
+ w_get = new QPushButton(i18n("&Get Selected"),this);
+ w_get->setFixedHeight(w_get->sizeHint().height()-3);
+ w_get->setMinimumWidth(w_get->sizeHint().width()-20);
+ w_get->setEnabled(false);
+ connect(w_get, SIGNAL(clicked()), this, SLOT(getSelected()));
+ boxLayout->addWidget(w_get,0);
+
+ w_getAll = new QPushButton(i18n("Get &All"),this);
+ w_getAll->setFixedHeight(w_getAll->sizeHint().height()-3);
+ w_getAll->setMinimumWidth(w_getAll->sizeHint().width()-20);
+ w_getAll->setEnabled(false);
+ connect(w_getAll, SIGNAL(clicked()), this, SLOT(getAll()));
+ boxLayout->addWidget(w_getAll,0);
+ connect(interface,SIGNAL(matchReady(const QStringList &)),this,SLOT(newList(const QStringList &)));
+ rightBtnMenu = new KPopupMenu();
+}
+
+
+MatchView::~MatchView()
+{
+}
+
+
+void MatchView::updateStrategyCombo()
+{
+ w_strat->clear();
+ w_strat->insertStringList(global->strategies);
+ w_strat->setCurrentItem(global->currentStrategy);
+}
+
+
+bool MatchView::selectStrategy(const QString &strategy) const
+{
+ int newCurrent = global->strategies.findIndex(strategy);
+ if (newCurrent == -1)
+ return false;
+ else {
+ global->currentStrategy = newCurrent;
+ w_strat->setCurrentItem(global->currentStrategy);
+ return true;
+ }
+}
+
+
+void MatchView::match(const QString &query)
+{
+ interface->match(query.utf8());
+}
+
+
+void MatchView::closeEvent ( QCloseEvent * e )
+{
+ e->accept(); // hides the widget
+ emit(windowClosed());
+}
+
+
+void MatchView::strategySelected(int num)
+{
+ global->currentStrategy = num;
+}
+
+
+void MatchView::enableGetButton()
+{
+ if (w_getAll->isEnabled()) {
+ w_get->setEnabled(true);
+ getOn = true;
+ }
+}
+
+
+void MatchView::mouseButtonPressed(int button, QListViewItem *, const QPoint &, int)
+{
+ if (button == MidButton)
+ emit(clipboardRequested());
+}
+
+
+void MatchView::returnPressed(QListViewItem *)
+{
+ getSelected();
+}
+
+
+void MatchView::getOneItem(QListViewItem *i)
+{
+ QStringList defines;
+
+ if ((!i->childCount())&&(i->parent()))
+ defines.append(((MatchViewItem *)(i))->command);
+ else {
+ i = i->firstChild();
+ while (i) {
+ defines.append(((MatchViewItem *)(i))->command);
+ i = i->nextSibling();
+ }
+ }
+
+ doGet(defines);
+}
+
+
+void MatchView::getSelected()
+{
+ QStringList defines;
+ MatchViewItem *top = static_cast<MatchViewItem*>(w_list->firstChild());
+ MatchViewItem *sub;
+
+ while (top) {
+ if (top->isSelected()&&(!top->subEntrys.isEmpty())) {
+ QString command;
+ QStringList::iterator it;
+ for (it = top->subEntrys.begin(); it != top->subEntrys.end(); ++it) {
+ command = "define ";
+ command += (*it);
+ command += "\r\n";
+ defines.append(command);
+ }
+ } else {
+ sub = static_cast<MatchViewItem*>(top->firstChild());
+ while (sub) {
+ if (top->isSelected()||sub->isSelected())
+ defines.append(sub->command);
+ sub = static_cast<MatchViewItem*>(sub->nextSibling());
+ }
+ }
+ top = static_cast<MatchViewItem*>(top->nextSibling());
+ }
+ doGet(defines);
+}
+
+
+void MatchView::getAll()
+{
+ QStringList defines;
+ MatchViewItem *top = static_cast<MatchViewItem*>(w_list->firstChild());
+ MatchViewItem *sub;
+
+ while (top) {
+ if (!top->subEntrys.isEmpty()) {
+ QString command;
+ QStringList::iterator it;
+ for (it = top->subEntrys.begin(); it != top->subEntrys.end(); ++it) {
+ command = "define ";
+ command += (*it);
+ command += "\r\n";
+ defines.append(command);
+ }
+ } else {
+ sub = static_cast<MatchViewItem*>(top->firstChild());
+ while (sub) {
+ defines.append(sub->command);
+ sub = static_cast<MatchViewItem*>(sub->nextSibling());
+ }
+ }
+ top = static_cast<MatchViewItem*>(top->nextSibling());
+ }
+ doGet(defines);
+}
+
+
+void MatchView::doGet(QStringList &defines)
+{
+ if (defines.count() > 0) {
+ if (defines.count() > global->maxDefinitions) {
+ KMessageBox::sorry(global->topLevel,i18n("You have selected %1 definitions,\nbut Kdict will fetch only the first %2 definitions.\nYou can modify this limit in the Preferences Dialog.")
+ .arg(defines.count()).arg(global->maxDefinitions));
+ while (defines.count()>global->maxDefinitions)
+ defines.pop_back();
+ }
+ interface->getDefinitions(defines);
+ }
+}
+
+
+void MatchView::newList(const QStringList &matches)
+{
+ MatchViewItem *top=0;
+ bool initialOpen = (matches.count()<200);
+ int numDb = 0;
+
+ rightBtnMenu->hide();
+ w_list->clear();
+ w_list->setColumnWidth(0,0);
+ w_list->setUpdatesEnabled(false);
+ w_get->setEnabled(false);
+ getOn = false;
+
+ if (matches.isEmpty()) {
+ w_list->setColumnWidth(0,w_get->width()-5);
+ w_list->setRootIsDecorated(false);
+ w_getAll->setEnabled(false);
+ getAllOn = false;
+ top = new MatchViewItem(w_list,top,i18n(" No Hits"));
+ } else {
+ w_list->setRootIsDecorated(true);
+ w_getAll->setEnabled(true);
+ getAllOn = true;
+ QString lastDb, db, match;
+
+ QStringList::const_iterator it;
+ for (it = matches.begin(); it != matches.end(); ++it) {
+ db = (*it).section(' ', 0, 0);
+
+ if (db != lastDb) {
+ numDb++;
+ if (top) {
+ top->setOpen(initialOpen);
+ top = new MatchViewItem(w_list, top, db);
+ } else
+ top = new MatchViewItem(w_list, db);
+ top->setExpandable(true);
+ lastDb = db;
+ }
+
+ if (top)
+ top->subEntrys.append(*it);
+ }
+
+ if ((numDb == 1)||(initialOpen))
+ top->setOpen(true);
+ }
+
+ w_list->setUpdatesEnabled(true);
+ w_list->repaint();
+ w_list->setFocus();
+}
+
+
+// construct the right-mouse-button-popup-menu on demand
+void MatchView::buildPopupMenu(QListViewItem *i, const QPoint &_point, int)
+{
+ rightBtnMenu->clear();
+
+ if ((i!=0L)&&(i->isExpandable()||i->parent())) {
+ popupCurrent = (MatchViewItem *)(i);
+ rightBtnMenu->insertItem(i18n("&Get"),this,SLOT(popupGetCurrent()));
+ if (!i->isExpandable()) { // toplevel item -> only "get"
+ rightBtnMenu->insertItem(i18n("&Match"),this,SLOT(popupMatchCurrent()));
+ rightBtnMenu->insertItem(i18n("&Define"),this,SLOT(popupDefineCurrent()));
+ }
+ rightBtnMenu->insertSeparator();
+ }
+
+ kapp->clipboard()->setSelectionMode(false);
+ QString text = kapp->clipboard()->text();
+ if (text.isEmpty()) {
+ kapp->clipboard()->setSelectionMode(true);
+ text = kapp->clipboard()->text();
+ }
+ if (!text.isEmpty()) {
+ popupClip = kapp->clipboard()->text();
+ rightBtnMenu->insertItem(i18n("Match &Clipboard Content"),this,SLOT(popupMatchClip()));
+ rightBtnMenu->insertItem(SmallIcon("define_clip"),i18n("D&efine Clipboard Content"),this,SLOT(popupDefineClip()));
+ rightBtnMenu->insertSeparator();
+ }
+
+ int ID = rightBtnMenu->insertItem(i18n("Get &Selected"),this,SLOT(getSelected()));
+ rightBtnMenu->setItemEnabled(ID,getOn);
+ ID = rightBtnMenu->insertItem(i18n("Get &All"),this,SLOT(getAll()));
+ rightBtnMenu->setItemEnabled(ID,getAllOn);
+
+ if (w_list->childCount()) {
+ rightBtnMenu->insertSeparator();
+ rightBtnMenu->insertItem(i18n("E&xpand List"),this,SLOT(expandList()));
+ rightBtnMenu->insertItem(i18n("C&ollapse List"),this,SLOT(collapseList()));
+ }
+
+ rightBtnMenu->popup(_point);
+}
+
+
+void MatchView::popupGetCurrent()
+{
+ getOneItem(popupCurrent);
+}
+
+
+void MatchView::popupDefineCurrent()
+{
+ emit(defineRequested(popupCurrent->text(0)));
+}
+
+
+void MatchView::popupMatchCurrent()
+{
+ emit(matchRequested(popupCurrent->text(0)));
+}
+
+
+void MatchView::popupDefineClip()
+{
+ emit(defineRequested(popupClip));
+}
+
+
+void MatchView::popupMatchClip()
+{
+ emit(matchRequested(popupClip));
+}
+
+
+void MatchView::expandList()
+{
+ QListViewItem *top = w_list->firstChild();
+
+ while (top) {
+ w_list->setOpen(top,true);
+ top = top->nextSibling();
+ }
+}
+
+
+void MatchView::collapseList()
+{
+ w_list->setCurrentItem(w_list->firstChild());
+ QListViewItem *top = w_list->firstChild();
+
+ while (top) {
+ w_list->setOpen(top,false);
+ top = top->nextSibling();
+ }
+}
+
+//--------------------------------
+
+#include "matchview.moc"
diff --git a/kdict/matchview.h b/kdict/matchview.h
new file mode 100644
index 00000000..f619820e
--- /dev/null
+++ b/kdict/matchview.h
@@ -0,0 +1,105 @@
+/* -------------------------------------------------------------
+
+ matchview.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ MatchView This widget contains the list of matching definitions
+
+ ------------------------------------------------------------- */
+
+
+#ifndef _MATCHVIEW_H_
+#define _MATCHVIEW_H_
+
+#include <qlistview.h>
+class KPopupMenu;
+
+
+//********* MatchViewItem ********************************************
+
+class MatchViewItem : public QListViewItem
+{
+
+public:
+
+ MatchViewItem(QListView *view,const QString &text);
+ MatchViewItem(QListView *view,QListViewItem *after,const QString &text);
+ MatchViewItem(QListViewItem *item,const QString &text,const QString &commandStr);
+ MatchViewItem(QListViewItem *item,QListViewItem *after,const QString &text,const QString &commandStr);
+ ~MatchViewItem();
+
+ void setOpen(bool o);
+ void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment);
+
+ QString command;
+ QStringList subEntrys;
+};
+
+
+//********* MatchView ******************************************
+
+
+class MatchView : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ MatchView(QWidget *parent=0,const char *name=0);
+ ~MatchView();
+
+ void updateStrategyCombo();
+ bool selectStrategy(const QString &strategy) const;
+ void match(const QString &query);
+
+signals:
+
+ void defineRequested(const QString &query);
+ void matchRequested(const QString &query);
+ void clipboardRequested();
+ void windowClosed();
+
+protected:
+
+ void closeEvent ( QCloseEvent * e );
+
+private slots:
+
+ void strategySelected(int num);
+ void enableGetButton();
+ void mouseButtonPressed(int, QListViewItem *, const QPoint &, int);
+ void returnPressed(QListViewItem *i);
+ void getOneItem(QListViewItem *i);
+ void getSelected();
+ void getAll();
+ void doGet(QStringList &defines);
+ void newList(const QStringList &matches);
+ void buildPopupMenu(QListViewItem *, const QPoint &, int);
+ void popupGetCurrent();
+ void popupDefineCurrent();
+ void popupMatchCurrent();
+ void popupDefineClip();
+ void popupMatchClip();
+ void expandList();
+ void collapseList();
+
+private:
+
+ QComboBox *w_strat;
+ QListView *w_list;
+ QPushButton *w_get,*w_getAll;
+
+ bool getOn, getAllOn;
+
+ KPopupMenu *rightBtnMenu;
+ MatchViewItem *popupCurrent;
+ QString popupClip; // needed for rightbtn-popup menu
+};
+
+#endif
diff --git a/kdict/options.cpp b/kdict/options.cpp
new file mode 100644
index 00000000..a157fbf5
--- /dev/null
+++ b/kdict/options.cpp
@@ -0,0 +1,947 @@
+/* -------------------------------------------------------------
+
+ options.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ GlobalData manages all global data of Kdict
+
+ OptionsDialog the "Preferences" dialog
+
+ DbSetsDialog dialog for editing the user defined database sets
+
+ ------------------------------------------------------------- */
+
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qbuttongroup.h>
+#include <qpainter.h>
+
+#include <kcolordialog.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <knumvalidator.h>
+#include <knuminput.h>
+#include <klineedit.h>
+#include <kcharsets.h>
+#include <kfontdialog.h>
+#include <kiconloader.h>
+
+#include "options.h"
+
+
+//********* DictOptions ******************************************
+
+
+void GlobalData::read()
+{
+ KConfig *config=KGlobal::config();
+
+ // general...
+ config->setGroup("General");
+ defineClipboard = config->readBoolEntry("Lookup_Clipboard",false);
+ headLayout = config->readNumEntry("Heading_Layout",0);
+ if ((headLayout > 2)||(headLayout < 0))
+ headLayout = 0;
+ saveHistory = config->readBoolEntry("Save_History",true);
+ maxHistEntrys = config->readNumEntry("Max_History_Entrys",500);
+ if ((maxHistEntrys < 10)||(maxHistEntrys >5000))
+ maxHistEntrys = 200;
+ maxBrowseListEntrys = config->readNumEntry("Max_Browse_Entrys",15);
+ if ((maxBrowseListEntrys < 1)||(maxBrowseListEntrys > 50))
+ maxBrowseListEntrys = 15;
+ maxDefinitions = config->readNumEntry("Max_Definitions",2000);
+ if ((maxDefinitions < 100)||(maxDefinitions > 10000))
+ maxDefinitions = 2000;
+
+ //colors
+ config->setGroup("Colors");
+ useCustomColors=config->readBoolEntry("customColors", false);
+
+ QColor defCol=KGlobalSettings::textColor();
+ c_olors[Ctext]=config->readColorEntry("textColor",&defCol);
+ c_olorNames[Ctext]=i18n("Text");
+
+ defCol=KGlobalSettings::baseColor();
+ c_olors[Cbackground]=config->readColorEntry("backgroundColor",&defCol);
+ c_olorNames[Cbackground]=i18n("Background");
+
+ defCol=KGlobalSettings::highlightedTextColor();
+ c_olors[CheadingsText]=config->readColorEntry("headingsTextColor",&defCol);
+ c_olorNames[CheadingsText]=i18n("Heading Text");
+
+ defCol=KGlobalSettings::highlightColor();
+ c_olors[CheadingsBackground]=config->readColorEntry("headingsBackgroundColor",&defCol);
+ c_olorNames[CheadingsBackground]=i18n("Heading Background");
+
+ defCol=KGlobalSettings::linkColor();
+ c_olors[Clinks]=config->readColorEntry("linksColor",&defCol);
+ c_olorNames[Clinks]=i18n("Link");
+
+ defCol=KGlobalSettings::visitedLinkColor();
+ c_olors[CvisitedLinks]=config->readColorEntry("linksColor",&defCol);
+ c_olorNames[CvisitedLinks]=i18n("Followed Link");
+
+ //fonts
+ config->setGroup("Fonts");
+ useCustomFonts=config->readBoolEntry("customFonts", false);
+
+ QFont defFont=KGlobalSettings::generalFont();
+ f_onts[Ftext]=config->readFontEntry("textFont",&defFont);
+ f_ontNames[Ftext]=i18n("Text");
+
+ defFont.setBold( true );
+ defFont.setPointSize(defFont.pointSize()+2);
+ f_onts[Fheadings]=config->readFontEntry("headingsFont",&defFont);
+ f_ontNames[Fheadings]=i18n("Headings");
+
+ // geometry...
+ config->setGroup("Geometry");
+ QSize invalid(-1,-1);
+ optSize = config->readSizeEntry("Opt_Size",&invalid);
+ setsSize = config->readSizeEntry("Sets_Size",&invalid);
+ matchSize = config->readSizeEntry("Match_Size",&invalid);
+ showMatchList = config->readBoolEntry("Show_MatchList",false);
+ splitterSizes = config->readIntListEntry("Splitter_Sizes");
+
+ config->setGroup("Query Combo");
+ queryComboCompletionMode = (KGlobalSettings::Completion)config->readNumEntry("Completion_mode",
+ KGlobalSettings::completionMode());
+
+ config->setGroup("Query_History");
+ queryHistory = config->readListEntry("History");
+
+ config->setGroup("DictServer");
+ server = config->readEntry("Server", "dict.org");
+ port = config->readNumEntry("Port", 2628);
+ if (port < 0)
+ port = 2628;
+ timeout = config->readNumEntry("Timeout",60);
+ if (timeout < 0)
+ timeout = 60;
+ pipeSize = config->readNumEntry("Pipe_Size",256);
+ if (pipeSize < 0)
+ pipeSize = 256;
+ idleHold = config->readNumEntry("Idle_Hold",30);
+ if (idleHold < 0)
+ idleHold = 30;
+ encoding=config->readEntry("encoding", "utf8");
+ authEnabled = config->readBoolEntry("Auth_Enabled",false);
+ user = config->readEntry("User");
+ secret = encryptStr(config->readEntry("Secret"));
+ serverDatabases = config->readListEntry("Server_Databases");
+ currentDatabase = config->readNumEntry("Current_Database",0);
+ strategies = config->readListEntry("Strategies");
+ if (strategies.isEmpty()) {
+ strategies.append(i18n("Spell Check"));
+ strategies.append(i18n("Exact"));
+ strategies.append(i18n("Prefix"));
+ } else {
+ strategies.remove(strategies.begin());
+ strategies.prepend(i18n("Spell Check"));
+ }
+
+ currentStrategy = config->readNumEntry("Current_Strategy",0);
+ if (currentStrategy >= strategies.count())
+ currentStrategy = 0;
+
+ config->setGroup("Database_Sets");
+ databaseSets.setAutoDelete(true);
+ int num = config->readNumEntry("Num_Sets",0);
+ QStringList* temp;
+ QString strNum;
+ while (num > 0) {
+ temp = new QStringList();
+ strNum.setNum(num);
+ *temp = config->readListEntry(strNum);
+ if (!temp->isEmpty()) {
+ databaseSets.prepend(temp);
+ num--;
+ } else {
+ delete temp;
+ num = 0; // stop reading...
+ }
+ }
+ databases = serverDatabases;
+ for (int i = databaseSets.count()-1;i>=0;i--)
+ databases.prepend(databaseSets.at(i)->first());
+ databases.prepend(i18n("All Databases"));
+ if (currentDatabase >= databases.count())
+ currentDatabase = 0;
+}
+
+
+void GlobalData::write()
+{
+ KConfig *config=KGlobal::config();
+
+ config->setGroup("General");
+ config->writeEntry("Lookup_Clipboard",defineClipboard);
+ config->writeEntry("Heading_Layout",headLayout);
+ config->writeEntry("Save_History",saveHistory);
+ config->writeEntry("Max_History_Entrys",maxHistEntrys);
+ config->writeEntry("Max_Browse_Entrys",maxBrowseListEntrys);
+ config->writeEntry("Max_Definitions",maxDefinitions);
+
+ config->setGroup("Colors");
+ config->writeEntry("customColors",useCustomColors);
+ config->writeEntry("textColor", c_olors[Ctext]);
+ config->writeEntry("backgroundColor", c_olors[Cbackground]);
+ config->writeEntry("headingsTextColor", c_olors[CheadingsText]);
+ config->writeEntry("headingsBackgroundColor", c_olors[CheadingsBackground]);
+ config->writeEntry("linksColor", c_olors[Clinks]);
+ config->writeEntry("visitedLinksColor", c_olors[CvisitedLinks]);
+
+ config->setGroup("Fonts");
+ config->writeEntry("customFonts", useCustomFonts);
+ config->writeEntry("textFont", f_onts[Ftext]);
+ config->writeEntry("headingsFont", f_onts[Fheadings]);
+
+ config->setGroup("Geometry");
+ config->writeEntry("Opt_Size",optSize);
+ config->writeEntry("Sets_Size",setsSize);
+ config->writeEntry("Match_Size",matchSize);
+ config->writeEntry("Show_MatchList",showMatchList);
+ config->writeEntry("Splitter_Sizes",splitterSizes);
+
+ config->setGroup("Query Combo");
+ config->writeEntry("Completion_mode", (int)queryComboCompletionMode);
+
+ config->setGroup("Query_History");
+ QStringList copy;
+ if (saveHistory)
+ copy = queryHistory;
+ config->writeEntry("History",copy);
+
+ config->setGroup("DictServer");
+ config->writeEntry("Server", server);
+ config->writeEntry("Port", port);
+ config->writeEntry("Timeout",timeout);
+ config->writeEntry("Pipe_Size",pipeSize);
+ config->writeEntry("Idle_Hold",idleHold);
+ config->writeEntry("encoding", encoding);
+ config->writeEntry("Auth_Enabled",authEnabled);
+ config->writeEntry("User", user);
+ config->writeEntry("Secret", encryptStr(secret));
+ config->writeEntry("Server_Databases",serverDatabases);
+ config->writeEntry("Current_Database",currentDatabase);
+ config->writeEntry("Strategies",strategies);
+ config->writeEntry("Current_Strategy",currentStrategy);
+
+ config->setGroup("Database_Sets");
+ config->writeEntry("Num_Sets",databaseSets.count());
+ QString strNum;
+ for (unsigned int i = 0;i<databaseSets.count();i++)
+ config->writeEntry(strNum.setNum(i+1),*databaseSets.at(i));
+}
+
+
+QColor GlobalData::defaultColor(int i)
+{
+ switch(i) {
+ case Ctext:
+ return KGlobalSettings::textColor();
+ break;
+
+ case Cbackground:
+ return KGlobalSettings::baseColor();
+ break;
+
+ case CheadingsText:
+ return KGlobalSettings::highlightedTextColor();
+ break;
+
+ case CheadingsBackground:
+ return KGlobalSettings::highlightColor();
+ break;
+
+ case Clinks:
+ return KGlobalSettings::linkColor();
+ break;
+
+ case CvisitedLinks:
+ return KGlobalSettings::visitedLinkColor();
+ break;
+
+ }
+
+ return KGlobalSettings::baseColor();
+}
+
+
+QColor GlobalData::textColor()
+{
+ if(useCustomColors)
+ return c_olors[Ctext];
+ else
+ return defaultColor(Ctext);
+}
+
+
+QColor GlobalData::backgroundColor()
+{
+ if(useCustomColors)
+ return c_olors[Cbackground];
+ else
+ return defaultColor(Cbackground);
+}
+
+
+QColor GlobalData::headingsTextColor()
+{
+ if(useCustomColors)
+ return c_olors[CheadingsText];
+ else
+ return defaultColor(CheadingsText);
+}
+
+
+QColor GlobalData::headingsBackgroundColor()
+{
+ if(useCustomColors)
+ return c_olors[CheadingsBackground];
+ else
+ return defaultColor(CheadingsBackground);
+}
+
+
+QColor GlobalData::linksColor()
+{
+ if(useCustomColors)
+ return c_olors[Clinks];
+ else
+ return defaultColor(Clinks);
+}
+
+
+QColor GlobalData::visitedLinksColor()
+{
+ if(useCustomColors)
+ return c_olors[CvisitedLinks];
+ else
+ return defaultColor(CvisitedLinks);
+}
+
+
+QFont GlobalData::defaultFont(int i)
+{
+ QFont font = KGlobalSettings::generalFont();
+
+ if (font.pointSize() < 5)
+ font.setPointSize(12);
+
+ if (i==Fheadings)
+ font.setPointSize(font.pointSize()+5);
+
+ return font;
+}
+
+
+QFont GlobalData::textFont()
+{
+ if(useCustomFonts)
+ return f_onts[Ftext];
+ else
+ return defaultFont(Ftext);
+}
+
+
+QFont GlobalData::headingsFont()
+{
+ if(useCustomFonts)
+ return f_onts[Fheadings];
+ else
+ return defaultFont(Fheadings);
+}
+
+
+// simple password scrambling...
+QString GlobalData::encryptStr(const QString& aStr)
+{
+ uint i,val,len = aStr.length();
+ QString result;
+
+ for (i=0; i<len; i++)
+ {
+ val = aStr[i] - ' ';
+ val = (255-' ') - val;
+ result += (char)(val + ' ');
+ }
+
+ return result;
+}
+
+
+//********* OptionsDialog::DialogListBox *****************************
+
+
+OptionsDialog::DialogListBox::DialogListBox(bool alwaysIgnore, QWidget * parent, const char * name)
+ : QListBox(parent, name), a_lwaysIgnore(alwaysIgnore)
+{
+}
+
+
+OptionsDialog::DialogListBox::~DialogListBox()
+{
+}
+
+
+void OptionsDialog::DialogListBox::keyPressEvent(QKeyEvent *e)
+{
+ if ((a_lwaysIgnore || !(hasFocus()&&isVisible()))&&((e->key()==Key_Enter)||(e->key()==Key_Return)))
+ e->ignore();
+ else
+ QListBox::keyPressEvent(e);
+}
+
+
+//********* OptionsDialog::ColorListItem *****************************
+
+
+OptionsDialog::ColorListItem::ColorListItem( const QString &text, const QColor &color )
+ : QListBoxText(text), mColor( color )
+{
+}
+
+
+OptionsDialog::ColorListItem::~ColorListItem()
+{
+}
+
+
+void OptionsDialog::ColorListItem::paint( QPainter *p )
+{
+ QFontMetrics fm = p->fontMetrics();
+ int h = fm.height();
+
+ p->drawText( 30+3*2, fm.ascent() + fm.leading()/2, text() );
+
+ p->setPen( Qt::black );
+ p->drawRect( 3, 1, 30, h-1 );
+ p->fillRect( 4, 2, 28, h-3, mColor );
+}
+
+
+int OptionsDialog::ColorListItem::height(const QListBox *lb ) const
+{
+ return( lb->fontMetrics().lineSpacing()+1 );
+}
+
+
+int OptionsDialog::ColorListItem::width(const QListBox *lb ) const
+{
+ return( 30 + lb->fontMetrics().width( text() ) + 6 );
+}
+
+
+//********* OptionsDialog::FontListItem *****************************
+
+
+OptionsDialog::FontListItem::FontListItem( const QString &name, const QFont &font )
+ : QListBoxText(name), f_ont(font)
+{
+ fontInfo = QString("[%1 %2]").arg(f_ont.family()).arg(f_ont.pointSize());
+}
+
+
+OptionsDialog::FontListItem::~FontListItem()
+{
+}
+
+
+void OptionsDialog::FontListItem::setFont(const QFont &font)
+{
+ f_ont = font;
+ fontInfo = QString("[%1 %2]").arg(f_ont.family()).arg(f_ont.pointSize());
+}
+
+
+void OptionsDialog::FontListItem::paint( QPainter *p )
+{
+ QFont fnt = p->font();
+ fnt.setWeight(QFont::Bold);
+ p->setFont(fnt);
+ int fontInfoWidth = p->fontMetrics().width(fontInfo);
+ int h = p->fontMetrics().ascent() + p->fontMetrics().leading()/2;
+ p->drawText(2, h, fontInfo );
+ fnt.setWeight(QFont::Normal);
+ p->setFont(fnt);
+ p->drawText(5 + fontInfoWidth, h, text() );
+}
+
+
+int OptionsDialog::FontListItem::width(const QListBox *lb ) const
+{
+ return( lb->fontMetrics().width(fontInfo) + lb->fontMetrics().width(text()) + 20 );
+}
+
+
+//********* OptionsDialog ******************************************
+
+
+OptionsDialog::OptionsDialog(QWidget *parent, const char *name)
+ : KDialogBase(IconList, i18n("Configure"), Help|Default|Ok|Apply|Cancel, Ok, parent, name, false, true)
+{
+
+ //******** Server ************************************
+ serverTab = addPage(i18n("Server"),i18n("DICT Server Configuration"), BarIcon("network", KIcon::SizeMedium ));
+ QGridLayout* grid = new QGridLayout(serverTab,10,3,0,spacingHint());
+
+ w_server = new KLineEdit(serverTab);
+ w_server->setText(global->server);
+ QLabel *l = new QLabel(w_server, i18n("Host&name:"), serverTab);
+ grid->addWidget(l,0,0);
+ grid->addMultiCellWidget(w_server,0,0,1,2);
+ connect( w_server, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) );
+
+ w_port = new KLineEdit(serverTab);
+ w_port->setValidator(new KIntValidator(0,65536,this));
+ w_port->setText(QString::number(global->port));
+ l = new QLabel(w_port, i18n("&Port:"), serverTab);
+ grid->addWidget(l,1,0);
+ grid->addWidget(w_port,1,1);
+ connect( w_port, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) );
+
+ w_idleHold = new KIntSpinBox(0,300,5,0,10,serverTab);
+ w_idleHold->setSuffix(i18n(" sec"));
+ w_idleHold->setValue(global->idleHold);
+ l = new QLabel(w_idleHold, i18n("Hold conn&ection for:"), serverTab);
+ grid->addWidget(l,2,0);
+ grid->addWidget(w_idleHold,2,1);
+ connect( w_idleHold, SIGNAL( valueChanged(int) ), this, SLOT( slotChanged() ) );
+
+ w_timeout = new KIntSpinBox(5,600,5,5,10,serverTab);
+ w_timeout->setSuffix(i18n(" sec"));
+ w_timeout->setValue(global->timeout);
+ l = new QLabel(w_timeout, i18n("T&imeout:"), serverTab);
+ grid->addWidget(l,3,0);
+ grid->addWidget(w_timeout,3,1);
+ connect( w_timeout, SIGNAL( valueChanged(int) ), this, SLOT( slotChanged() ) );
+
+ w_pipesize = new KIntSpinBox(100,5000,2,2,10,serverTab);
+ w_pipesize->setSuffix(i18n(" bytes"));
+ w_pipesize->setValue(global->pipeSize);
+ l = new QLabel(w_pipesize, i18n("Command &buffer:"), serverTab);
+ grid->addWidget(l,4,0);
+ grid->addWidget(w_pipesize,4,1);
+ connect( w_pipesize, SIGNAL( valueChanged(int) ), this, SLOT( slotChanged() ) );
+
+ QStringList encodingNames = KGlobal::charsets()->descriptiveEncodingNames();
+ int i=0,x=0;
+ for ( QStringList::Iterator it = encodingNames.begin(); it != encodingNames.end(); ++it ) {
+ if (KGlobal::charsets()->encodingForName(*it)==global->encoding) {
+ x = i;
+ break;
+ }
+ i++;
+ }
+ w_encoding = new QComboBox(serverTab);
+ w_encoding->insertStringList(encodingNames);
+ w_encoding->setCurrentItem(x);
+ l = new QLabel(w_encoding, i18n("Encod&ing:"), serverTab);
+ grid->addWidget(l,5,0);
+ grid->addMultiCellWidget(w_encoding,5,5,1,2);
+ connect( w_encoding, SIGNAL( activated(int) ), this, SLOT( slotChanged() ) );
+
+ w_auth = new QCheckBox(i18n("Server requires a&uthentication"),serverTab);
+ w_auth->setChecked(global->authEnabled);
+ grid->addMultiCellWidget(w_auth,6,6,0,2);
+ connect( w_auth, SIGNAL( toggled(bool) ), this, SLOT( slotChanged() ) );
+ connect(w_auth,SIGNAL(toggled(bool)),SLOT(slotAuthRequiredToggled(bool)));
+
+ w_user = new KLineEdit(serverTab);
+ w_user->setText(global->user);
+ l_user = new QLabel(w_user, i18n("U&ser:"),serverTab);
+ grid->addWidget(l_user,7,0);
+ grid->addMultiCellWidget(w_user,7,7,1,2);
+ connect( w_user, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) );
+
+ w_secret = new KLineEdit(serverTab);
+ w_secret->setEchoMode(QLineEdit::Password);
+ w_secret->setText(global->secret);
+ l_secret = new QLabel(w_secret, i18n("Pass&word:"), serverTab);
+ grid->addWidget(l_secret,8,0);
+ grid->addMultiCellWidget(w_secret,8,8,1,2);
+ connect( w_secret, SIGNAL( textChanged ( const QString & ) ), this, SLOT( slotChanged() ) );
+
+ slotAuthRequiredToggled( w_auth->isChecked() );
+
+ grid->setColStretch(1,2);
+ grid->setColStretch(2,2);
+
+ //************ Appearance ***************************
+ appTab = addPage(i18n("Appearance"),i18n("Customize Visual Appearance"), BarIcon("appearance", KIcon::SizeMedium ));
+
+ QGridLayout *topL=new QGridLayout(appTab, 8, 3, 0, spacingHint());
+
+ //color-list
+ c_List = new DialogListBox(false, appTab);
+ topL->addMultiCellWidget(c_List,1,3,0,1);
+ connect(c_List, SIGNAL(selected(QListBoxItem*)),SLOT(slotColItemSelected(QListBoxItem*)));
+ connect(c_List, SIGNAL(selectionChanged()), SLOT(slotColSelectionChanged()));
+
+ c_olorCB = new QCheckBox(i18n("&Use custom colors"),appTab);
+ topL->addWidget(c_olorCB,0,0);
+ connect(c_olorCB, SIGNAL(toggled(bool)), this, SLOT(slotColCheckBoxToggled(bool)));
+ connect(c_olorCB, SIGNAL(toggled(bool) ), this, SLOT( slotChanged()));
+
+ c_olChngBtn=new QPushButton(i18n("Cha&nge..."), appTab);
+ connect(c_olChngBtn, SIGNAL(clicked()), SLOT(slotColChangeBtnClicked()));
+ topL->addWidget(c_olChngBtn,1,2);
+
+ c_olDefBtn=new QPushButton(i18n("Default&s"), appTab);
+ connect(c_olDefBtn, SIGNAL(clicked()), SLOT(slotColDefaultBtnClicked()));
+ topL->addWidget(c_olDefBtn,2,2);
+ connect(c_olDefBtn, SIGNAL(clicked()), SLOT(slotChanged()));
+
+ //font-list
+ f_List = new DialogListBox(false, appTab);
+ topL->addMultiCellWidget(f_List,5,7,0,1);
+ connect(f_List, SIGNAL(selected(QListBoxItem*)),SLOT(slotFontItemSelected(QListBoxItem*)));
+ connect(f_List, SIGNAL(selectionChanged()),SLOT(slotFontSelectionChanged()));
+
+ f_ontCB = new QCheckBox(i18n("Use custom &fonts"),appTab);
+ topL->addWidget(f_ontCB,4,0);
+ connect(f_ontCB, SIGNAL(toggled(bool)), SLOT(slotFontCheckBoxToggled(bool)));
+ connect(f_ontCB, SIGNAL(toggled(bool)), SLOT(slotChanged()));
+
+ f_ntChngBtn=new QPushButton(i18n("Chang&e..."), appTab);
+ connect(f_ntChngBtn, SIGNAL(clicked()), SLOT(slotFontChangeBtnClicked()));
+ topL->addWidget(f_ntChngBtn,5,2);
+
+ f_ntDefBtn=new QPushButton(i18n("Defaul&ts"), appTab);
+ connect(f_ntDefBtn, SIGNAL(clicked()), SLOT(slotFontDefaultBtnClicked()));
+ topL->addWidget(f_ntDefBtn,6,2);
+ connect(f_ntDefBtn, SIGNAL(clicked()), SLOT(slotChanged()));
+
+ topL->setColStretch(1,2);
+ topL->setColStretch(2,0);
+ topL->setRowStretch(3,1);
+ topL->setRowStretch(7,1);
+ topL->setResizeMode(QLayout::Minimum);
+
+ //init
+ c_olorCB->setChecked(global->useCustomColors);
+ slotColCheckBoxToggled(global->useCustomColors);
+ for(int i=0; i<global->colorCount(); i++)
+ c_List->insertItem(new ColorListItem(global->colorName(i), global->color(i)));
+
+ f_ontCB->setChecked(global->useCustomFonts);
+ slotFontCheckBoxToggled(global->useCustomFonts);
+ for(int i=0; i<global->fontCount(); i++)
+ f_List->insertItem(new FontListItem(global->fontName(i), global->font(i)));
+
+ //************ Layout ***************************
+ layoutTab = addPage(i18n("Layout"),i18n("Customize Output Format"), BarIcon("text_left", KIcon::SizeMedium ));
+
+ QVBoxLayout *vbox = new QVBoxLayout(layoutTab, 0, spacingHint());
+
+ QButtonGroup *bGroup = new QButtonGroup(i18n("Headings"),layoutTab);
+ QVBoxLayout *bvbox = new QVBoxLayout(bGroup,8,5);
+
+ bvbox->addSpacing(fontMetrics().lineSpacing()-4);
+ w_layout[0] = new QRadioButton(i18n("O&ne heading for each database"),bGroup);
+ w_layout[0]->setChecked(global->headLayout == 0);
+ bvbox->addWidget(w_layout[0],1);
+ w_layout[1] = new QRadioButton(i18n("A&s above, with separators between the definitions"),bGroup);
+ w_layout[1]->setChecked(global->headLayout == 1);
+ bvbox->addWidget(w_layout[1],1);
+ w_layout[2] = new QRadioButton(i18n("A separate heading for &each definition"),bGroup);
+ w_layout[2]->setChecked(global->headLayout == 2);
+ bvbox->addWidget(w_layout[2],1);
+ connect(w_layout[0], SIGNAL(toggled(bool)), SLOT(slotChanged()));
+ connect(w_layout[1], SIGNAL(toggled(bool)), SLOT(slotChanged()));
+ connect(w_layout[2], SIGNAL(toggled(bool)), SLOT(slotChanged()));
+
+ vbox->addWidget(bGroup,0);
+ vbox->addStretch(1);
+
+ //************ Other ***************************
+ otherTab = addPage(i18n("Miscellaneous"),i18n("Various Settings"), BarIcon("misc", KIcon::SizeMedium ));
+
+ vbox = new QVBoxLayout(otherTab, 0, spacingHint());
+
+ QGroupBox *group = new QGroupBox(i18n("Limits"),otherTab);
+
+ grid = new QGridLayout(group,4,2,8,5);
+ grid->addRowSpacing(0, fontMetrics().lineSpacing()-4);
+
+ w_MaxDefinitions = new KIntSpinBox(100,10000,100,100,10,group);
+ w_MaxDefinitions->setValue(global->maxDefinitions);
+ l = new QLabel(w_MaxDefinitions, i18n("De&finitions:"), group);
+ grid->addWidget(l,1,0);
+ grid->addWidget(w_MaxDefinitions,1,1);
+ connect(w_MaxDefinitions, SIGNAL(valueChanged(int)), SLOT(slotChanged()));
+
+ w_Maxbrowse = new KIntSpinBox(1,100,1,1,10,group);
+ w_Maxbrowse->setValue(global->maxBrowseListEntrys);
+ l = new QLabel(w_Maxbrowse, i18n("Cached &results:"), group);
+ grid->addWidget(l,2,0);
+ grid->addWidget(w_Maxbrowse,2,1);
+ connect(w_Maxbrowse, SIGNAL(valueChanged(int)), SLOT(slotChanged()));
+
+ w_Maxhist = new KIntSpinBox(10,5000,10,10,10,group);
+ w_Maxhist->setValue(global->maxHistEntrys);
+ l = new QLabel(w_Maxhist, i18n("Hi&story entries:"), group);
+ grid->addWidget(l,3,0);
+ grid->addWidget(w_Maxhist,3,1);
+ connect(w_Maxhist, SIGNAL(valueChanged(int)), SLOT(slotChanged()));
+
+ grid->setColStretch(1,1);
+
+ vbox->addWidget(group,0);
+
+ group = new QGroupBox(i18n("Other"),otherTab);
+
+ QVBoxLayout *vbox2 = new QVBoxLayout(group, 8, 5);
+
+ vbox2->addSpacing(fontMetrics().lineSpacing()-4);
+
+ w_Savehist = new QCheckBox(i18n("Sa&ve history on exit"),group);
+ w_Savehist->setChecked(global->saveHistory);
+ vbox2->addWidget(w_Savehist,0);
+ connect(w_Savehist, SIGNAL(toggled(bool)), SLOT(slotChanged()));
+
+ w_Clipboard = new QCheckBox(i18n("D&efine selected text on start"),group);
+ w_Clipboard->setChecked(global->defineClipboard);
+ vbox2->addWidget(w_Clipboard,1);
+ connect(w_Clipboard, SIGNAL(toggled(bool)), SLOT(slotChanged()));
+
+ vbox->addWidget(group,0);
+ vbox->addStretch(2);
+
+ setHelp("preferences");
+
+ if (global->optSize.isValid())
+ resize(global->optSize);
+ else
+ resize(300,200);
+ enableButton( Apply, false );
+ configChanged = false;
+}
+
+
+OptionsDialog::~OptionsDialog()
+{
+ global->optSize = size();
+}
+
+
+void OptionsDialog::slotApply()
+{
+ global->server = w_server->text();
+ global->port = w_port->text().toInt();
+ global->timeout = w_timeout->value();
+ global->idleHold = w_idleHold->value();
+ global->pipeSize = w_pipesize->value();
+ global->encoding = KGlobal::charsets()->encodingForName(w_encoding->currentText());
+ global->authEnabled = w_auth->isChecked();
+ global->user = w_user->text();
+ global->secret = w_secret->text();
+ global->useCustomColors=c_olorCB->isChecked();
+ for(int i=0; i<global->colorCount(); i++)
+ global->c_olors[i] = (static_cast<ColorListItem*>(c_List->item(i)))->color();
+
+ global->useCustomFonts=f_ontCB->isChecked();
+ for(int i=0; i<global->fontCount(); i++)
+ global->f_onts[i] = (static_cast<FontListItem*>(f_List->item(i)))->font();
+ if (w_layout[0]->isChecked())
+ global->headLayout = 0;
+ else
+ if (w_layout[1]->isChecked())
+ global->headLayout = 1;
+ else
+ global->headLayout = 2;
+ global->maxDefinitions = w_MaxDefinitions->value();
+ global->maxBrowseListEntrys = w_Maxbrowse->value();
+ global->maxHistEntrys = w_Maxhist->value();
+ global->defineClipboard = w_Clipboard->isChecked();
+ global->saveHistory = w_Savehist->isChecked();
+ emit(optionsChanged());
+ enableButton( Apply, false );
+ configChanged = false;
+}
+
+
+void OptionsDialog::slotOk()
+{
+ if( configChanged )
+ slotApply();
+ KDialogBase::slotOk();
+}
+
+
+void OptionsDialog::slotDefault()
+{
+ QStringList encodingNames;
+ int i=0,x=0;
+
+ switch(activePageIndex()) {
+ case 0:
+ w_server->setText("dict.org");
+ w_port->setText("2628");
+ w_idleHold->setValue(30);
+ w_timeout->setValue(60);
+ w_pipesize->setValue(256);
+ encodingNames = KGlobal::charsets()->descriptiveEncodingNames();
+ for ( QStringList::Iterator it = encodingNames.begin(); it != encodingNames.end(); ++it ) {
+ if (KGlobal::charsets()->encodingForName(*it)=="utf8")
+ x = i;
+ i++;
+ }
+ w_encoding->setCurrentItem(x);
+ w_auth->setChecked(false);
+ w_user->clear();
+ w_user->setEnabled(false);
+ w_secret->clear();
+ w_secret->setEnabled(false);
+ break;
+ case 1:
+ c_olorCB->setChecked(false);
+ slotColCheckBoxToggled(false);
+ slotColDefaultBtnClicked();
+ f_ontCB->setChecked(false);
+ slotFontCheckBoxToggled(false);
+ slotFontDefaultBtnClicked();
+ break;
+ case 2:
+ w_layout[0]->setChecked(true);
+ break;
+ case 3:
+ w_MaxDefinitions->setValue(2000);
+ w_Maxbrowse->setValue(15);
+ w_Maxhist->setValue(500);
+ w_Savehist->setChecked(true);
+ w_Clipboard->setChecked(false);
+ }
+}
+
+
+void OptionsDialog::slotAuthRequiredToggled( bool enable )
+{
+ l_user->setEnabled( enable );
+ l_secret->setEnabled( enable );
+ w_user->setEnabled( enable );
+ w_secret->setEnabled( enable );
+}
+
+
+void OptionsDialog::slotColCheckBoxToggled(bool b)
+{
+ c_List->setEnabled(b);
+ c_olDefBtn->setEnabled(b);
+ c_olChngBtn->setEnabled(b && (c_List->currentItem()!=-1));
+ if (b) c_List->setFocus();
+}
+
+
+// show color dialog for the entry
+void OptionsDialog::slotColItemSelected(QListBoxItem *it)
+{
+ if (it) {
+ ColorListItem *colorItem = static_cast<ColorListItem*>(it);
+ QColor col = colorItem->color();
+ int result = KColorDialog::getColor(col,this);
+
+ if (result == KColorDialog::Accepted) {
+ colorItem->setColor(col);
+ c_List->triggerUpdate(false);
+ slotChanged();
+ }
+ }
+}
+
+
+void OptionsDialog::slotColDefaultBtnClicked()
+{
+ ColorListItem *colorItem;
+ for(int i=0; i < global->colorCount(); i++) {
+ colorItem=static_cast<ColorListItem*>(c_List->item(i));
+ colorItem->setColor(global->defaultColor(i));
+ }
+ c_List->triggerUpdate(true);
+ c_List->repaint(true);
+}
+
+
+void OptionsDialog::slotColChangeBtnClicked()
+{
+ if(c_List->currentItem()!=-1)
+ slotColItemSelected(c_List->item(c_List->currentItem()));
+}
+
+
+void OptionsDialog::slotColSelectionChanged()
+{
+ c_olChngBtn->setEnabled(c_List->currentItem()!=-1);
+}
+
+
+void OptionsDialog::slotFontCheckBoxToggled(bool b)
+{
+ f_List->setEnabled(b);
+ f_ntDefBtn->setEnabled(b);
+ f_ntChngBtn->setEnabled(b && (f_List->currentItem()!=-1));
+ if (b) f_List->setFocus();
+}
+
+
+// show font dialog for the entry
+void OptionsDialog::slotFontItemSelected(QListBoxItem *it)
+{
+ if (it) {
+ FontListItem *fontItem = static_cast<FontListItem*>(it);
+ QFont font = fontItem->font();
+ int result = KFontDialog::getFont(font,false,this);
+
+ if (result == KFontDialog::Accepted) {
+ fontItem->setFont(font);
+ f_List->triggerUpdate(false);
+ slotChanged();
+ }
+ }
+}
+
+
+void OptionsDialog::slotFontDefaultBtnClicked()
+{
+ FontListItem *fontItem;
+ for(int i=0; i < global->fontCount(); i++) {
+ fontItem=static_cast<FontListItem*>(f_List->item(i));
+ fontItem->setFont(global->defaultFont(i));
+ }
+ f_List->triggerUpdate(false);
+}
+
+
+void OptionsDialog::slotFontChangeBtnClicked()
+{
+ if(f_List->currentItem()!=-1)
+ slotFontItemSelected(f_List->item(f_List->currentItem()));
+}
+
+
+void OptionsDialog::slotFontSelectionChanged()
+{
+ f_ntChngBtn->setEnabled(f_List->currentItem()!=-1);
+}
+
+void OptionsDialog::slotChanged()
+{
+ enableButton( Apply, true );
+ configChanged = true;
+}
+
+
+//--------------------------------
+
+#include "options.moc"
diff --git a/kdict/options.h b/kdict/options.h
new file mode 100644
index 00000000..ecef7606
--- /dev/null
+++ b/kdict/options.h
@@ -0,0 +1,229 @@
+/* -------------------------------------------------------------
+
+ options.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ GlobalData manages all global data of Kdict
+ DialgoListBox a list box which ignores Enter, usefull for dialogs
+ OptionsDialog the "Preferences" dialog
+
+ ------------------------------------------------------------- */
+
+#ifndef _KDICT_OPTIONS_H_
+#define _KDICT_OPTIONS_H_
+
+#include <qlistbox.h>
+#include <kdialogbase.h>
+#include <kglobalsettings.h>
+
+class QLineEdit;
+class QCheckBox;
+class QComboBox;
+class QRadioButton;
+
+class KColorButton;
+class KLineEdit;
+class KIntSpinBox;
+
+
+//********* GlobalData ******************************************
+
+#define COL_CNT 6
+#define FNT_CNT 2
+
+class GlobalData
+{
+
+public:
+
+ enum ColorIndex { Ctext=0, Cbackground=1, CheadingsText=2, CheadingsBackground=3, Clinks=4, CvisitedLinks=5 };
+ enum FontIndex { Ftext=0, Fheadings=1 };
+
+ void read();
+ void write();
+
+ // colors...
+ const QColor& color(int i) { return c_olors[i]; }
+ const QString& colorName(int i) { return c_olorNames[i]; }
+ int colorCount() const { return COL_CNT; }
+ QColor defaultColor(int i);
+ bool useCustomColors;
+ QColor textColor();
+ QColor backgroundColor();
+ QColor headingsTextColor();
+ QColor headingsBackgroundColor();
+ QColor linksColor();
+ QColor visitedLinksColor();
+
+ // fonts...
+ const QFont& font(int i) { return f_onts[i]; }
+ const QString& fontName(int i) { return f_ontNames[i]; }
+ int fontCount() const { return FNT_CNT; }
+ QFont defaultFont(int);
+ bool useCustomFonts;
+ QFont textFont();
+ QFont headingsFont();
+
+ QString encryptStr(const QString& aStr);
+
+ bool defineClipboard; // define clipboard content on startup?
+
+ QSize optSize,setsSize,matchSize; // window geometry
+ bool showMatchList;
+ QValueList<int> splitterSizes;
+
+ KGlobalSettings::Completion queryComboCompletionMode;
+
+ QStringList queryHistory;
+ bool saveHistory; // save query history to disk on exit?
+ unsigned int maxHistEntrys, maxBrowseListEntrys, maxDefinitions;
+ int headLayout;
+
+ QString server; // network client...
+ int port,timeout,pipeSize,idleHold;
+ QString encoding;
+ bool authEnabled;
+ QString user, secret;
+ QStringList serverDatabases, databases, strategies;
+ QPtrList<QStringList> databaseSets;
+ unsigned int currentDatabase, currentStrategy;
+
+ QColor c_olors[COL_CNT];
+ QString c_olorNames[COL_CNT];
+ QFont f_onts[FNT_CNT];
+ QString f_ontNames[FNT_CNT];
+
+ QWidget *topLevel;
+};
+
+extern GlobalData *global;
+
+
+//********* OptionsDialog ******************************************
+
+
+class OptionsDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ OptionsDialog(QWidget *parent=0, const char *name=0);
+ ~OptionsDialog();
+
+ //===================================================================================
+
+ class DialogListBox : public QListBox {
+
+ public:
+ // alwaysIgnore==false: enter is ignored when the widget isn't visible/out of focus
+ DialogListBox(bool alwaysIgnore=false, QWidget * parent=0, const char * name=0);
+ ~DialogListBox();
+
+ protected:
+ void keyPressEvent( QKeyEvent *e );
+
+ bool a_lwaysIgnore;
+ };
+
+ //===================================================================================
+
+ class ColorListItem : public QListBoxText {
+
+ public:
+ ColorListItem( const QString &text, const QColor &color=Qt::black );
+ ~ColorListItem();
+ const QColor& color() { return mColor; }
+ void setColor( const QColor &color ) { mColor = color; }
+
+ protected:
+ virtual void paint( QPainter * );
+ virtual int height( const QListBox * ) const;
+ virtual int width( const QListBox * ) const;
+
+ private:
+ QColor mColor;
+ };
+
+ //===================================================================================
+
+ class FontListItem : public QListBoxText {
+
+ public:
+ FontListItem( const QString &name, const QFont & );
+ ~FontListItem();
+ const QFont& font() { return f_ont; }
+ void setFont( const QFont &);
+ protected:
+ virtual void paint( QPainter * );
+ virtual int width( const QListBox * ) const;
+
+ private:
+ QFont f_ont;
+ QString fontInfo;
+ };
+
+ //===================================================================================
+
+signals:
+
+ void optionsChanged();
+
+protected slots:
+ void slotApply();
+ void slotOk();
+ void slotDefault();
+ void slotChanged();
+
+ //server
+ void slotAuthRequiredToggled( bool );
+
+ //colors
+ void slotColCheckBoxToggled(bool b);
+ void slotColItemSelected(QListBoxItem *); // show color dialog for the entry
+ void slotColDefaultBtnClicked();
+ void slotColChangeBtnClicked();
+ void slotColSelectionChanged();
+
+ //fonts
+ void slotFontCheckBoxToggled(bool b);
+ void slotFontItemSelected(QListBoxItem *); // show font dialog for the entry
+ void slotFontDefaultBtnClicked();
+ void slotFontChangeBtnClicked();
+ void slotFontSelectionChanged();
+
+private:
+
+ QFrame *serverTab;
+ QLabel *l_user, *l_secret;
+ KLineEdit *w_server, *w_user, *w_secret, *w_port;
+ QComboBox *w_encoding;
+ QCheckBox *w_auth;
+ KIntSpinBox *w_idleHold,*w_timeout,*w_pipesize;
+
+ QFrame *appTab;
+ DialogListBox *c_List,
+ *f_List;
+ QCheckBox *c_olorCB,
+ *f_ontCB;
+ QPushButton *c_olDefBtn,
+ *c_olChngBtn,
+ *f_ntDefBtn,
+ *f_ntChngBtn;
+
+ QFrame *layoutTab;
+ QRadioButton *w_layout[3];
+
+ QFrame *otherTab;
+ QCheckBox *w_Clipboard, *w_Savehist;
+ KIntSpinBox *w_Maxhist, *w_Maxbrowse, *w_MaxDefinitions;
+ bool configChanged;
+};
+
+#endif
diff --git a/kdict/pics/Makefile.am b/kdict/pics/Makefile.am
new file mode 100644
index 00000000..dfb183ec
--- /dev/null
+++ b/kdict/pics/Makefile.am
@@ -0,0 +1,2 @@
+kdicticondir = $(kde_datadir)/kdict/icons
+kdicticon_ICON = define_clip query_erase
diff --git a/kdict/pics/cr16-action-define_clip.png b/kdict/pics/cr16-action-define_clip.png
new file mode 100644
index 00000000..dd83280b
--- /dev/null
+++ b/kdict/pics/cr16-action-define_clip.png
Binary files differ
diff --git a/kdict/pics/cr16-action-query_erase.png b/kdict/pics/cr16-action-query_erase.png
new file mode 100644
index 00000000..0fb00f91
--- /dev/null
+++ b/kdict/pics/cr16-action-query_erase.png
Binary files differ
diff --git a/kdict/pics/cr22-action-define_clip.png b/kdict/pics/cr22-action-define_clip.png
new file mode 100644
index 00000000..3ab1b0cc
--- /dev/null
+++ b/kdict/pics/cr22-action-define_clip.png
Binary files differ
diff --git a/kdict/pics/cr32-action-define_clip.png b/kdict/pics/cr32-action-define_clip.png
new file mode 100644
index 00000000..f0c56ca4
--- /dev/null
+++ b/kdict/pics/cr32-action-define_clip.png
Binary files differ
diff --git a/kdict/queryview.cpp b/kdict/queryview.cpp
new file mode 100644
index 00000000..a2674d68
--- /dev/null
+++ b/kdict/queryview.cpp
@@ -0,0 +1,618 @@
+/* -------------------------------------------------------------
+
+ queryview.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ BrowseData data structure used for caching definitions
+ DictHTMLPart handling of middle mouse button clicks
+ QueryView widget that displays the definitions
+
+ ------------------------------------------------------------- */
+
+#include <qclipboard.h>
+#include <qtimer.h>
+
+#include <kfiledialog.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+#include <kcursor.h>
+#include <kpopupmenu.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <khtml_events.h>
+#include <khtmlview.h>
+
+#include "actions.h"
+#include "options.h"
+#include "dict.h"
+#include "queryview.h"
+#include <kapplication.h>
+#include <kiconloader.h>
+
+
+//******** SaveHelper *******************************************
+
+QString SaveHelper::lastPath;
+
+SaveHelper::SaveHelper(const QString &saveName, const QString &filter, QWidget *parent)
+ : p_arent(parent), s_aveName(saveName), f_ilter(filter), file(0), tmpFile(0)
+{
+}
+
+
+SaveHelper::~SaveHelper()
+{
+ if (file) { // local filesystem, just close the file
+ delete file;
+ } else
+ if (tmpFile) { // network location, initiate transaction
+ tmpFile->close();
+ if (KIO::NetAccess::upload(tmpFile->name(),url, p_arent) == false)
+ KMessageBox::error(global->topLevel, i18n("Unable to save remote file."));
+ tmpFile->unlink(); // delete temp file
+ delete tmpFile;
+ }
+}
+
+
+QFile* SaveHelper::getFile(const QString &dialogTitle)
+{
+ url = KFileDialog::getSaveURL(lastPath+s_aveName,f_ilter,p_arent,dialogTitle);
+
+ if (url.isEmpty())
+ return 0;
+
+ lastPath = url.url(-1);
+ lastPath.truncate(lastPath.length()-url.fileName().length());
+
+ if (url.isLocalFile()) {
+ if (QFileInfo(url.path()).exists() &&
+ (KMessageBox::warningContinueCancel(global->topLevel,
+ i18n("A file named %1 already exists.\nDo you want to replace it?").arg(url.path()),
+ dialogTitle, i18n("&Replace")) != KMessageBox::Continue)) {
+ return 0;
+ }
+
+ file = new QFile(url.path());
+ if(!file->open(IO_WriteOnly)) {
+ KMessageBox::error(global->topLevel, i18n("Unable to save file."));
+ delete file;
+ file = 0;
+ }
+ return file;
+ } else {
+ tmpFile = new KTempFile();
+ if (tmpFile->status()!=0)
+ KMessageBox::error(global->topLevel, i18n("Unable to create temporary file.")); {
+ delete tmpFile;
+ tmpFile = 0;
+ return 0;
+ }
+ return tmpFile->file();
+ }
+}
+
+
+//**** BrowseData ****************************************************
+
+
+BrowseData::BrowseData(const QString &Nhtml, const QString &NqueryText)
+: html(Nhtml),queryText(NqueryText),xPos(0),yPos(0)
+{}
+
+
+//********* DictHTMLPart ******************************************
+
+DictHTMLPart::DictHTMLPart(QWidget *parentWidget, const char *widgetname)
+ : KHTMLPart(parentWidget,widgetname)
+{}
+
+
+DictHTMLPart::~DictHTMLPart()
+{}
+
+
+void DictHTMLPart::khtmlMouseReleaseEvent(khtml::MouseReleaseEvent *event)
+{
+ if (event->qmouseEvent()->button()==MidButton)
+ emit(middleButtonClicked());
+ else
+ KHTMLPart::khtmlMouseReleaseEvent(event);
+}
+
+
+//********* QueryView ******************************************
+
+
+QueryView::QueryView(QWidget *_parent)
+: QVBox( _parent), actBack(0L), actForward(0L), actQueryCombo(0L), browsePos(0), isRendering(false)
+{
+ browseList.setAutoDelete(true);
+
+ part=new DictHTMLPart(this);
+ part->setDNDEnabled(false);
+ part->setJScriptEnabled(false);
+ part->setJavaEnabled(false);
+ part->setURLCursor(KCursor::handCursor());
+ setFocusPolicy(QWidget::NoFocus);
+ connect(part, SIGNAL(completed()), SLOT(partCompleted()));
+ connect(part, SIGNAL(middleButtonClicked()), SLOT(middleButtonClicked()));
+ rightBtnMenu = new KPopupMenu(this);
+ connect(part,SIGNAL(popupMenu(const QString &, const QPoint &)),this,SLOT(buildPopupMenu(const QString &, const QPoint &)));
+ connect(part->browserExtension(),SIGNAL(openURLRequest(const KURL &,const KParts::URLArgs &)),
+ this,SLOT(slotURLRequest(const KURL &,const KParts::URLArgs &)));
+ connect(part->browserExtension(),SIGNAL(enableAction(const char *,bool)),this,SLOT(enableAction(const char *,bool)));
+ QTimer::singleShot( 0, this, SLOT(optionsChanged()) );
+ connect(interface,SIGNAL(resultReady(const QString &, const QString &)), SLOT(resultReady(const QString &, const QString &)));
+}
+
+
+QueryView::~QueryView()
+{}
+
+
+void QueryView::setActions(KToolBarPopupAction* NactBack, KToolBarPopupAction* NactForward, DictComboAction* NactQueryCombo)
+{
+ actBack = NactBack;
+ connect(actBack->popupMenu(),SIGNAL(activated(int)),SLOT(browseBack(int)));
+ actForward = NactForward;
+ connect(actForward->popupMenu(),SIGNAL(activated(int)),SLOT(browseForward(int)));
+ actQueryCombo = NactQueryCombo;
+}
+
+
+bool QueryView::browseBackPossible() const
+{
+ return (browsePos > 0)? true:false;
+}
+
+
+bool QueryView::browseForwardPossible() const
+{
+ return (browsePos+1 < browseList.count()) ? true:false;
+}
+
+
+void QueryView::optionsChanged()
+{
+ saveCurrentResultPos();
+
+ currentHTMLHeader = QString("<html><head><style type=\"text/css\">\n");
+ currentHTMLHeader += QString("body { background-color:%1; color:%2; }\n").arg(global->backgroundColor().name()).arg(global->textColor().name());
+ currentHTMLHeader += QString("a:link, a:active { color:%1; text-decoration:none; }\n").arg(global->linksColor().name());
+ currentHTMLHeader += QString("a:visited { color:%1; text-decoration:none; }\n").arg(global->visitedLinksColor().name());
+ currentHTMLHeader += QString("a:hover { color:%1; text-decoration:underline; }\n").arg(global->linksColor().name());
+ currentHTMLHeader += QString("p.heading { margin-left:0mm; margin-top:2mm; margin-bottom:2mm; padding:1mm; background-color:%1; color:%2; font-family:%3; font-size:%4pt; ").arg(global->headingsBackgroundColor().name()).arg(global->headingsTextColor().name()).arg(global->headingsFont().family()).arg(global->headingsFont().pointSize());
+ if (global->headingsFont().italic())
+ currentHTMLHeader += QString("font-style:italic; ");
+ if (global->headingsFont().bold())
+ currentHTMLHeader += QString("font-weight:bold; ");
+ currentHTMLHeader += QString("}\n");
+ currentHTMLHeader += QString("p.definition { margin-left:1.5mm; margin-top:2mm; margin-bottom:2mm;}\n");
+ currentHTMLHeader += QString("table { margin-left:1.5mm; margin-top:2mm; margin-bottom:2mm;}\n");
+ currentHTMLHeader += QString("pre { font-family:%1; font-size:%2pt; ").arg(global->textFont().family()).arg(global->textFont().pointSize());
+ if (global->textFont().italic())
+ currentHTMLHeader += QString("font-style:italic; ");
+ if (global->textFont().bold())
+ currentHTMLHeader += QString("font-weight:bold; ");
+ currentHTMLHeader += QString("}\n");
+ currentHTMLHeader += QString("</style></head>\n");
+
+ showResult(); // apply changes directly
+}
+
+
+void QueryView::stop()
+{
+ if (isRendering == true) {
+ part->closeURL();
+ isRendering = false;
+ emit(renderingStopped());
+ }
+}
+
+
+// print current result
+void QueryView::printQuery()
+{
+ part->view()->print();
+}
+
+
+// save the current result in an .html file
+void QueryView::saveQuery()
+{
+ if (!browseList.isEmpty()) {
+ BrowseData* brw = browseList.at(browsePos);
+ QString fName = brw->queryText+".html";
+ fName.replace(QRegExp("[\\s/]"),"_");
+ SaveHelper helper(fName,"*.html",global->topLevel);
+ QFile *file = helper.getFile(QString::null);
+
+ if (file) {
+ QTextStream stream(file);
+ stream.setEncoding(QTextStream::Locale);
+ stream << currentHTMLHeader+brw->html;
+ }
+ }
+}
+
+
+void QueryView::browseBack()
+{
+ if (browseBackPossible()) {
+ saveCurrentResultPos();
+ browsePos--;
+ actQueryCombo->setEditText(browseList.at(browsePos)->queryText);
+ showResult();
+ updateBrowseActions();
+ }
+}
+
+
+void QueryView::browseForward()
+{
+ if (browseForwardPossible()) {
+ saveCurrentResultPos();
+ browsePos++;
+ actQueryCombo->setEditText(browseList.at(browsePos)->queryText);
+ showResult();
+ updateBrowseActions();
+ }
+}
+
+
+void QueryView::selectAll()
+{
+ part->selectAll();
+}
+
+
+void QueryView::copySelection()
+{
+ kapp->clipboard()->setText(part->selectedText());
+}
+
+
+void QueryView::showFindDialog()
+{
+ KAction *act = part->actionCollection()->action("find");
+ if (act)
+ act->activate();
+}
+
+
+void QueryView::paletteChange ( const QPalette & )
+{
+
+ optionsChanged();
+}
+
+
+void QueryView::fontChange ( const QFont & )
+{
+ optionsChanged();
+}
+
+
+void QueryView::saveCurrentResultPos()
+{
+ if (!browseList.isEmpty()) {
+ browseList.at(browsePos)->xPos = part->view()->contentsX();
+ browseList.at(browsePos)->yPos = part->view()->contentsY();
+ }
+}
+
+
+void QueryView::showResult()
+{
+ if (!isRendering) {
+ isRendering = true;
+ emit(renderingStarted());
+ }
+
+ part->begin();
+ if (browseList.isEmpty()) {
+ part->write(currentHTMLHeader+"<body></body></html>");
+ part->end();
+ } else {
+ BrowseData* brw = browseList.at(browsePos);
+ emit(newCaption(getShortString(brw->queryText.simplifyWhiteSpace(),70)));
+ part->write(currentHTMLHeader+brw->html);
+ part->end();
+ part->view()->setFocus();
+ }
+}
+
+
+void QueryView::resultReady(const QString &result, const QString &query)
+{
+ BrowseData* brw = new BrowseData(result,query);
+
+ if (browseList.isEmpty()) {
+ browsePos = 0;
+ browseList.append(brw);
+ } else {
+ saveCurrentResultPos();
+ while (browseList.count()>browsePos+1)
+ browseList.removeLast();
+ browseList.append(brw);
+ browsePos++;
+ while (browseList.count()>global->maxBrowseListEntrys) {
+ browseList.removeFirst();
+ browsePos--;
+ }
+ }
+
+ showResult();
+ emit(enablePrintSave());
+ actQueryCombo->selectAll();
+ updateBrowseActions();
+}
+
+
+void QueryView::partCompleted()
+{
+ if (!browseList.isEmpty())
+ part->view()->setContentsPos(browseList.at(browsePos)->xPos,browseList.at(browsePos)->yPos);
+ if (isRendering) {
+ emit(renderingStopped());
+ isRendering = false;
+ }
+}
+
+
+void QueryView::slotURLRequest (const KURL &url, const KParts::URLArgs &)
+{
+ QString type = url.host();
+ QString urlText = url.prettyURL();
+ urlText.remove(0,8+type.length());
+
+ if (type.length()) { // valid url
+ if(type=="define")
+ emit(defineRequested(urlText));
+ if(type=="dbinfo")
+ interface->showDbInfo(urlText.utf8());
+ if(type=="realhttp")
+ kapp->invokeBrowser("http://"+urlText);
+ if(type=="realftp")
+ kapp->invokeBrowser("ftp://"+urlText);
+ }
+}
+
+
+void QueryView::middleButtonClicked()
+{
+ emit(clipboardRequested());
+}
+
+
+// construct the right-mouse-button-popup-menu on demand
+void QueryView::buildPopupMenu(const QString &url, const QPoint &point)
+{
+ rightBtnMenu->clear();
+
+ if (!url.isEmpty()) { // menuitem if mouse is over link
+ KURL u(url);
+ QString type = u.host();
+ popupLink = u.prettyURL();
+ popupLink.remove(0,8+type.length());
+
+ if (type.length()) { // valid url
+ if(type=="define") {
+ rightBtnMenu->insertItem(i18n("Define &Synonym"),
+ this,SLOT(popupDefineLink()));
+ rightBtnMenu->insertItem(i18n("M&atch Synonym"),
+ this,SLOT(popupMatchLink()));
+ rightBtnMenu->insertSeparator();
+ }
+ if(type=="dbinfo") {
+ rightBtnMenu->insertItem(i18n("D&atabase Information"),this,SLOT(popupDbInfo()));
+ rightBtnMenu->insertSeparator();
+ }
+ if(type=="realhttp") {
+ popupLink.prepend("http://");
+ rightBtnMenu->insertItem(SmallIcon("fileopen"),
+ i18n("&Open Link"),
+ this,SLOT(popupOpenLink()));
+ rightBtnMenu->insertSeparator();
+ }
+ if(type=="realftp") {
+ popupLink.prepend("ftp://");
+ rightBtnMenu->insertItem(SmallIcon("fileopen"),
+ i18n("&Open Link"),
+ this,SLOT(popupOpenLink()));
+ rightBtnMenu->insertSeparator();
+ }
+ }
+ }
+
+ if (part->hasSelection()) {
+ popupSelect = part->selectedText();
+ rightBtnMenu->insertItem(i18n("&Define Selection"),
+ this,SLOT(popupDefineSelect()));
+ rightBtnMenu->insertItem(i18n("&Match Selection"),
+ this,SLOT(popupMatchSelect()));
+ rightBtnMenu->insertSeparator();
+ } else {
+ kapp->clipboard()->setSelectionMode(false);
+ QString text = kapp->clipboard()->text();
+ if (text.isEmpty()) {
+ kapp->clipboard()->setSelectionMode(true);
+ text = kapp->clipboard()->text();
+ }
+ if (!text.isEmpty()) {
+ popupSelect = QApplication::clipboard()->text();
+ rightBtnMenu->insertItem(SmallIcon("define_clip"),
+ i18n("&Define Clipboard Content"),
+ this,SLOT(popupDefineSelect()));
+ rightBtnMenu->insertItem(i18n("&Match Clipboard Content"),
+ this,SLOT(popupMatchSelect()));
+ rightBtnMenu->insertSeparator();
+ }
+ }
+
+ int ID;
+
+ if (browseBackPossible()) { // if possible, show string
+ if (browseList.at(browsePos-1)->queryText.isEmpty())
+ rightBtnMenu->insertItem(SmallIcon("back"),
+ i18n("&Back: Information"),
+ this,SLOT(browseBack()));
+ else
+ rightBtnMenu->insertItem(SmallIcon("back"),
+ i18n("&Back: '%1'").arg(getShortString(browseList.at(browsePos-1)->queryText,25)),
+ this,SLOT(browseBack()));
+ } else {
+ ID = rightBtnMenu->insertItem(SmallIcon("back"), i18n("&Back"), this, SLOT(browseBack()));
+ rightBtnMenu->setItemEnabled(ID,false);
+ }
+
+ if (browseForwardPossible()) { // if possible, show string
+ if (browseList.at(browsePos+1)->queryText.isEmpty())
+ rightBtnMenu->insertItem(SmallIcon("forward"),
+ i18n("&Forward: Information"),
+ this,SLOT(browseForward()));
+ else
+ rightBtnMenu->insertItem(SmallIcon("forward"),
+ i18n("&Forward: '%1'").arg(getShortString(browseList.at(browsePos+1)->queryText,25)),
+ this,SLOT(browseForward()));
+ } else {
+ ID = rightBtnMenu->insertItem(SmallIcon("forward"),i18n("&Forward"),this,SLOT(browseForward()));
+ rightBtnMenu->setItemEnabled(ID,false);
+ }
+
+ rightBtnMenu->popup(point);
+}
+
+
+void QueryView::popupDefineLink()
+{
+ emit(defineRequested(popupLink));
+}
+
+
+void QueryView::popupMatchLink()
+{
+ emit(matchRequested(popupLink));
+}
+
+
+void QueryView::popupOpenLink()
+{
+ kapp->invokeBrowser(popupLink);
+}
+
+
+void QueryView::popupDefineSelect()
+{
+ emit(defineRequested(popupSelect));
+}
+
+
+void QueryView::popupMatchSelect()
+{
+ emit(matchRequested(popupSelect));
+}
+
+
+void QueryView::popupDbInfo()
+{
+
+ interface->showDbInfo(popupLink.utf8());
+}
+
+
+void QueryView::enableAction(const char * name, bool enabled)
+{
+ if (!strcmp(name,"copy"))
+ emit(enableCopy(enabled));
+}
+
+
+void QueryView::browseBack(int index)
+{
+ int x = browsePos-index;
+ if (x>=0) {
+ saveCurrentResultPos();
+ browsePos = x;
+ actQueryCombo->setEditText(browseList.at(browsePos)->queryText);
+ showResult();
+ QTimer::singleShot(0, this, SLOT(updateBrowseActions())); // don't clear the menu in this slot
+ }
+}
+
+
+void QueryView::browseForward(int index)
+{
+ int x = browsePos+index;
+ if (x < (int)(browseList.count())) {
+ saveCurrentResultPos();
+ browsePos = x;
+ actQueryCombo->setEditText(browseList.at(browsePos)->queryText);
+ showResult();
+ QTimer::singleShot(0, this, SLOT(updateBrowseActions())); // don't clear the menu in this slot
+ }
+}
+
+
+void QueryView::updateBrowseActions()
+{
+ if (browseBackPossible()) {
+ actBack->setEnabled(true);
+ if (browseList.at(browsePos-1)->queryText.isEmpty())
+ actBack->setText(i18n("&Back: Information"));
+ else
+ actBack->setText(i18n("&Back: '%1'").arg(getShortString(browseList.at(browsePos-1)->queryText,25)));
+
+ actBack->popupMenu()->clear();
+ int i = browsePos-1;
+ int num = 1;
+ QString s;
+ while ((i>=0)&&(num<=10)) {
+ s = browseList.at(i)->queryText;
+ if (s.isEmpty()) s = i18n("Information");
+ actBack->popupMenu()->insertItem(s,num);
+ num++;
+ i--;
+ }
+ } else {
+ actBack->setEnabled(false);
+ actBack->setText(i18n("&Back"));
+ actBack->popupMenu()->clear();
+ }
+
+ if (browseForwardPossible()) {
+ actForward->setEnabled(true);
+ if (browseList.at(browsePos+1)->queryText.isEmpty())
+ actForward->setText(i18n("&Forward: Information"));
+ else
+ actForward->setText(i18n("&Forward: '%1'").arg(getShortString(browseList.at(browsePos+1)->queryText,25)));
+
+ actForward->popupMenu()->clear();
+ int i = browsePos+1;
+ int num = 1;
+ QString s;
+ while ((i<(int)(browseList.count()))&&(num<=10)) {
+ s = browseList.at(i)->queryText;
+ if (s.isEmpty()) s = i18n("Information");
+ actForward->popupMenu()->insertItem(s,num);
+ num++;
+ i++;
+ }
+ } else {
+ actForward->setEnabled(false);
+ actForward->setText(i18n("&Forward"));
+ actForward->popupMenu()->clear();
+ }
+}
+
+//--------------------------------
+
+#include "queryview.moc"
diff --git a/kdict/queryview.h b/kdict/queryview.h
new file mode 100644
index 00000000..e942d297
--- /dev/null
+++ b/kdict/queryview.h
@@ -0,0 +1,178 @@
+/* -------------------------------------------------------------
+
+ queryview.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ SaveHelper network transparent file saving
+ BrowseData data structure used for caching definitions
+ DictHTMLPart handling of middle mouse button clicks
+ QueryView widget that displays the definitions
+
+ ------------------------------------------------------------- */
+
+#ifndef _QUERYVIEW_H_
+#define _QUERYVIEW_H_
+
+#include <qvbox.h>
+#include <khtml_part.h>
+
+class QFile;
+class KTempFile;
+class KPopupMenu;
+class DictComboAction;
+
+
+QString getShortString(QString str,unsigned int length);
+
+
+//******** SaveHelper *******************************************
+
+
+class SaveHelper {
+
+public:
+
+ SaveHelper(const QString &saveName, const QString &filter, QWidget *parent);
+ ~SaveHelper();
+
+ // returns a file open for writing
+ QFile* getFile(const QString &dialogTitle);
+
+private:
+
+ QWidget *p_arent;
+ QString s_aveName, f_ilter;
+ KURL url;
+ QFile* file;
+ KTempFile* tmpFile;
+ static QString lastPath;
+
+};
+
+
+//******** BrowseData ******************************************
+
+
+class BrowseData
+{
+
+public:
+
+ BrowseData(const QString &Nhtml, const QString &NqueryText);
+
+ QString html;
+ QString queryText;
+ int xPos,yPos;
+};
+
+
+//********* DictHTMLPart ***************************************
+
+class DictHTMLPart : public KHTMLPart
+{
+ Q_OBJECT
+
+public:
+
+ DictHTMLPart(QWidget *parentWidget = 0, const char *widgetname = 0);
+ ~DictHTMLPart();
+
+signals:
+ void middleButtonClicked();
+
+protected:
+
+ virtual void khtmlMouseReleaseEvent(khtml::MouseReleaseEvent *event);
+
+};
+
+//********* QueryView ******************************************
+
+
+class QueryView : public QVBox
+{
+ Q_OBJECT
+
+public:
+
+ QueryView(QWidget *_parent = 0L);
+ ~QueryView();
+
+ void setActions(KToolBarPopupAction* NactBack, KToolBarPopupAction* NactForward, DictComboAction* NactQueryCombo);
+
+ bool browseBackPossible() const;
+ bool browseForwardPossible() const;
+
+ void stop();
+
+public slots:
+ void optionsChanged();
+ void printQuery();
+ void saveQuery();
+ void browseBack();
+ void browseForward();
+ void selectAll();
+ void copySelection();
+ void showFindDialog();
+
+signals:
+
+ void defineRequested(const QString &query);
+ void matchRequested(const QString &query);
+ void clipboardRequested();
+ void enableCopy(bool selected); // emited when the user selects/deselects text
+ void enablePrintSave();
+ void renderingStarted();
+ void renderingStopped();
+ void newCaption(const QString&);
+
+protected:
+
+ void paletteChange ( const QPalette & );
+ void fontChange ( const QFont & );
+
+ void saveCurrentResultPos();
+ void showResult();
+
+protected slots:
+
+ void resultReady(const QString &result, const QString &query);
+ void partCompleted();
+ void slotURLRequest (const KURL &url, const KParts::URLArgs &args);
+ void middleButtonClicked();
+ void buildPopupMenu(const QString &url, const QPoint &point);
+ void popupDefineLink();
+ void popupMatchLink();
+ void popupOpenLink();
+ void popupDefineSelect();
+ void popupMatchSelect();
+ void popupDbInfo();
+ void enableAction(const char *, bool);
+ void browseBack(int);
+ void browseForward(int);
+ void updateBrowseActions();
+
+private:
+
+ DictHTMLPart *part; // Widgets
+
+ KToolBarPopupAction *actBack, *actForward;
+ DictComboAction *actQueryCombo;
+
+ KPopupMenu *rightBtnMenu;
+ QString popupLink,popupSelect; // needed for rightbtn-popup menu
+
+ QPtrList<BrowseData> browseList;
+ unsigned int browsePos; // position in browseList
+ QString currentHTMLHeader;
+
+ bool isRendering;
+};
+
+#endif
diff --git a/kdict/sets.cpp b/kdict/sets.cpp
new file mode 100644
index 00000000..0a252cec
--- /dev/null
+++ b/kdict/sets.cpp
@@ -0,0 +1,326 @@
+/* -------------------------------------------------------------
+
+ sets.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ DbSetsDialog dialog for editing the user defined database sets
+
+ ------------------------------------------------------------- */
+
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+
+#include <kiconloader.h>
+#include <kseparator.h>
+#include <klocale.h>
+
+#include "options.h"
+#include "sets.h"
+
+
+//********* DbSetsDialog ******************************************
+
+
+DbSetsDialog::DbSetsDialog(QWidget *parent, const char *name)
+ : KDialogBase(Plain, i18n("Database Sets"),Close | Help, Close, parent, name, false, true)
+{
+ QFrame* page=plainPage();
+
+ QStringList sets;
+ for(unsigned int i=1;i<global->databaseSets.count()+1;i++)
+ sets.append(global->databases[i]);
+
+ QVBoxLayout * topLayout = new QVBoxLayout(page, 0, 0);
+
+ QHBoxLayout * subLayout1 = new QHBoxLayout(5);
+ topLayout->addLayout(subLayout1,0);
+
+ w_set = new QComboBox(true,page);
+ w_set->setFixedHeight(w_set->sizeHint().height());
+ w_set->setInsertionPolicy (QComboBox::NoInsertion);
+ w_set->insertStringList(sets);
+ connect(w_set, SIGNAL(activated(int)),this, SLOT(activateSet(int)));
+ QLabel *l = new QLabel(w_set, i18n("&Set:"),page);
+ l->setMinimumSize(l->sizeHint());
+ subLayout1->addWidget(l,0);
+ subLayout1->addWidget(w_set,1);
+
+ subLayout1->addSpacing(8);
+
+ w_save = new QPushButton(i18n("S&ave"),page);
+ connect(w_save,SIGNAL(clicked()),this, SLOT(transferSet()));
+ subLayout1->addWidget(w_save,0);
+
+ QPushButton *btn = new QPushButton(i18n("&New"),page);
+ btn->setMinimumSize(btn->sizeHint());
+ connect(btn, SIGNAL(clicked()),this, SLOT(newPressed()));
+ subLayout1->addWidget(btn,0);
+
+ w_delete = new QPushButton(i18n("&Delete"),page);
+ w_delete->setMinimumSize(w_delete->sizeHint());
+ connect(w_delete, SIGNAL(clicked()),this, SLOT(deletePressed()));
+ subLayout1->addWidget(w_delete,0);
+
+ topLayout->addSpacing(8);
+
+ KSeparator *sep = new KSeparator(page);
+ topLayout->addWidget(sep,0);
+
+ topLayout->addSpacing(8);
+
+ QGridLayout * subLayout2 = new QGridLayout(7,3,6);
+ topLayout->addLayout(subLayout2,1);
+
+ w_leftBox = new QListBox(page);
+ connect(w_leftBox, SIGNAL(selected(int)),this, SLOT(leftSelected(int)));
+ connect(w_leftBox, SIGNAL(highlighted(int)),this, SLOT(leftHighlighted(int)));
+ QLabel *leftLabel = new QLabel(w_leftBox, i18n("S&elected databases:"),page);
+ leftLabel->setMinimumSize(leftLabel->sizeHint());
+ subLayout2->addWidget(leftLabel,0,0);
+ subLayout2->addMultiCellWidget(w_leftBox,1,6,0,0);
+
+ w_allLeft = new QPushButton(page);
+ w_allLeft->setIconSet(BarIconSet("2leftarrow"));
+ connect(w_allLeft, SIGNAL(clicked()),this, SLOT(allLeftPressed()));
+ subLayout2->addWidget(w_allLeft,2,1);
+
+ w_left = new QPushButton(page);
+ w_left->setIconSet(BarIconSet("1leftarrow"));
+ connect(w_left, SIGNAL(clicked()),this, SLOT(leftPressed()));
+ subLayout2->addWidget(w_left,3,1);
+
+ w_right = new QPushButton(page);
+ w_right->setIconSet(BarIconSet("1rightarrow"));
+ connect(w_right, SIGNAL(clicked()),this, SLOT(rightPressed()));
+ subLayout2->addWidget(w_right,4,1);
+
+ w_allRight = new QPushButton(page);
+ w_allRight->setIconSet(BarIconSet("2rightarrow"));
+ connect(w_allRight, SIGNAL(clicked()),this, SLOT(allRightPressed()));
+ subLayout2->addWidget(w_allRight,5,1);
+
+ w_rightBox = new QListBox(page);
+ connect(w_rightBox, SIGNAL(selected(int)),this, SLOT(rightSelected(int)));
+ connect(w_rightBox, SIGNAL(highlighted(int)),this, SLOT(rightHighlighted(int)));
+ QLabel *rightLabel = new QLabel(w_rightBox, i18n("A&vailable databases:"),page);
+ rightLabel->setMinimumSize(rightLabel->sizeHint());
+ subLayout2->addWidget(rightLabel,0,2);
+ subLayout2->addMultiCellWidget(w_rightBox,1,6,2,2);
+
+ subLayout2->setRowStretch(1,1);
+ subLayout2->setRowStretch(6,1);
+ subLayout2->setColStretch(0,1);
+ subLayout2->setColStretch(2,1);
+
+ setHelp("database-sets");
+
+ if (global->setsSize.isValid())
+ resize(global->setsSize);
+ else
+ resize(300,200);
+
+ if ((global->currentDatabase>=1)&&(global->currentDatabase<=global->databaseSets.count()))
+ activateSet(global->currentDatabase-1);
+ else
+ activateSet(0);
+ w_set->setFocus();
+}
+
+
+void DbSetsDialog::hideEvent(QHideEvent *)
+{
+ global->setsSize = size();
+ emit(dialogClosed());
+}
+
+
+void DbSetsDialog::newPressed()
+{
+ QStringList *temp = new QStringList;
+ temp->append(i18n("New Set"));
+ global->databaseSets.append(temp);
+ global->databases.insert(global->databases.at(global->databaseSets.count()),i18n("New Set"));
+ if (global->currentDatabase >= global->databaseSets.count())
+ global->currentDatabase++;
+
+ QStringList sets; // reread sets, because w_sets internal list is not correct in all cases
+ for(unsigned int i=1;i<global->databaseSets.count()+1;i++)
+ sets.append(global->databases[i]);
+ w_set->clear();
+ w_set->insertStringList(sets);
+ emit(setsChanged());
+ activateSet(global->databaseSets.count()-1);
+ w_set->setFocus();
+}
+
+
+void DbSetsDialog::deletePressed()
+{
+ int pos = w_set->currentItem();
+ if (pos>=0) {
+ global->databaseSets.remove(global->databaseSets.at(pos));
+ global->databases.remove(global->databases.at(pos+1));
+ if ((int)global->currentDatabase >= pos+1)
+ global->currentDatabase--;
+ w_set->removeItem(pos);
+ if (pos >= w_set->count())
+ pos--;
+ emit(setsChanged());
+ activateSet(pos);
+ w_set->setFocus();
+ }
+}
+
+
+void DbSetsDialog::allLeftPressed()
+{
+ while (w_rightBox->count()) {
+ w_leftBox->insertItem(w_rightBox->text(0));
+ w_rightBox->removeItem(0);
+ }
+ w_leftBox->sort();
+ checkButtons();
+}
+
+
+void DbSetsDialog::leftPressed()
+{
+ int pos = w_rightBox->currentItem();
+ if (pos>=0) {
+ w_leftBox->insertItem(w_rightBox->text(pos));
+ w_leftBox->sort();
+ w_rightBox->removeItem(pos);
+ if (pos >= (int)w_rightBox->count())
+ pos--;
+ if (pos>=0)
+ w_rightBox->setCurrentItem(pos);
+ checkButtons();
+ }
+}
+
+
+void DbSetsDialog::rightPressed()
+{
+ int pos = w_leftBox->currentItem();
+ if (pos>=0) {
+ w_rightBox->insertItem(w_leftBox->text(pos));
+ w_rightBox->sort();
+ w_leftBox->removeItem(pos);
+ if (pos >= (int)w_leftBox->count())
+ pos--;
+ if (pos>=0)
+ w_leftBox->setCurrentItem(pos);
+ checkButtons();
+ }
+}
+
+
+void DbSetsDialog::allRightPressed()
+{
+ while (w_leftBox->count()) {
+ w_rightBox->insertItem(w_leftBox->text(0));
+ w_leftBox->removeItem(0);
+ }
+ w_rightBox->sort();
+ checkButtons();
+}
+
+
+void DbSetsDialog::closePressed()
+{
+ accept();
+ global->setsSize = size();
+ emit(dialogClosed());
+}
+
+
+void DbSetsDialog::transferSet()
+{
+ global->databaseSets.at(w_set->currentItem())->clear();
+ global->databaseSets.at(w_set->currentItem())->append(w_set->currentText());
+ for (unsigned int i = 0;i<w_leftBox->count();i++)
+ global->databaseSets.at(w_set->currentItem())->append(w_leftBox->text(i));
+ global->databases.remove(global->databases.at(w_set->currentItem()+1));
+ global->databases.insert(global->databases.at(w_set->currentItem()+1),w_set->currentText());
+ w_set->changeItem(w_set->currentText(),w_set->currentItem());
+ emit(setsChanged());
+}
+
+
+void DbSetsDialog::activateSet(int num)
+{
+ w_leftBox->clear();
+ w_rightBox->clear();
+
+ if ((num < 0)||(num>=(int)global->databaseSets.count())) {
+ w_set->clearEdit();
+ w_delete->setEnabled(false);
+ w_save->setEnabled(false);
+ w_rightBox->repaint(true); // Workaround for repaint-bug
+ w_leftBox->repaint(true); // Workaround for repaint-bug
+ } else {
+ w_set->setCurrentItem(num);
+ for (unsigned int i=0;i<global->serverDatabases.count();i++)
+ if (global->databaseSets.at(num)->findIndex(global->serverDatabases[i])>0)
+ w_leftBox->insertItem(global->serverDatabases[i]);
+ else
+ w_rightBox->insertItem(global->serverDatabases[i]);
+ w_leftBox->sort();
+ w_rightBox->sort();
+ w_delete->setEnabled(true);
+ w_save->setEnabled(true);
+ if (w_rightBox->count()==0)
+ w_rightBox->repaint(true); // Workaround for repaint-bug
+ if (w_leftBox->count()==0)
+ w_leftBox->repaint(true); // Workaround for repaint-bug
+ w_leftBox->clearSelection();
+ w_leftBox->centerCurrentItem();
+ w_rightBox->clearSelection();
+ w_rightBox->centerCurrentItem();
+ }
+ checkButtons();
+}
+
+
+void DbSetsDialog::leftSelected(int)
+{
+ rightPressed();
+}
+
+
+void DbSetsDialog::rightSelected(int)
+{
+ leftPressed();
+}
+
+
+void DbSetsDialog::leftHighlighted(int)
+{
+ w_right->setEnabled(true);
+}
+
+
+void DbSetsDialog::rightHighlighted(int)
+{
+ w_left->setEnabled(true);
+}
+
+void DbSetsDialog::checkButtons()
+{
+ w_allLeft->setEnabled((w_rightBox->count()>0));
+ w_allRight->setEnabled((w_leftBox->count()>0));
+ w_right->setEnabled((w_leftBox->currentItem()>=0));
+ w_left->setEnabled((w_rightBox->currentItem()>=0));
+}
+
+//--------------------------------
+
+#include "sets.moc"
diff --git a/kdict/sets.h b/kdict/sets.h
new file mode 100644
index 00000000..3e874a6e
--- /dev/null
+++ b/kdict/sets.h
@@ -0,0 +1,68 @@
+/* -------------------------------------------------------------
+
+ sets.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ dbSetsDialog dialog for editing the user defined database sets
+
+ ------------------------------------------------------------- */
+
+#ifndef _KDICT_SETS_H_
+#define _KDICT_SETS_H_
+
+#include <kdialogbase.h>
+
+class QListBox;
+
+
+//********* DbSetsDialog ******************************************
+
+
+class DbSetsDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ DbSetsDialog(QWidget *parent=0, const char *name=0);
+
+signals:
+
+ void setsChanged();
+ void dialogClosed();
+
+protected:
+ void hideEvent(QHideEvent *);
+
+private slots:
+
+ void newPressed();
+ void deletePressed();
+ void allLeftPressed();
+ void leftPressed();
+ void rightPressed();
+ void allRightPressed();
+ void closePressed();
+ void transferSet();
+ void activateSet(int num);
+ void leftSelected(int index);
+ void rightSelected(int index);
+ void leftHighlighted(int index);
+ void rightHighlighted(int index);
+
+private:
+
+ void checkButtons();
+
+ QComboBox *w_set;
+ QListBox *w_leftBox, *w_rightBox;
+ QPushButton *w_delete,*w_save,*w_allLeft,*w_left,*w_right,*w_allRight;
+};
+
+#endif
diff --git a/kdict/toplevel.cpp b/kdict/toplevel.cpp
new file mode 100644
index 00000000..ee334cbd
--- /dev/null
+++ b/kdict/toplevel.cpp
@@ -0,0 +1,778 @@
+/* -------------------------------------------------------------
+
+ toplevel.cpp (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+ (C) by Matthias Hölzer 1998
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ TopLevel The toplevel widget of Kdict.
+
+ ------------------------------------------------------------- */
+
+#include <qclipboard.h>
+
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kapplication.h>
+#include <kstatusbar.h>
+#include <klocale.h>
+#include <kwin.h>
+#include <kedittoolbar.h>
+#include <kdebug.h>
+#include <dcopclient.h>
+
+#include "actions.h"
+#include "dict.h"
+#include "options.h"
+#include "queryview.h"
+#include "matchview.h"
+#include "sets.h"
+#include "toplevel.h"
+
+
+// cut a QString and add "..."
+QString getShortString(QString str,unsigned int length)
+{
+ if (str.length()>length) {
+ str.truncate(length-3);
+ str.append("...");
+ }
+ return str;
+}
+
+
+DictInterface *interface;
+GlobalData *global;
+
+
+TopLevel::TopLevel(QWidget* parent, const char* name)
+ : DCOPObject("KDictIface"), KMainWindow(parent, name, WType_TopLevel),
+ optDlg(0L), setsDlg(0L), stopRef(0)
+{
+ kapp->dcopClient()->setDefaultObject(objId());
+ kapp->setMainWidget(this);
+
+ global = new GlobalData();
+ global->topLevel = this;
+ global->read();
+ interface = new DictInterface();
+ connect(interface,SIGNAL(infoReady()),SLOT(stratDbChanged()));
+ connect(interface,SIGNAL(started(const QString&)),SLOT(clientStarted(const QString&)));
+ connect(interface,SIGNAL(stopped(const QString&)),SLOT(clientStopped(const QString&)));
+
+ queryView = new QueryView(this);
+ connect(queryView,SIGNAL(defineRequested(const QString&)),SLOT(define(const QString&)));
+ connect(queryView,SIGNAL(matchRequested(const QString&)),SLOT(match(const QString&)));
+ connect(queryView,SIGNAL(clipboardRequested()),SLOT(defineClipboard()));
+ connect(queryView,SIGNAL(enableCopy(bool)),SLOT(enableCopy(bool)));
+ connect(queryView,SIGNAL(enablePrintSave()),SLOT(enablePrintSave()));
+ connect(queryView,SIGNAL(renderingStarted()),SLOT(renderingStarted()));
+ connect(queryView,SIGNAL(renderingStopped()),SLOT(renderingStopped()));
+ connect(queryView,SIGNAL(newCaption(const QString&)),SLOT(newCaption(const QString&)));
+
+ matchView = new MatchView();
+ connect(matchView,SIGNAL(defineRequested(const QString&)),SLOT(define(const QString&)));
+ connect(matchView,SIGNAL(matchRequested(const QString&)),SLOT(match(const QString&)));
+ connect(matchView,SIGNAL(clipboardRequested()),SLOT(matchClipboard()));
+ connect(matchView,SIGNAL(windowClosed()),SLOT(toggleMatchListShow()));
+ connect(&resetStatusbarTimer,SIGNAL(timeout()),SLOT(resetStatusbar()));
+
+ setupStatusBar();
+ setupActions();
+ recreateGUI();
+ buildHistMenu();
+
+ if (global->showMatchList)
+ { // show splitter, html view & match list
+ splitter = new QSplitter(QSplitter::Horizontal,this);
+ splitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
+ queryView->reparent(splitter,0,queryView->pos(),true);
+ matchView->reparent(splitter,0,matchView->pos(),true);
+ setCentralWidget(splitter);
+ splitter->setResizeMode(matchView,QSplitter::KeepSize);
+ adjustMatchViewSize();
+ }
+ else
+ { // show only html view
+ setCentralWidget(queryView);
+ matchView->hide();
+ }
+
+ //apply settings
+ resize(600,390);
+ applyMainWindowSettings(KGlobal::config(),"toplevel_options");
+ stratDbChanged(); // fill combos, build menus
+
+ actQueryCombo->setFocus(); // place cursor in combobox
+}
+
+
+TopLevel::~TopLevel()
+{
+}
+
+
+void TopLevel::normalStartup()
+{
+ if (global->defineClipboard)
+ defineClipboard();
+}
+
+// ******* DCOP Interface ********************************************************
+
+void TopLevel::quit()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::quit()" << endl;
+ kapp->closeAllWindows();
+}
+
+
+void TopLevel::makeActiveWindow()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::makeActiveWindow()" << endl;
+ raiseWindow();
+}
+
+
+void TopLevel::definePhrase(QString phrase)
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::definePhrase()" << endl;
+ define(phrase);
+ raiseWindow();
+}
+
+
+void TopLevel::matchPhrase(QString phrase)
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::matchPhrase()" << endl;
+ match(phrase);
+ raiseWindow();
+}
+
+
+void TopLevel::defineClipboardContent()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::defineClipboardContent()" << endl;
+ defineClipboard();
+ raiseWindow();
+}
+
+
+void TopLevel::matchClipboardContent()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::matchClipboardContent()" << endl;
+ matchClipboard();
+ raiseWindow();
+}
+
+
+QStringList TopLevel::getDatabases()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::getDatabases()" << endl;
+ return global->databases;
+}
+
+
+QString TopLevel::currentDatabase()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::currentDatabase()" << endl;
+ return global->databases[global->currentDatabase];
+}
+
+
+QStringList TopLevel::getStrategies()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::getStrategies()" << endl;
+ return global->strategies;
+}
+
+
+QString TopLevel::currentStrategy()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::currentStrategy()" << endl;
+ return global->strategies[global->currentStrategy];
+}
+
+
+bool TopLevel::setDatabase(QString db)
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::setDatabase()" << endl;
+
+ int newCurrent = global->databases.findIndex(db);
+ if (newCurrent == -1)
+ return false;
+ else {
+ global->currentDatabase = newCurrent;
+ actDbCombo->setCurrentItem(global->currentDatabase);
+ return true;
+ }
+}
+
+
+bool TopLevel::setStrategy(QString strategy)
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::setStrategy()" << endl;
+
+ return matchView->selectStrategy(strategy);
+}
+
+
+bool TopLevel::historyGoBack()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::historyGoBack()" << endl;
+
+ if (!queryView->browseBackPossible())
+ return false;
+ else {
+ queryView->browseBack();
+ return true;
+ }
+}
+
+
+bool TopLevel::historyGoForward()
+{
+ kdDebug(5004) << "*DCOP call* TopLevel::historyGoForward()" << endl;
+
+ if (!queryView->browseForwardPossible())
+ return false;
+ else {
+ queryView->browseForward();
+ return true;
+ }
+}
+
+// *******************************************************************************
+
+void TopLevel::define(const QString &query)
+{
+ kdDebug(5004) << "TopLevel::define()" << endl;
+ actQueryCombo->setEditText(query);
+ doDefine();
+}
+
+
+void TopLevel::defineClipboard()
+{
+ kdDebug(5004) << "TopLevel::defineClipboard()" << endl;
+ kapp->clipboard()->setSelectionMode(true);
+ QString text = kapp->clipboard()->text();
+ if (text.isEmpty()) {
+ kapp->clipboard()->setSelectionMode(false);
+ text = kapp->clipboard()->text();
+ }
+ define(text);
+}
+
+
+void TopLevel::match(const QString &query)
+{
+ kdDebug(5004) << "TopLevel::match()" << endl;
+ actQueryCombo->setEditText(query);
+ doMatch();
+}
+
+
+void TopLevel::matchClipboard()
+{
+ kdDebug(5004) << "TopLevel::matchClipboard()" << endl;
+ kapp->clipboard()->setSelectionMode(true);
+ QString text = kapp->clipboard()->text();
+ if (text.isEmpty()) {
+ kapp->clipboard()->setSelectionMode(false);
+ text = kapp->clipboard()->text();
+ }
+ match(text);
+}
+
+
+bool TopLevel::queryClose()
+{
+ kdDebug(5004) << "TopLevel::queryClose()" << endl;
+
+ saveMainWindowSettings(KGlobal::config(),"toplevel_options");
+ saveMatchViewSize();
+ global->queryComboCompletionMode = actQueryCombo->completionMode();
+
+ global->write();
+
+ return true;
+}
+
+
+void TopLevel::setupActions()
+{
+ // file menu...
+ actSave = KStdAction::save(queryView, SLOT(saveQuery()), actionCollection());
+ actSave->setText(i18n("&Save As..."));
+ actSave->setEnabled(false);
+ actPrint = KStdAction::print(queryView, SLOT(printQuery()), actionCollection());
+ actPrint->setEnabled(false);
+ actStartQuery = new KAction(i18n("St&art Query"),"reload", 0 , this,
+ SLOT(doDefine()), actionCollection(), "start_query");
+ actStopQuery = new KAction(i18n("St&op Query"),"stop", 0 , this,
+ SLOT(stopClients()), actionCollection(), "stop_query");
+ actStopQuery->setEnabled(false);
+ KStdAction::quit(kapp, SLOT(closeAllWindows()), actionCollection());
+
+ // edit menu...
+ actCopy = KStdAction::copy(queryView, SLOT(copySelection()), actionCollection());
+ actCopy->setEnabled(false);
+ KStdAction::selectAll(queryView, SLOT(selectAll()), actionCollection());
+ new KAction(i18n("&Define Clipboard Content"), "define_clip", 0 , this,
+ SLOT(defineClipboard()), actionCollection(), "define_clipboard");
+ new KAction(i18n("&Match Clipboard Content"), 0 , this,
+ SLOT(matchClipboard()), actionCollection(), "match_clipboard");
+ KStdAction::find(queryView, SLOT(showFindDialog()), actionCollection());
+
+ // history menu...
+ actBack = new KToolBarPopupAction(i18n("&Back"), "back", KStdAccel::shortcut(KStdAccel::Back),
+ queryView, SLOT(browseBack()), actionCollection(),"browse_back");
+ actBack->setDelayed(true);
+ actBack->setStickyMenu(false);
+ actBack->setEnabled(false);
+ actForward = new KToolBarPopupAction(i18n("&Forward"), "forward", KStdAccel::shortcut(KStdAccel::Forward),
+ queryView, SLOT(browseForward()), actionCollection(),"browse_forward");
+ actForward->setDelayed(true);
+ actForward->setStickyMenu(false);
+ actForward->setEnabled(false);
+ new KAction(i18n("&Clear History"), 0 , this,
+ SLOT(clearQueryHistory()), actionCollection(), "clear_history");
+
+ // server menu...
+ new KAction(i18n("&Get Capabilities"), 0 , interface,
+ SLOT(updateServer()), actionCollection(), "get_capabilities");
+ new KAction(i18n("Edit &Database Sets..."), "edit", 0 , this,
+ SLOT(showSetsDialog()), actionCollection(), "edit_sets");
+ new KAction(i18n("&Summary"), 0 , interface,
+ SLOT(showDatabases()), actionCollection(), "db_summary");
+ new KAction(i18n("S&trategy Information"), 0 , interface,
+ SLOT(showStrategies()), actionCollection(), "strategy_info");
+ new KAction(i18n("&Server Information"), 0 , interface,
+ SLOT(showInfo()), actionCollection(), "server_info");
+
+ // settings menu...
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+
+ actShowMatchList = new KToggleAction(i18n("Show &Match List"), 0 , this,
+ SLOT(toggleMatchListShow()), actionCollection(), "show_match");
+ actShowMatchList->setCheckedState(i18n("Hide &Match List"));
+ actShowMatchList->setChecked(global->showMatchList);
+ KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()),
+actionCollection());
+ KStdAction::configureToolbars(this, SLOT(slotConfToolbar()), actionCollection());
+ KStdAction::preferences(this, SLOT(showOptionsDialog()), actionCollection());
+
+ // toolbar...
+ new KAction(i18n("Clear Input Field"), "query_erase", 0 , this,
+ SLOT(clearInput()), actionCollection(), "clear_query");
+
+ actQueryLabel = new DictLabelAction(i18n("&Look for:"), actionCollection(), "look_label");
+ actQueryCombo = new DictComboAction(i18n("Query"), actionCollection(), "query_combo",true,true);
+ connect(actQueryCombo,SIGNAL(activated(const QString &)), SLOT(define(const QString&)));
+ actQueryCombo->setCompletionMode(global->queryComboCompletionMode);
+ actDbLabel = new DictLabelAction(i18n("&in"), actionCollection(), "in_label");
+ actDbCombo = new DictComboAction(i18n("Databases"), actionCollection(), "db_combo",false,false);
+ connect(actDbCombo,SIGNAL(activated(int)),SLOT(databaseSelected(int)));
+ actDefineBtn = new DictButtonAction(i18n("&Define"), this, SLOT(doDefine()), actionCollection(), "define_btn");
+ actMatchBtn = new DictButtonAction(i18n("&Match"), this, SLOT(doMatch()), actionCollection(), "match_btn");
+
+ queryView->setActions(actBack,actForward,actQueryCombo);
+}
+
+
+void TopLevel::setupStatusBar()
+{
+ statusBar()->insertItem(i18n(" Ready "),0,2);
+ statusBar()->setItemAlignment(0,AlignLeft | AlignVCenter);
+
+ QString serverInfo;
+ if (global->authEnabled)
+ serverInfo = QString(" %1@%2:%3 ").arg(getShortString(global->user,50))
+ .arg(getShortString(global->server,50))
+ .arg(global->port);
+ else
+ serverInfo = QString(" %1:%3 ").arg(getShortString(global->server,50))
+ .arg(global->port);
+ statusBar()->insertItem(serverInfo, 1,3);
+ statusBar()->setItemAlignment(1,AlignLeft | AlignVCenter);
+}
+
+
+void TopLevel::recreateGUI()
+{
+ kdDebug(5004) << "TopLevel::recreateGUI()" << endl;
+ createGUI("kdictui.rc", false);
+ actQueryCombo->setList(global->queryHistory);
+ actQueryCombo->clearEdit();
+ actQueryLabel->setBuddy(actQueryCombo->widget());
+
+ actDbCombo->setList(global->databases);
+ actDbCombo->setCurrentItem(global->currentDatabase);
+ actDbLabel->setBuddy(actDbCombo->widget());
+ int bwidth;
+ if (actDefineBtn->widthHint() > actMatchBtn->widthHint())
+ bwidth = actDefineBtn->widthHint();
+ else
+ bwidth = actMatchBtn->widthHint();
+ actDefineBtn->setWidth(bwidth);
+ actMatchBtn->setWidth(bwidth);
+}
+
+
+// add text in the query-combobox to the history
+void TopLevel::addCurrentInputToHistory()
+{
+ QString text(actQueryCombo->currentText());
+
+ // maintain queryHistory
+ global->queryHistory.remove(text); // no double entrys
+ global->queryHistory.prepend(text); // prepend new item
+ while (global->queryHistory.count()>global->maxHistEntrys) // shorten list
+ global->queryHistory.remove(global->queryHistory.fromLast());
+
+ actQueryCombo->setList(global->queryHistory);
+ actQueryCombo->setCurrentItem(0);
+ buildHistMenu();
+}
+
+
+
+// erase text in query-combobox
+void TopLevel::clearInput()
+{
+ actQueryCombo->clearEdit();
+ actQueryCombo->setFocus(); // place cursor in combobox
+}
+
+
+// define text in the combobox
+void TopLevel::doDefine()
+{
+ QString text(actQueryCombo->currentText());
+
+ if (!text.isEmpty())
+ {
+ addCurrentInputToHistory();
+ actQueryCombo->selectAll();
+ interface->define(text);
+ }
+}
+
+
+void TopLevel::doMatch()
+{
+ QString text(actQueryCombo->currentText());
+
+ if (!text.isEmpty())
+ {
+ addCurrentInputToHistory();
+ actQueryCombo->selectAll();
+
+ if (!global->showMatchList)
+ {
+ toggleMatchListShow();
+ }
+
+ matchView->match(text);
+ setCaption(getShortString(text.simplifyWhiteSpace(),70));
+ }
+}
+
+
+void TopLevel::stopClients()
+{
+ interface->stop();
+ queryView->stop();
+}
+
+
+// rebuild history menu on demand
+void TopLevel::buildHistMenu()
+{
+ unplugActionList("history_items");
+
+ historyActionList.setAutoDelete(true);
+ historyActionList.clear();
+
+ unsigned int i = 0;
+ while ((i<10)&&(i<global->queryHistory.count())) {
+ historyActionList.append( new KAction(getShortString(global->queryHistory[i],70), 0, this, SLOT(queryHistMenu()),
+ (QObject*)0, global->queryHistory[i].utf8().data()) );
+ i++;
+ }
+
+ plugActionList("history_items", historyActionList);
+}
+
+
+// process a query via the history menu
+void TopLevel::queryHistMenu()
+{
+ QCString name = sender()->name();
+ if (!name.isEmpty())
+ define(QString::fromUtf8(name));
+}
+
+
+void TopLevel::clearQueryHistory()
+{
+ global->queryHistory.clear();
+ actQueryCombo->clear();
+ buildHistMenu();
+}
+
+
+// fill combos, rebuild menus
+void TopLevel::stratDbChanged()
+{
+ actDbCombo->setList(global->databases);
+ actDbCombo->setCurrentItem(global->currentDatabase);
+ matchView->updateStrategyCombo();
+
+ unplugActionList("db_detail");
+
+ dbActionList.setAutoDelete(true);
+ dbActionList.clear();
+
+ for (unsigned int i=0;i<global->serverDatabases.count();i++)
+ dbActionList.append( new KAction(global->serverDatabases[i], 0, this, SLOT(dbInfoMenuClicked()),
+ (QObject*)0, global->serverDatabases[i].utf8().data()) );
+
+ plugActionList("db_detail", dbActionList);
+}
+
+
+void TopLevel::dbInfoMenuClicked()
+{
+ QCString name = sender()->name();
+ if (!name.isEmpty())
+ interface->showDbInfo(name);
+}
+
+
+void TopLevel::databaseSelected(int num)
+{
+ global->currentDatabase = num;
+}
+
+
+void TopLevel::enableCopy(bool selected)
+{
+ actCopy->setEnabled(selected);
+}
+
+
+void TopLevel::enablePrintSave()
+{
+ actSave->setEnabled(true);
+ actPrint->setEnabled(true);
+}
+
+
+void TopLevel::clientStarted(const QString &message)
+{
+ statusBar()->changeItem(message,0);
+ resetStatusbarTimer.stop();
+ stopRef++;
+ actStopQuery->setEnabled(stopRef>0); // enable stop-icon
+ kapp->setOverrideCursor(waitCursor);
+}
+
+
+void TopLevel::clientStopped(const QString &message)
+{
+ statusBar()->changeItem(message,0);
+ resetStatusbarTimer.start(4000);
+ if (stopRef > 0)
+ stopRef--;
+ actStopQuery->setEnabled(stopRef>0); // disable stop-icon
+ kapp->restoreOverrideCursor();
+}
+
+
+void TopLevel::resetStatusbar()
+{
+ resetStatusbarTimer.stop();
+ statusBar()->changeItem(i18n(" Ready "),0);
+}
+
+
+void TopLevel::renderingStarted()
+{
+ stopRef++;
+ actStopQuery->setEnabled(stopRef>0); // disable stop-icon
+ kapp->setOverrideCursor(waitCursor);
+}
+
+
+void TopLevel::renderingStopped()
+{
+ if (stopRef > 0)
+ stopRef--;
+ actStopQuery->setEnabled(stopRef>0); // disable stop-icon
+ kapp->restoreOverrideCursor();
+}
+
+
+void TopLevel::newCaption(const QString &s)
+{
+ setCaption(s);
+}
+
+void TopLevel::toggleMatchListShow()
+{
+ saveMatchViewSize();
+ if (global->showMatchList) // list is visible -> hide it
+ {
+ global->showMatchList = false;
+ queryView->reparent(this,0,queryView->pos(),true);
+ matchView->reparent(this,0,matchView->pos(),true);
+ matchView->hide();
+ delete splitter;
+ setCentralWidget(queryView);
+ }
+ else // list is not visible -> show it
+ {
+ global->showMatchList = true;
+ splitter = new QSplitter(QSplitter::Horizontal,this);
+ splitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
+ setCentralWidget(splitter);
+ splitter->show();
+ queryView->reparent(splitter,0,queryView->pos(),true);
+ matchView->reparent(splitter,0,matchView->pos(),true);
+ splitter->setResizeMode(matchView,QSplitter::KeepSize);
+ adjustMatchViewSize();
+ }
+
+ actShowMatchList->setChecked(global->showMatchList);
+}
+
+
+void TopLevel::saveMatchViewSize()
+{
+ if (global->showMatchList)
+ {
+ global->splitterSizes = splitter->sizes();
+ }
+}
+
+
+void TopLevel::adjustMatchViewSize()
+{
+ if (global->splitterSizes.count()==2)
+ {
+ splitter->setSizes(global->splitterSizes);
+ }
+}
+
+
+void TopLevel::slotConfToolbar()
+{
+ saveMainWindowSettings(KGlobal::config(),"toplevel_options");
+ KEditToolbar dlg(actionCollection(), "kdictui.rc");
+ connect(&dlg,SIGNAL( newToolbarConfig() ), this, SLOT( slotNewToolbarConfig() ));
+ dlg.exec();
+}
+
+
+void TopLevel::slotNewToolbarConfig()
+{
+ recreateGUI();
+ applyMainWindowSettings(KGlobal::config(),"toplevel_options");
+ buildHistMenu(); // actionlists must be inserted
+ stratDbChanged();
+}
+
+
+void TopLevel::showSetsDialog()
+{
+ if (!setsDlg) {
+ setsDlg = new DbSetsDialog(this);
+ connect(setsDlg,SIGNAL(setsChanged()),this,SLOT(setsChanged()));
+ connect(setsDlg,SIGNAL(dialogClosed()),this,SLOT(hideSetsDialog()));
+ setsDlg->show();
+ } else {
+ KWin::activateWindow(setsDlg->winId());
+ }
+}
+
+
+void TopLevel::hideSetsDialog()
+{
+ if (setsDlg) {
+ setsDlg->delayedDestruct();
+ setsDlg = 0L;
+ }
+}
+
+
+void TopLevel::setsChanged()
+{
+ actDbCombo->setList(global->databases);
+ actDbCombo->setCurrentItem(global->currentDatabase);
+}
+
+
+void TopLevel::showOptionsDialog()
+{
+ if (!optDlg) {
+ optDlg = new OptionsDialog(this);
+ connect(optDlg,SIGNAL(optionsChanged()),this,SLOT(optionsChanged()));
+ connect(optDlg,SIGNAL(finished()),this,SLOT(hideOptionsDialog()));
+ optDlg->show();
+ } else {
+ KWin::activateWindow(optDlg->winId());
+ }
+}
+
+
+void TopLevel::hideOptionsDialog()
+{
+ if (optDlg) {
+ optDlg->delayedDestruct();
+ optDlg=0;
+ }
+}
+
+
+void TopLevel::optionsChanged()
+{
+ QString serverInfo;
+ if (global->authEnabled)
+ serverInfo = QString(" %1@%2:%3 ").arg(getShortString(global->user,50))
+ .arg(getShortString(global->server,50))
+ .arg(global->port);
+ else
+ serverInfo = QString(" %1:%3 ").arg(getShortString(global->server,50))
+ .arg(global->port);
+ statusBar()->changeItem(serverInfo,1);
+ interface->serverChanged(); // inform client
+ queryView->optionsChanged(); // inform html-view
+}
+
+void TopLevel::raiseWindow()
+{
+ // Bypass focus stealing prevention
+ kapp->updateUserTimestamp();
+
+ KWin::WindowInfo info = KWin::windowInfo( winId() );
+
+ if ( !info.isOnCurrentDesktop() )
+ {
+ KWin::setOnDesktop( winId(), KWin::currentDesktop() );
+ }
+
+ KWin::activateWindow(winId());
+}
+
+
+//--------------------------------
+
+#include "toplevel.moc"
diff --git a/kdict/toplevel.h b/kdict/toplevel.h
new file mode 100644
index 00000000..cd8fa25d
--- /dev/null
+++ b/kdict/toplevel.h
@@ -0,0 +1,149 @@
+/* -------------------------------------------------------------
+
+ toplevel.h (part of The KDE Dictionary Client)
+
+ Copyright (C) 2000-2001 Christian Gebauer <gebauer@kde.org>
+ (C) by Matthias Hölzer 1998
+
+ This file is distributed under the Artistic License.
+ See LICENSE for details.
+
+ -------------------------------------------------------------
+
+ TopLevel The toplevel widget of Kdict.
+
+ ------------------------------------------------------------- */
+
+#ifndef _TOPLEVEL_H_
+#define _TOPLEVEL_H_
+
+#include <qtimer.h>
+#include <kmainwindow.h>
+#include "dcopinterface.h"
+
+class QSplitter;
+
+class KToggleAction;
+class KToolBarPopupAction;
+
+class DictLabelAction;
+class DictComboAction;
+class DictButtonAction;
+class MatchView;
+class QueryView;
+class OptionsDialog;
+class DbSetsDialog;
+
+
+class TopLevel : public KMainWindow, virtual public KDictIface
+{
+ Q_OBJECT
+
+ friend class QueryView;
+
+public:
+
+ TopLevel(QWidget* parent = 0, const char* name = 0);
+ ~TopLevel();
+
+ void normalStartup(); // called when started without commandline parameters
+
+ // DCOP-Interface...
+ void quit();
+ void makeActiveWindow();
+ void definePhrase(QString phrase);
+ void matchPhrase(QString phrase);
+ void defineClipboardContent();
+ void matchClipboardContent();
+ QStringList getDatabases();
+ QString currentDatabase();
+ QStringList getStrategies();
+ QString currentStrategy();
+ bool setDatabase(QString db);
+ bool setStrategy(QString strategy);
+ bool historyGoBack();
+ bool historyGoForward();
+
+public slots:
+
+ void define(const QString &query);
+ void defineClipboard();
+
+ void match(const QString &query);
+ void matchClipboard();
+
+protected:
+ bool queryClose();
+
+private:
+
+ void setupActions();
+ void setupStatusBar();
+ void recreateGUI();
+ void raiseWindow();
+
+ void addCurrentInputToHistory(); // add text in the query-combobox to the history
+
+private slots:
+ void clearInput(); // erase text in query-combobox
+
+ void doDefine(); // define text in the combobox
+ void doMatch(); // match text in the combobox
+
+ void stopClients();
+
+ void buildHistMenu();
+ void queryHistMenu(); // process a query via the history menu
+ void clearQueryHistory();
+
+ void stratDbChanged();
+ void dbInfoMenuClicked();
+ void databaseSelected(int num);
+
+ void enableCopy(bool selected);
+ void enablePrintSave();
+
+ void clientStarted(const QString &message);
+ void clientStopped(const QString &message);
+ void resetStatusbar();
+ void renderingStarted();
+ void renderingStopped();
+
+ void newCaption(const QString&);
+
+ void toggleMatchListShow();
+ void saveMatchViewSize();
+ void adjustMatchViewSize();
+
+ void slotConfToolbar();
+ void slotNewToolbarConfig();
+
+ void showSetsDialog();
+ void hideSetsDialog();
+ void setsChanged();
+
+ void showOptionsDialog();
+ void hideOptionsDialog();
+ void optionsChanged();
+
+private:
+
+ KAction *actSave, *actPrint, *actStartQuery, *actStopQuery, *actCopy;
+ KToggleAction *actShowMatchList;
+ DictLabelAction *actQueryLabel, *actDbLabel;
+ DictComboAction *actQueryCombo, *actDbCombo;
+ DictButtonAction *actDefineBtn, *actMatchBtn;
+ QPtrList<KAction> historyActionList, dbActionList;
+ KToolBarPopupAction *actBack, *actForward;
+
+ QSplitter *splitter; // widgets....
+ QueryView *queryView;
+ MatchView *matchView;
+ OptionsDialog *optDlg;
+ DbSetsDialog *setsDlg;
+
+ QTimer resetStatusbarTimer;
+ int stopRef; // remember how many "clients" are running
+};
+
+#endif