浏览代码

Implement my own AssistantClient using KDE classes (KProcIO, KExtendedSocket) because QAssistantClient uses QProcess which conflicts with KProcess (fixes lockups while waiting for a process to complete).
This also means Debian users no longer need qt3-apps-dev to build KTIGCC.


git-svn-id: file:///var/svn/tigccpp/trunk@846 9552661e-59e3-4036-b4f2-dbe53926924f

kevinkofler 18 年之前
父节点
当前提交
80132e6bd4
共有 9 个文件被更改,包括 239 次插入34 次删除
  1. 1 2
      ktigcc/INSTALL
  2. 4 2
      ktigcc/KTIGCC.prj
  3. 171 0
      ktigcc/assistant.cpp
  4. 44 0
      ktigcc/assistant.h
  5. 2 2
      ktigcc/ktigcc.h
  6. 5 7
      ktigcc/ktigcc.pro
  7. 6 10
      ktigcc/mainform.ui.h
  8. 3 6
      ktigcc/programoptions.ui.h
  9. 3 5
      ktigcc/srcfilewin.ui.h

+ 1 - 2
ktigcc/INSTALL

@@ -42,7 +42,7 @@ B. Installing KTIGCC from source
                                                     alpha at the time I'm
                                                     writing this)
    kdebase from KDE 3 (should be the same version as kdelibs)
-   Qt 3 Assistant (*) (often included in qt or qt-devel packages)
+   Qt 3 Assistant (often included in qt or qt-devel packages)
    pkg-config
    Exuberant Ctags - can be obtained from http://ctags.sourceforge.net
    libticables2 (*), libtifiles2 (*), libticalcs2 (*) and libticonv (*) - can be
@@ -50,7 +50,6 @@ B. Installing KTIGCC from source
    TIGCC/*nix - can be obtained from http://tigcc.ticalc.org/linux/
    (*) If your distribution provides both a runtime and a -devel or -dev version
        of these packages, the -devel or -dev version is also needed.
-       NOTE: On Debian, the Qt Assistant headers are in qt3-apps-dev.
    1.1. Installation instructions for libti*
         The libti* libraries are standard autotools projects, they should build
         and install just fine with:

+ 4 - 2
ktigcc/KTIGCC.prj

@@ -88,7 +88,8 @@ module.include.files=\
 	selectstyle.ui.h\
 	colorlistitem.h\
 	errorlist.ui.h\
-	completion.h
+	completion.h\
+	assistant.h
 
 module.source.name=.
 module.source.type=
@@ -117,7 +118,8 @@ module.source.files=\
 	selectcolors.ui\
 	selectstyle.ui\
 	wordlist.ui\
-	completion.cpp
+	completion.cpp\
+	assistant.cpp
 
 module.pixmap.name=.
 module.pixmap.type=

+ 171 - 0
ktigcc/assistant.cpp

@@ -0,0 +1,171 @@
+/*
+   ktigcc - TIGCC IDE for KDE
+
+   Copyright (C) 2006 Kevin Kofler
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+// This class is like QAssistantClient, but simpler (taylored to KTIGCC's use)
+// and uses KProcess and KExtendedSocket instead of QProcess and QSocket. This
+// is needed because, very annoyingly, QProcess doesn't work together with
+// KProcess.
+
+#include "assistant.h"
+#include <kprocio.h>
+#include <kextsock.h>
+#include <kmessagebox.h>
+#include <qtextcodec.h>
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qeventloop.h>
+#include <qtextstream.h>
+#include <unistd.h>
+
+AssistantClient::AssistantClient(QObject *parent, const QString &profile)
+  : QObject(parent), parentWidget(0), procIO(0), socket(0),
+    assistantProfile(profile)
+{
+  if (parent->isWidgetType()) parentWidget=static_cast<QWidget *>(parent);
+}
+
+AssistantClient::~AssistantClient()
+{
+  int socketStatus=socket?socket->socketStatus():0;
+  if (socketStatus && socketStatus<KExtendedSocket::lookupInProgress) {
+    KMessageBox::error(parentWidget,socket->strError(socketStatus,
+                                                     socket->systemError()),
+                       "Socket Error");
+  }
+  if (procIO) delete procIO;
+  if (socket) delete socket;
+}
+
+void AssistantClient::openAssistant(const QString &page)
+{
+  int socketStatus=socket?socket->socketStatus():0;
+  if (socketStatus && socketStatus<KExtendedSocket::lookupInProgress) {
+    KMessageBox::error(parentWidget,socket->strError(socketStatus,
+                                                     socket->systemError()),
+                       "Socket Error");
+    delete procIO;
+    procIO=static_cast<KProcIO *>(NULL);
+    return;
+  }
+  if (socketStatus>=KExtendedSocket::closing) {
+    // The old process is not closed yet, but the connection was already lost.
+    // So kill the old process now and run a new one.
+    delete procIO;
+    procIO=static_cast<KProcIO *>(NULL);
+    delete socket;
+    socket=static_cast<KExtendedSocket *>(NULL);
+  }
+  if (!procIO) {
+    start_new:
+    // The QTextCodec has to be passed explicitly, or it will default to
+    // ISO-8859-1 regardless of the locale, which is just broken.
+    procIO=new KProcIO(QTextCodec::codecForLocale());
+    // Use MergedStderr instead of Stderr so the messages get ordered
+    // properly.
+    procIO->setComm(static_cast<KProcess::Communication>(
+      KProcess::Stdout|KProcess::MergedStderr));
+    (*procIO)<<"assistant"<<"-server";
+    if (!assistantProfile.isNull())
+      (*procIO)<<"-profile"<<assistantProfile;
+    if (!page.isNull())
+      (*procIO)<<"-file"<<page;
+    connect(procIO,SIGNAL(processExited(KProcess*)),
+            this,SLOT(procIO_processExited()));
+    connect(procIO,SIGNAL(readReady(KProcIO*)),this,SLOT(procIO_readReady()));
+    if (!procIO->start()) {
+      KMessageBox::error(parentWidget,"Could not run assistant.\n"
+                         "This feature requires Qt 3 Assistant.");
+      delete procIO;
+      procIO=static_cast<KProcIO *>(NULL);
+      return;
+    }
+  } else if (!page.isNull()) {
+    // Wait for Qt Assistant to actually open.
+    while (procIO && !socket) {
+      usleep(10000);
+      QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput,10);
+    }
+    if (!procIO) goto start_new;
+    QTextStream stream(static_cast<QIODevice *>(socket));
+    stream<<page<<'\n';
+  }
+}
+
+void AssistantClient::procIO_processExited()
+{
+  disconnect(procIO,SIGNAL(processExited(KProcess*)),
+             this,SLOT(procIO_processExited()));
+  disconnect(procIO,SIGNAL(readReady(KProcIO*)),this,SLOT(procIO_readReady()));
+  procIO->deleteLater();
+  procIO=static_cast<KProcIO *>(NULL);
+  int socketStatus=socket?socket->socketStatus():0;
+  if (socketStatus && socketStatus<KExtendedSocket::lookupInProgress) {
+    KMessageBox::error(parentWidget,socket->strError(socketStatus,
+                                                     socket->systemError()),
+                       "Socket Error");
+  }
+  if (socket) delete socket;
+  socket=static_cast<KExtendedSocket *>(NULL);
+}
+
+void AssistantClient::procIO_readReady()
+{
+  QString line;
+  while (procIO->readln(line)>=0) {
+    if (!socket) {
+      bool ok;
+      unsigned short port=line.toUShort(&ok);
+      if (ok) {
+        socket=new KExtendedSocket("localhost",port,KExtendedSocket::inetSocket);
+        switch (socket->connect()) {
+          case 0:
+            break;
+          case -1:
+            KMessageBox::error(parentWidget,socket->strError(socket->socketStatus(),
+                                                             socket->systemError()),
+                               "Socket Error");
+            goto error;
+          case -2:
+            KMessageBox::error(parentWidget,"Failed to connect to Qt Assistant.",
+                               "Socket Error");
+            goto error;
+          case -3:
+            KMessageBox::error(parentWidget,"Connection to Qt Assistant timed out.",
+                               "Socket Error");
+            goto error;
+          default:
+            KMessageBox::error(parentWidget,"Socket Error.");
+            error:
+            disconnect(procIO,SIGNAL(processExited(KProcess*)),
+                       this,SLOT(procIO_processExited()));
+            disconnect(procIO,SIGNAL(readReady(KProcIO*)),
+                       this,SLOT(procIO_readReady()));
+            procIO->deleteLater();
+            procIO=static_cast<KProcIO *>(NULL);
+            delete socket;
+            socket=static_cast<KExtendedSocket *>(NULL);
+            return;
+        }
+        continue;
+      }
+    }
+    KMessageBox::error(parentWidget,line,"Qt Assistant Error");
+  }
+}

+ 44 - 0
ktigcc/assistant.h

@@ -0,0 +1,44 @@
+/*
+   ktigcc - TIGCC IDE for KDE
+
+   Copyright (C) 2006 Kevin Kofler
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+*/
+
+#include <qobject.h>
+#include <qstring.h>
+
+class QWidget;
+class KProcIO;
+class KExtendedSocket;
+class AssistantClient : public QObject {
+  Q_OBJECT
+
+  public:
+    AssistantClient(QObject *parent=0, const QString &profile=QString::null);
+    ~AssistantClient();
+    void openAssistant(const QString &page=QString::null);
+
+  private slots:
+    void procIO_processExited();
+    void procIO_readReady();
+
+  private:
+    QWidget *parentWidget;
+    KProcIO *procIO;
+    KExtendedSocket *socket;
+    QString assistantProfile;
+};

+ 2 - 2
ktigcc/ktigcc.h

@@ -25,7 +25,7 @@
 #include <kaboutdata.h>
 #include <qstring.h>
 #include <qvaluevector.h>
-class QAssistantClient;
+class AssistantClient;
 class QClipboard;
 class SourceFile;
 typedef struct tprsettings tprSettings;
@@ -45,7 +45,7 @@ const char *lookup_doc_keyword(const char *keyword);
 extern KConfig *pconfig;
 extern KAboutData *pabout;
 extern const char *parg;
-extern QAssistantClient *assistant;
+extern AssistantClient *assistant;
 extern QClipboard *clipboard;
 extern QPtrList<SourceFile> sourceFiles;
 extern tprSettings settings;

+ 5 - 7
ktigcc/ktigcc.pro

@@ -3,7 +3,7 @@ LANGUAGE	= C++
 
 CONFIG	+= qt warn_on debug
 
-LIBS	+= -lktexteditor -lqassistantclient -lkutils
+LIBS	+= -lktexteditor -lkutils
 
 HEADERS	+= tpr.h \
 	ktigcc.h \
@@ -14,7 +14,8 @@ HEADERS	+= tpr.h \
 	callbacks.h \
 	parsing.h \
 	colorlistitem.h \
-	completion.h
+	completion.h \
+	assistant.h
 
 SOURCES	+= ktigcc.cpp \
 	preferences.cpp \
@@ -22,7 +23,8 @@ SOURCES	+= ktigcc.cpp \
 	tiemu_stub.cpp \
 	callbacks.cpp \
 	parsing.cpp \
-	completion.cpp
+	completion.cpp \
+	assistant.cpp
 
 FORMS	= srcfilewin.ui \
 	projectoptions.ui \
@@ -97,10 +99,6 @@ unix {
   OBJECTS_DIR = .obj
 }
 
-!exists($$QMAKE_INCDIR_QT/qassistantclient.h) {
-  error("Qt Assistant 3 headers required, try installing qt3-apps-dev.")
-}
-
 KDEPREFIX = $$system(kde-config --prefix)
 isEmpty(KDEPREFIX):error(KDE 3 kdelibs required.)
 

+ 6 - 10
ktigcc/mainform.ui.h

@@ -38,7 +38,6 @@
 #include <qtimer.h>
 #include <qdatetime.h>
 #include <qdragobject.h>
-#include <qassistantclient.h>
 #include <qdir.h>
 #include <qclipboard.h>
 #include <qaccel.h>
@@ -103,6 +102,7 @@
 #include "toolsdlg.h"
 #include "newsdlg.h"
 #include "completion.h"
+#include "assistant.h"
 
 using std::puts;
 using std::exit;
@@ -396,7 +396,7 @@ static QDockWindow *errorListDock;
 static ErrorList *errorList;
 static unsigned errorCountTotal=0,errorCountErrors=0,errorCountWarnings=0;
 static QString programOutput;
-QAssistantClient *assistant;
+AssistantClient *assistant;
 static unsigned fileCount=0, hFileCount=0, cFileCount=0, sFileCount=0, asmFileCount=0, qllFileCount=0, oFileCount=0, aFileCount=0, txtFileCount=0, othFileCount=0;
 tprSettings settings;
 tprLibOpts libopts;
@@ -1048,10 +1048,8 @@ void MainForm::init()
   othFilesListItem=folderListItem;
   folderListItem->setText(0,"Other Files");
   khelpmenu=new KHelpMenu(this,pabout);
-  assistant = new QAssistantClient("",this);
-  QStringList args(QString("-profile"));
-  args.append(QString("%1/doc/html/qt-assistant.adp").arg(tigcc_base));
-  assistant->setArguments(args);
+  assistant=new AssistantClient(this,
+    QString("%1/doc/html/qt-assistant.adp").arg(tigcc_base));
   lastDirectory=QString("%1/tigcc-projects").arg(QDir::homeDirPath());
   if (!QDir(lastDirectory).exists() && !QDir().mkdir(lastDirectory))
     lastDirectory=QString("%1/projects").arg(tigcc_base);
@@ -1289,10 +1287,8 @@ void MainForm::accel_activated(int index)
         if (wordUnderCursor.isEmpty()) return;
         QString docFile=lookup_doc_keyword(wordUnderCursor);
         if (docFile.isEmpty()) return;
-        // wait for Qt Assistant to actually open
-        while (!assistant->isOpen())
-          QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput,1000);
-        assistant->showPage(QString(tigcc_base)+QString("/doc/html/")+docFile);
+        assistant->openAssistant(
+          QString(tigcc_base)+QString("/doc/html/")+docFile);
         break;
       }
       case 6:

+ 3 - 6
ktigcc/programoptions.ui.h

@@ -35,9 +35,9 @@
 #include <qevent.h>
 #include <qeventloop.h>
 #include <qtooltip.h>
-#include <qassistantclient.h>
 #include "ktigcc.h"
 #include "tpr.h"
+#include "assistant.h"
 
 void ProgramOptions::ImportSettings()
 {
@@ -310,10 +310,7 @@ void ProgramOptions::mousePressEvent( QMouseEvent * e )
     QString docFile=lookup_doc_keyword(toolTip);
     if (docFile.isEmpty()) return;
     force_qt_assistant_page(1);
-    assistant->openAssistant();
-    // wait for it to actually open
-    while (!assistant->isOpen())
-      QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput,1000);
-    assistant->showPage(QString(tigcc_base)+QString("/doc/html/")+docFile);
+    assistant->openAssistant(
+      QString(tigcc_base)+QString("/doc/html/")+docFile);
   }
 }

+ 3 - 5
ktigcc/srcfilewin.ui.h

@@ -35,7 +35,6 @@
 #include <qtimer.h>
 #include <qdatetime.h>
 #include <qdragobject.h>
-#include <qassistantclient.h>
 #include <qdir.h>
 #include <qclipboard.h>
 #include <qaccel.h>
@@ -73,6 +72,7 @@
 #include "srcfile.h"
 #include "functions.h"
 #include "completion.h"
+#include "assistant.h"
 
 using std::puts;
 using std::exit;
@@ -347,10 +347,8 @@ void SourceFileWindow::accel_activated(int index)
         if (wordUnderCursor.isEmpty()) return;
         QString docFile=lookup_doc_keyword(wordUnderCursor);
         if (docFile.isEmpty()) return;
-        // wait for Qt Assistant to actually open
-        while (!assistant->isOpen())
-          QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput,1000);
-        assistant->showPage(QString(tigcc_base)+QString("/doc/html/")+docFile);
+        assistant->openAssistant(
+          QString(tigcc_base)+QString("/doc/html/")+docFile);
         break;
       }
       case 6: