summaryrefslogtreecommitdiff
path: root/src/fqterm/fqterm_window.cpp
diff options
context:
space:
mode:
authoriroul <iroul@iroul-VirtualBox.(none)>2014-04-04 07:35:14 -0700
committeriroul <iroul@iroul-VirtualBox.(none)>2014-04-04 07:35:14 -0700
commitafd34f2893a06a3aecf17e8e83b1df6ed2ae91a2 (patch)
tree851102abc55d91a1b76e63e9e89f9a7733da95b5 /src/fqterm/fqterm_window.cpp
parentc4b028ad53f7b362a864de24828d7cc39ff67b0a (diff)
downloadfqterm-afd34f2893a06a3aecf17e8e83b1df6ed2ae91a2.tar.xz
move to my github.
Diffstat (limited to 'src/fqterm/fqterm_window.cpp')
-rw-r--r--src/fqterm/fqterm_window.cpp2531
1 files changed, 2531 insertions, 0 deletions
diff --git a/src/fqterm/fqterm_window.cpp b/src/fqterm/fqterm_window.cpp
new file mode 100644
index 0000000..bb2c867
--- /dev/null
+++ b/src/fqterm/fqterm_window.cpp
@@ -0,0 +1,2531 @@
+/***************************************************************************
+ * fqterm, a terminal emulator for both BBS and *nix. *
+ * Copyright (C) 2008 fqterm development group. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <QClipboard>
+#include <QDesktopServices>
+#include <QDialog>
+#include <QFileDialog>
+#include <QFontDialog>
+#include <QFontMetrics>
+#include <QInputDialog>
+#include <QImageReader>
+#include <QMenu>
+#include <QMessageBox>
+#include <QStatusBar>
+#include <QTextEdit>
+#include <QTimer>
+#include <QUrl>
+#include <QtScript/QScriptValue>
+#include <QMdiArea>
+#include <QMdiSubWindow>
+#include <QTemporaryFile>
+#include <QRegExp>
+#include <QNetworkProxy>
+#include "addrdialog.h"
+#include "articledialog.h"
+#include "msgdialog.h"
+#include "osdmessage.h"
+#include "popwidget.h"
+#include "progressBar.h"
+#include "common.h"
+#include "fqterm_buffer.h"
+#include "fqterm_canvas.h"
+#include "fqterm_config.h"
+#include "fqterm_convert.h"
+#include "fqterm_filedialog.h"
+#include "fqterm_frame.h"
+#include "fqterm_http.h"
+#include "fqterm_ip_location.h"
+#include "fqterm_param.h"
+#include "fqterm_path.h"
+#include "fqterm_screen.h"
+#include "fqterm_session.h"
+#include "fqterm_sound.h"
+#include "fqterm_window.h"
+#include "fqterm_wndmgr.h"
+#include "imageviewer.h"
+#include "sshlogindialog.h"
+#include "statusBar.h"
+#include "zmodemdialog.h"
+#ifdef HAVE_PYTHON
+#include <Python.h>
+#include "fqterm_python.h"
+#endif //HAVE_PYTHON
+#include "fqterm_scriptengine.h"
+
+
+namespace FQTerm {
+
+char FQTermWindow::directions_[][5] = {
+ // 4
+ "\x1b[1~", // 0 HOME
+ "\x1b[4~", // 1 END
+ "\x1b[5~", // 2 PAGE UP
+ "\x1b[6~", // 3 PAGE DOWN
+ // 3
+ "\x1b[A", // 4 UP
+ "\x1b[B", // 5 DOWN
+ "\x1b[D", // 6 LEFT
+ "\x1b[C" // 7 RIGHT
+};
+
+class FAQ: public QObject {
+ Q_OBJECT;
+ public slots:
+ FAQ() {a = 100;}
+
+ int get() {return a;}
+
+ private:
+ int a;
+};
+
+
+//constructor
+FQTermWindow::FQTermWindow(FQTermConfig *config, FQTermFrame *frame, FQTermParam param,
+ int addressIndex, QWidget *parent,
+ const char *name, Qt::WFlags wflags)
+ : QMainWindow(parent, wflags),
+ frame_(frame),
+ isSelecting_(false),
+ addressIndex_(addressIndex),
+ sound_(NULL),
+ isMouseClicked_(false),
+ blinkStatus_(true),
+ isUrlUnderLined_(false),
+#ifdef HAVE_PYTHON
+ // the system wide script
+ pythonScriptLoaded_(false),
+ // python thread module
+ pModule(NULL),
+ pDict(NULL),
+#endif
+ script_engine_(NULL),
+ externalEditor_(NULL) {
+ // isMouseX11_ = false;
+ session_ = new FQTermSession(config, param);
+ screen_ = new FQTermScreen(this, session_);
+
+ config_ = config;
+ zmodemDialog_ = new zmodemDialog(this);
+
+ externalEditor_ = new FQTermExternalEditor(this);
+
+ pageViewMessage_ = new PageViewMessage(this);
+ tabBlinkTimer_ = new QTimer;
+
+ setWindowIcon(QIcon("noicon"));
+ setWindowTitle(param.name_);
+ setMouseTracking(true);
+ setFocusProxy(screen_);
+ setCentralWidget(screen_);
+ addMenu();
+ setStatusBar(NULL);
+
+
+ FQ_VERIFY(connect(pageViewMessage_, SIGNAL(hideAt(const QRect&)),
+ screen_, SLOT(widgetHideAt(const QRect&))));
+
+ FQ_VERIFY(connect(frame_, SIGNAL(bossColor()),
+ screen_, SLOT(bossColor())));
+
+ FQ_VERIFY(connect(frame_, SIGNAL(fontAntiAliasing(bool)),
+ screen_, SLOT(setFontAntiAliasing(bool))));
+
+ FQ_VERIFY(connect(frame_, SIGNAL(changeLanguage()),
+ this, SLOT(recreateMenu())));
+ FQ_VERIFY(connect(frame_, SIGNAL(bossColor()),
+ screen_, SLOT(bossColor())));
+ FQ_VERIFY(connect(frame_, SIGNAL(updateScroll()),
+ screen_, SLOT(updateScrollBar())));
+
+ FQ_VERIFY(connect(screen_, SIGNAL(inputEvent(const QString&)),
+ session_, SLOT(handleInput(const QString&))));
+
+ FQ_VERIFY(connect(session_, SIGNAL(zmodemStateChanged(int, int, const char*)),
+ this, SLOT(ZmodemState(int, int, const char *))));
+ FQ_VERIFY(connect(zmodemDialog_, SIGNAL(canceled()),
+ session_, SLOT(cancelZmodem())));
+ FQ_VERIFY(connect(session_, SIGNAL(connectionClosed()),
+ this, SLOT(connectionClosed())));
+ FQ_VERIFY(connect(session_, SIGNAL(startAlert()), this, SLOT(startBlink())));
+ FQ_VERIFY(connect(session_, SIGNAL(stopAlert()), this, SLOT(stopBlink())));
+ // FQ_VERIFY(connect(session_->decoder_, SIGNAL(mouseMode(bool)),
+ // this, SLOT(setMouseMode(bool))));
+ FQ_VERIFY(connect(session_, SIGNAL(articleCopied(int, const QString)),
+ this, SLOT(articleCopied(int, const QString))));
+ FQ_VERIFY(connect(session_, SIGNAL(requestUserPwd(QString*, QString*, bool*)),
+ this, SLOT(requestUserPwd(QString *, QString *, bool *))));
+ //connect telnet signal to slots
+ // QVERIFY(connect(session_->telnet_, SIGNAL(readyRead(int)),
+ // this, SLOT(readReady(int))));
+ FQ_VERIFY(connect(session_, SIGNAL(sessionUpdated()),
+ this, SLOT(sessionUpdated())));
+ FQ_VERIFY(connect(session_, SIGNAL(bellReceived()), this, SLOT(beep())));
+ FQ_VERIFY(connect(session_, SIGNAL(onTitleSet(const QString&)), this, SLOT(onTitleSet(const QString&))));
+
+ FQ_VERIFY(connect(session_, SIGNAL(messageAutoReplied()),
+ this, SLOT(messageAutoReplied())));
+ FQ_VERIFY(connect(session_, SIGNAL(telnetStateChanged(int)),
+ this, SLOT(TelnetState(int))));
+ FQ_VERIFY(connect(session_, SIGNAL(errorMessage(QString)),
+ this, SLOT(showSessionErrorMessage(QString))));
+
+ FQ_VERIFY(connect(tabBlinkTimer_, SIGNAL(timeout()), this, SLOT(blinkTab())));
+
+ FQ_VERIFY(connect(externalEditor_, SIGNAL(done(const QString&)), this, SLOT(externalEditorDone(const QString&))));
+
+ FQ_VERIFY(connect(this, SIGNAL(writeStringSignal(const QString&)), this, SLOT(writeString(const QString&)), Qt::QueuedConnection));
+ FQ_VERIFY(connect(this, SIGNAL(writeRawStringSignal(const QString&)), this, SLOT(writeRawString(const QString&)), Qt::QueuedConnection));
+
+#if defined(WIN32)
+ popWindow_ = new popWidget(this, frame_);
+#else
+ popWindow_ = new popWidget(this);
+#endif
+
+ const QString &resource_dir = getPath(RESOURCE);
+
+ cursors_[FQTermSession::kHome] = QCursor(
+ QPixmap(resource_dir + "cursor/home.xpm"));
+ cursors_[FQTermSession::kEnd] = QCursor(
+ QPixmap(resource_dir + "cursor/end.xpm"));
+ cursors_[FQTermSession::kPageUp] = QCursor(
+ QPixmap(resource_dir + "cursor/pageup.xpm"));
+ cursors_[FQTermSession::kPageDown] = QCursor(
+ QPixmap(resource_dir + "cursor/pagedown.xpm"));
+ cursors_[FQTermSession::kUp] = QCursor(
+ QPixmap(resource_dir + "cursor/prev.xpm"));
+ cursors_[FQTermSession::kDown] = QCursor(
+ QPixmap(resource_dir + "cursor/next.xpm"));
+ cursors_[FQTermSession::kLeft] = QCursor(
+ QPixmap(resource_dir + "cursor/exit.xpm"), 0, 10);
+ cursors_[FQTermSession::kRight] = QCursor(
+ QPixmap(resource_dir + "cursor/hand.xpm"));
+ cursors_[FQTermSession::kNormal] = Qt::ArrowCursor;
+
+ script_engine_ = new FQTermScriptEngine(this);
+ if (session_->param().isAutoLoadScript_
+ && !session_->param().autoLoadedScriptFileName_.isEmpty()) {
+ const QString &filename = session_->param().autoLoadedScriptFileName_;
+#ifdef HAVE_PYTHON
+ if (filename.trimmed().endsWith(".py", Qt::CaseInsensitive)){
+ initPython(filename);
+ } else {
+ initPython("");
+#endif
+ runScript(filename);
+#ifdef HAVE_PYTHON
+ }
+ } else {
+ initPython("");
+#endif //HAVE_PYTHON
+ }
+ session_->setScriptListener(this);
+}
+
+FQTermWindow::~FQTermWindow() {
+#ifdef HAVE_PYTHON
+ finalizePython();
+#endif //HAVE_PYTHON
+ script_engine_->finalizeScript();
+ // delete telnet_;
+ delete session_;
+ delete popWindow_;
+ delete tabBlinkTimer_;
+ delete menu_;
+ delete urlMenu_;
+ delete screen_;
+ delete pageViewMessage_;
+ //delete script_engine_;
+}
+
+void FQTermWindow::addMenu() {
+ urlMenu_ = new QMenu(screen_);
+ urlMenu_->addAction(tr("Preview image"), this, SLOT(previewLink()));
+ urlMenu_->addAction(tr("Open link"), this, SLOT(openLink()));
+ urlMenu_->addAction(tr("Save As..."), this, SLOT(saveLink()));
+ urlMenu_->addAction(tr("Copy link address"), this, SLOT(copyLink()));
+ urlMenu_->addSeparator();
+ urlMenu_->addAction(tr("Share Selected Text and URL!"), this, SLOT(shareIt()));
+ const QString &resource_dir = getPath(RESOURCE);
+
+ menu_ = new QMenu(screen_);
+#if defined(__APPLE__)
+ // Please note that on MacOSX Qt::CTRL corresponds to Command key (apple key),
+ // while Qt::Meta corresponds to Ctrl key.
+ QKeySequence copy_shortcut(tr("Ctrl+C"));
+ QKeySequence paste_shortcut(tr("Ctrl+V"));
+#else
+ QKeySequence copy_shortcut(tr("Ctrl+Insert"));
+ QKeySequence paste_shortcut(tr("Shift+Insert"));
+#endif
+ menu_->addAction(QPixmap(resource_dir + "pic/copy.png"), tr("Copy"),
+ this, SLOT(copy()), copy_shortcut);
+ menu_->addAction(QPixmap(resource_dir + "pic/paste.png"), tr("Paste"),
+ this, SLOT(paste()), paste_shortcut);
+
+ menu_->addAction(QPixmap(resource_dir+"pic/get_article_fulltext.png"), tr("Copy Article"),
+ this, SLOT(copyArticle()));
+ menu_->addSeparator();
+
+ QMenu *fontMenu = new QMenu(menu_);
+ fontMenu->setTitle(tr("Font"));
+ fontMenu->setIcon(QPixmap(resource_dir + "pic/change_fonts.png"));
+ for (int i = 0; i < 2; ++i) {
+ QAction *act = fontMenu->addAction(
+ FQTermParam::getLanguageName(bool(i)) + tr(" Font"),
+ this, SLOT(setFont()));
+ act->setData(i);
+ }
+ menu_->addMenu(fontMenu);
+
+ menu_->addAction(QPixmap(resource_dir + "pic/ansi_color.png"), tr("Color"),
+ this, SLOT(setColor()));
+ menu_->addSeparator();
+ menu_->addAction(QPixmap(resource_dir + "pic/preferences.png"), tr("Setting"),
+ this, SLOT(setting()));
+ menu_->addSeparator();
+ menu_->addAction(tr("Open Selected As Url"), this, SLOT(openAsUrl()));
+ menu_->addAction(tr("Search Selected Text!"), this, SLOT(searchIt()));
+ menu_->addAction(tr("Share Selected Text and URL!"), this, SLOT(shareIt()));
+}
+
+void FQTermWindow::recreateMenu() {
+ delete urlMenu_;
+ delete menu_;
+ addMenu();
+}
+
+//close event received
+void FQTermWindow::closeEvent(QCloseEvent *clse) {
+ bool toClose = true;
+ if (isConnected() && FQTermPref::getInstance()->openWarnOnClose_) {
+ QMessageBox mb(tr("FQTerm"),
+ tr("Still connected, do you really want to exit?"),
+ QMessageBox::Warning, QMessageBox::Yes|QMessageBox::Default,
+ QMessageBox::No | QMessageBox::Escape, 0, this);
+ if (mb.exec() != QMessageBox::Yes) {
+ toClose = false;
+ }
+ }
+ if (toClose) {
+ session_->close();
+ } else {
+ clse->ignore();
+ return;
+ }
+ //We no longer save setting on close from r1036.
+ //saveSetting();
+}
+
+void FQTermWindow::blinkTab() {
+ emit blinkTheTab(this, blinkStatus_);
+ blinkStatus_ = !blinkStatus_;
+}
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* Mouse & Key */
+/* */
+/* ------------------------------------------------------------------------ */
+void FQTermWindow::enterEvent(QEvent*){}
+
+void FQTermWindow::leaveEvent(QEvent*) {
+ // TODO: code below doesn't work
+ // QPoint temp(0, 0);
+ // session_->setSelect(temp, temp, session_->isRectangleCopy_);
+ // QApplication::postEvent(screen_, new QPaintEvent(QRect(0, 0, 0, 0));
+ // &paintEvent);
+}
+
+void FQTermWindow::changeEvent(QEvent *e) {
+ if (e->type() == QEvent::WindowStateChange) {
+ QWindowStateChangeEvent *event = (QWindowStateChangeEvent*)(e);
+ Qt::WindowStates oldState = event->oldState();
+ if (!isMaximized()) {
+ emit refreshOthers(this);
+ }
+ if ( (oldState & Qt::WindowMinimized && !isMinimized()) ||
+ (!(oldState & Qt::WindowActive) && isActiveWindow())) {
+ forcedRepaintScreen();
+ }
+ if (oldState & Qt::WindowMaximized || isMaximized()) {
+ emit resizeSignal(this);
+ }
+ }
+}
+
+void FQTermWindow::resizeEvent(QResizeEvent *qResizeEvent)
+{
+ emit resizeSignal(this);
+}
+
+bool FQTermWindow::event(QEvent *qevent) {
+ bool res = false;
+ QKeyEvent *keyEvent;
+ switch(qevent->type()) {
+#ifdef __linux__
+ case QEvent::ShortcutOverride:
+ keyEvent = (QKeyEvent *)(qevent);
+ if(keyEvent->key() == Qt::Key_W &&
+ keyEvent->modifiers() == Qt::ControlModifier) {
+ keyEvent->accept();
+ res = true;
+ }
+ break;
+#endif
+ case QEvent::KeyPress:
+ keyEvent = (QKeyEvent *)(qevent);
+ if (keyEvent->key() == Qt::Key_Tab ||
+ keyEvent->key() == Qt::Key_Backtab) {
+ // Key_Tab and Key_Backtab are special, if we don't process them here,
+ // the default behavoir is to move focus. see QWidget::event.
+ keyPressEvent(keyEvent);
+ keyEvent->accept();
+ res = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ res = res || QMainWindow::event(qevent);
+
+ if (qevent->type() == QEvent::HoverMove
+ || qevent->type() == QEvent::MouseMove
+ || qevent->type() == QEvent::Move) {
+ if (res) {
+ FQ_TRACE("wndEvent", 10) << "Accept event: " << qevent->type()
+ << " " << getEventName(qevent->type()) << ".";
+ } else {
+ FQ_TRACE("wndEvent", 10) << "Ignore event: " << qevent->type()
+ << " " << getEventName(qevent->type()) << ".";
+ }
+ } else {
+ if (res) {
+ FQ_TRACE("wndEvent", 9) << "Accept event: " << qevent->type()
+ << " " << getEventName(qevent->type()) << ".";
+ } else {
+ FQ_TRACE("wndEvent", 9) << "Ignore event: " << qevent->type()
+ << " " << getEventName(qevent->type()) << ".";
+ }
+ }
+ return res;
+}
+
+void FQTermWindow::mouseDoubleClickEvent(QMouseEvent *mouseevent) {
+ if (scriptMouseEvent(mouseevent))
+ return;
+}
+
+void FQTermWindow::mousePressEvent(QMouseEvent *mouseevent) {
+ if (scriptMouseEvent(mouseevent))
+ return;
+ // stop the tab blinking
+ stopBlink();
+
+ // Left Button for selecting
+ if (mouseevent->button() & Qt::LeftButton && !(mouseevent->modifiers())) {
+ startSelecting(mouseevent->pos());
+ }
+
+ // Right Button
+ if ((mouseevent->button() & Qt::RightButton)) {
+ if (mouseevent->modifiers() & Qt::ControlModifier) {
+ // on Url
+ if (!session_->getUrl().isEmpty()) {
+ previewLink();
+ }
+ return ;
+ }
+
+#ifdef __APPLE__
+ bool additional_modifier = (mouseevent->modifiers() & !Qt::MetaModifier);
+#else
+ bool additional_modifier = mouseevent->modifiers();
+#endif
+
+ if (!(additional_modifier)) {
+ // on Url
+ if (!session_->getUrl().isEmpty()) {
+ urlMenu_->popup(mouseevent->globalPos());
+ } else {
+ menu_->popup(mouseevent->globalPos());
+ }
+ return ;
+ }
+ }
+ // Middle Button for paste
+ if (mouseevent->button() &Qt::MidButton && !(mouseevent->modifiers())) {
+ if (isConnected())
+ // on Url
+ if (!session_->getUrl().isEmpty()) {
+ previewLink();
+ } else {
+ pasteHelper(false);
+ }
+ return ;
+ }
+
+ // If it is a click, there should be a press event and a release event.
+ isMouseClicked_ = true;
+
+ // xterm mouse event
+ //session_->sendMouseState(0, me->button(), me->state(), me->pos());
+}
+
+
+void FQTermWindow::mouseMoveEvent(QMouseEvent *mouseevent) {
+ bool mouseEventConsumed = scriptMouseEvent(mouseevent);
+ QPoint position = mouseevent->pos();
+ if (!mouseEventConsumed)
+ {
+
+ // selecting by leftbutton
+ if ((mouseevent->buttons() &Qt::LeftButton) && isSelecting_) {
+ onSelecting(position);
+ }
+ }
+ if (!(session_->param().isSupportMouse_ && isConnected())) {
+ return;
+ }
+
+ setCursorPosition(position);
+ setCursorType(position);
+
+
+ if (!mouseEventConsumed)
+ {
+ if (!isUrlUnderLined_ && session_->urlStartPoint() != session_->urlEndPoint()) {
+ isUrlUnderLined_ = true;
+ urlStartPoint_ = session_->urlStartPoint();
+ urlEndPoint_ = session_->urlEndPoint();
+ clientRect_ = QRect(QPoint(0, urlStartPoint_.y()), QSize(session_->getBuffer()->getNumColumns(), urlEndPoint_.y() - urlStartPoint_.y() + 1));
+ repaintScreen();
+
+ } else if (isUrlUnderLined_ && (session_->urlStartPoint() != urlStartPoint_ || session_->urlEndPoint() != urlEndPoint_)) {
+ clientRect_ = QRect(QPoint(0, urlStartPoint_.y()), QSize(session_->getBuffer()->getNumColumns(), urlEndPoint_.y() - urlStartPoint_.y() + 1));
+ urlStartPoint_ = QPoint();
+ urlEndPoint_ = QPoint();
+ repaintScreen();
+ isUrlUnderLined_ = false;
+
+ }
+ }
+}
+
+static bool isSupportedImage(const QString &name) {
+ static QList<QByteArray> image_formats =
+ QImageReader::supportedImageFormats();
+
+ return image_formats.contains(name.section(".", -1).toLower().toUtf8());
+}
+
+void FQTermWindow::mouseReleaseEvent(QMouseEvent *mouseevent) {
+ if (scriptMouseEvent(mouseevent))
+ return;
+ if (!isMouseClicked_) {
+ return ;
+ }
+ isMouseClicked_ = false;
+ // other than Left Button ignored
+ if (!(mouseevent->button() & Qt::LeftButton) ||
+ (mouseevent->modifiers() & Qt::KeyboardModifierMask)) {
+ // no local mouse event
+ //session_->sendMouseState(3, me->button(), me->state(), me->pos());
+ return ;
+ }
+
+ // Left Button for selecting
+ QPoint currentMouseCell = screen_->mapToChar(mouseevent->pos());
+ if (currentMouseCell != lastMouseCell_ && isSelecting_) {
+ finishSelecting(mouseevent->pos());
+ return ;
+ }
+ isSelecting_ = false;
+
+ if (!session_->param().isSupportMouse_ || !isConnected()) {
+ return ;
+ }
+
+ // url
+ QString url = session_->getUrl();
+ if (!url.isEmpty()) {
+ if (isSupportedImage(url)) {
+ previewLink();
+ } else {
+ openUrl(url);
+ }
+ return ;
+ }
+
+ processLClick(currentMouseCell);
+}
+
+void FQTermWindow::wheelEvent(QWheelEvent *wheelevent) {
+ if (scriptWheelEvent(wheelevent)) return;
+ int j = wheelevent->delta() > 0 ? 4 : 5;
+ if (!(wheelevent->modifiers())) {
+ if (FQTermPref::getInstance()->isWheelSupported_ && isConnected()) {
+ session_->writeStr(directions_[j]);
+ }
+ return ;
+ }
+ //session_->sendMouseState(j, Qt::NoButton, we->state(), we->pos());
+}
+
+//keyboard input event
+void FQTermWindow::keyPressEvent(QKeyEvent *keyevent) {
+ if (keyevent->isAutoRepeat() && !session_->getBuffer()->isAutoRepeatMode()) {
+ FQ_TRACE("sendkey", 5)
+ << "The terminal is set to not allow repeated key events.";
+ keyevent->accept();
+ return;
+ }
+ if (scriptKeyEvent(keyevent))
+ return;
+
+ keyevent->accept();
+
+ if (!isConnected()) {
+ if (keyevent->key() == Qt::Key_Return || keyevent->key() == Qt::Key_Enter) {
+ session_->reconnect();
+ }
+ return ;
+ }
+
+ // stop the tab blinking
+ stopBlink();
+ if (!session_->readyForInput()) {
+ return;
+ }
+ // message replying
+ session_->leaveIdle();
+
+ Qt::KeyboardModifiers modifier = QApplication::keyboardModifiers();
+ int key = keyevent->key();
+ sendKey(key, modifier, keyevent->text());
+}
+/*
+void FQTermWindow::focusInEvent (QFocusEvent *event) {
+ QMainWindow::focusInEvent(event);
+ screen_->setFocus(Qt::OtherFocusReason);
+}
+*/
+
+//connect slot
+void FQTermWindow::connectHost() {
+ pageViewMessage_->display(tr("Not connected"), screen_->mapToPixel(QPoint(1, 1)));
+ session_->setProxy(session_->param().proxyType_,
+ session_->param().isAuthentation_,
+ session_->param().proxyHostName_,
+ session_->param().proxyPort_,
+ session_->param().proxyUserName_,
+ session_->param().proxyPassword_);
+ session_->connectHost(session_->param().hostAddress_, session_->param().port_);
+ config_->setItemValue("global", "lastaddrindex", QString("%1").arg(addressIndex_));
+}
+
+bool FQTermWindow::isConnected() {
+ return session_->isConnected();
+}
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* Telnet State */
+/* */
+/* ------------------------------------------------------------------------ */
+
+void FQTermWindow::sessionUpdated() {
+ refreshScreen();
+ //send a mouse move event to make mouse-related change
+ QMouseEvent* me = new QMouseEvent(
+ QEvent::MouseMove, mapFromGlobal(QCursor::pos()),
+ QCursor::pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
+ QApplication::postEvent(this, me);
+}
+
+void FQTermWindow::requestUserPwd(QString *user, QString *pwd, bool *isOK) {
+ SSHLoginDialog login(user, pwd, this);
+ *isOK = (login.exec() == QDialog::Accepted);
+}
+
+void FQTermWindow::ZmodemState(int type, int value, const char *status) {
+ QString strMsg;
+ //to be completed
+ switch (type) {
+ case RcvByteCount:
+ case SndByteCount:
+ zmodemDialog_->setProgress(value);
+ return;
+ case RcvTimeout:
+ /* receiver did not respond, aborting */
+ strMsg = QString(tr("Time out!"));
+ break;
+ case SndTimeout:
+ /* value is # of consecutive send timeouts */
+ strMsg = QString(tr("Time out after trying %1 times")).arg(value);
+ break;
+ case RmtCancel:
+ /* remote end has cancelled */
+ strMsg = QString(tr("Canceled by remote peer %1")).arg(status);
+ break;
+ case ProtocolErr:
+ /* protocol error has occurred, val=hdr */
+ strMsg = QString(
+ tr("Unhandled header %1 at state %2")).arg(value).arg(status);
+ break;
+ case RemoteMessage:
+ /* message from remote end */
+ strMsg = QString(tr("Msg from remote peer: %1")).arg(status);
+ break;
+ case DataErr:
+ /* data error, val=error count */
+ strMsg = QString(tr("Data errors %1")).arg(value);
+ break;
+ case FileErr:
+ /* error writing file, val=errno */
+ strMsg = QString(tr("Falied to write file"));
+ break;
+ case FileBegin:
+ /* file transfer begins, str=name */
+ FQ_TRACE("window", 1) << "Starting file " << status;
+ zmodemDialog_->setFileInfo(session_->bbs2unicode(status), value);
+ zmodemDialog_->setProgress(0);
+ zmodemDialog_->clearErrorLog();
+ zmodemDialog_->show();
+ zmodemDialog_->setModal(true);
+ return;
+ case FileEnd:
+ /* file transfer ends, str=name */
+ zmodemDialog_->hide();
+ return;
+ case FileSkip:
+ /* file being skipped, str=name */
+ strMsg = QString(tr("Skipping file %1")).arg(status);
+ break;
+ }
+ zmodemDialog_->addErrorLog(strMsg);
+}
+
+// telnet state slot
+void FQTermWindow::TelnetState(int state) {
+ switch (state) {
+ case TSRESOLVING:
+ pageViewMessage_->display(tr("Resolving host name"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSHOSTFOUND:
+ pageViewMessage_->display(tr("Host found"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSHOSTNOTFOUND:
+ pageViewMessage_->display(tr("Host not found"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSCONNECTING:
+ pageViewMessage_->display(tr("Connecting..."), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSHOSTCONNECTED:
+ pageViewMessage_->display(tr("Connected"), screen_->mapToPixel(QPoint(1, 1)));
+ frame_->updateMenuToolBar();
+ break;
+ case TSPROXYCONNECTED:
+ pageViewMessage_->display(tr("Connected to proxy"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSPROXYAUTH:
+ pageViewMessage_->display(tr("Proxy authentation"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSPROXYFAIL:
+ pageViewMessage_->display(tr("Proxy failed"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSREFUSED:
+ pageViewMessage_->display(tr("Connection refused"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSREADERROR:
+ pageViewMessage_->display(tr("Error when reading from server"), screen_->mapToPixel(QPoint(1, 1)),
+ PageViewMessage::Error);
+ break;
+ case TSCLOSED:
+ pageViewMessage_->display(tr("Connection closed"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSCLOSEFINISH:
+ pageViewMessage_->display(tr("Connection close finished"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSCONNECTVIAPROXY:
+ pageViewMessage_->display(tr("Connect to host via proxy"), screen_->mapToPixel(QPoint(1, 1)));
+ break;
+ case TSEGETHOSTBYNAME:
+ pageViewMessage_->display(
+ tr("Error in gethostbyname"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error);
+ break;
+ case TSEINIWINSOCK:
+ pageViewMessage_->display(
+ tr("Error in startup winsock"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error);
+ break;
+ case TSERROR:
+ pageViewMessage_->display(
+ tr("Error in connection"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error);
+ break;
+ case TSPROXYERROR:
+ pageViewMessage_->display(tr("Error in proxy"), screen_->mapToPixel(QPoint(1, 1)), PageViewMessage::Error);
+ break;
+ case TSWRITED:
+ break;
+ }
+}
+
+void FQTermWindow::showSessionErrorMessage(QString reason) {
+ if (reason == tr("User Cancel")) {
+ return;
+ }
+ QMessageBox::critical(this, tr("Session error"), reason);
+}
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* UI Slots */
+/* */
+/* ------------------------------------------------------------------------ */
+
+
+void FQTermWindow::copy() {
+ QClipboard *clipboard = QApplication::clipboard();
+
+ QString selected_text = session_->getBuffer()->getTextSelected(
+ session_->param().isRectSelect_,
+ session_->param().isColorCopy_,
+ parseString((const char*)session_->param().escapeString_.toLatin1()));
+
+ QByteArray cstrText = session_->unicode2bbs(selected_text);
+
+ // TODO_UTF16: avoid this replacement.
+ if (!FQTermPref::getInstance()->escapeString_.isEmpty()) {
+ cstrText.replace(
+ parseString((const char*)session_->param().escapeString_.toLatin1()),
+ parseString(FQTermPref::getInstance()->escapeString_.toLatin1()));
+ }
+ selected_text = session_->bbs2unicode(cstrText);
+
+ // TODO_UTF16: there are three modes: Clipboard, Selection, FindBuffer.
+ clipboard->setText(selected_text, QClipboard::Clipboard);
+ clipboard->setText(selected_text, QClipboard::Selection);
+}
+
+void FQTermWindow::paste() {
+ pasteHelper(true);
+}
+
+void FQTermWindow::writePasting(const QString& content)
+{
+ QByteArray cstrText = session_->unicode2bbs(content);
+
+ // TODO_UTF16: avoid this replacement.
+ if (!FQTermPref::getInstance()->escapeString_.isEmpty()) {
+ cstrText.replace(
+ parseString(FQTermPref::getInstance()->escapeString_.toLatin1()),
+ parseString((const char*)session_->param().escapeString_.toLatin1()));
+ }
+
+ if (session_->param().isAutoWrap_) {
+ // convert to unicode for word wrap
+ QString strText;
+ strText = session_->bbs2unicode(cstrText);
+ // insert '\n' as needed
+ for (uint i = 0; (long)i < strText.length(); i++) {
+ uint j = i;
+ uint k = 0, l = 0;
+ while ((long)j < strText.length() && strText.at(j) != QChar('\n')) {
+ if (FQTermPref::getInstance()->widthToWrapWord_ - (l - k) >= 0
+ && FQTermPref::getInstance()->widthToWrapWord_ - (l - k) < 2) {
+ strText.insert(j, QChar('\n'));
+ k = l;
+ j++;
+ break;
+ }
+ // double byte or not
+ if (strText.at(j).row() == '\0') {
+ l++;
+ } else {
+ l += 2;
+ }
+ j++;
+ }
+ i = j;
+ }
+
+ cstrText = session_->unicode2bbs(strText);
+ }
+
+ session_->write(cstrText, cstrText.length());
+}
+
+void FQTermWindow::pasteHelper(bool clip) {
+ if (!isConnected()) {
+ return ;
+ }
+
+ // TODO_UTF16: there are three modes: Clipboard, Selection, FindBuffer.
+ QClipboard *clipboard = QApplication::clipboard();
+
+ // TODO_UTF16: what's the termFrame_->clipboardEncodingID_?
+ /*
+ if (termFrame_->clipboardEncodingID_ == 0) {
+ if (clip) {
+ cstrText = U2G(clipboard->text(QClipboard::Clipboard));
+ }
+ else {
+ cstrText = U2G(clipboard->text(QClipboard::Selection));
+ }
+
+ if (session_->param().serverEncodingID_ == 1) {
+ char *str = encodingConverter_.G2B(cstrText, cstrText.length());
+ cstrText = str;
+ delete [] str;
+ }
+ } else {
+ if (clip) {
+ cstrText = U2B(clipboard->text(QClipboard::Clipboard));
+ } else {
+ cstrText = U2B(clipboard->text(QClipboard::Selection));
+ }
+
+ if (session_->param().serverEncodingID_ == 0) {
+ char *str = encodingConverter_.B2G(cstrText, cstrText.length());
+ cstrText = str;
+ delete [] str;
+ }
+ }
+ */
+
+ QString clipStr;
+
+ if (clip) {
+ clipStr = clipboard->text(QClipboard::Clipboard);
+ } else {
+ clipStr = clipboard->text(QClipboard::Selection);
+ }
+
+ writePasting(clipStr);
+}
+
+void FQTermWindow::openAsUrl() {
+ QString selected_text = session_->getBuffer()->getTextSelected(
+ session_->param().isRectSelect_,
+ session_->param().isColorCopy_,
+ parseString((const char*)session_->param().escapeString_.toLatin1()));
+ openUrl(selected_text);
+}
+
+void FQTermWindow::searchIt()
+{
+ script_engine_->runScript(getPath(RESOURCE) + "script/search.js");
+ QScriptValueList qvl;
+ qvl << FQTermPref::getInstance()->searchEngine_;
+ if (!script_engine_->scriptCallback("searchSelected", qvl)) {
+ //fall back to google.
+ QString selected_text = session_->getBuffer()->getTextSelected(
+ session_->param().isRectSelect_,
+ session_->param().isColorCopy_,
+ parseString((const char*)session_->param().escapeString_.toLatin1()));
+ QString searchUrl = "http://www.google.com/search?client=fqterm&rls=en&q=" + selected_text + "&sourceid=fqterm";
+ QByteArray url = QUrl(searchUrl).toEncoded();
+ openUrlImpl(url);
+ }
+}
+
+void FQTermWindow::shareIt()
+{
+ script_engine_->runScript(getPath(RESOURCE) + "script/weiboshare.js");
+}
+
+void FQTermWindow::fastPost()
+{
+ QClipboard *clipboard = QApplication::clipboard();
+ QString clipStr = clipboard->text(QClipboard::Clipboard);
+ QString lineEnd("\n");
+ QString postTitle = clipStr.left(clipStr.indexOf(lineEnd));
+
+ sendParsedString("^p");
+ writeRawString(postTitle);
+ writeRawString(QString("\n\n"));
+ writePasting(clipStr);
+ sendParsedString("^W\n");
+}
+
+
+void FQTermWindow::externalEditor() {
+ externalEditor_->start();
+}
+
+
+void FQTermWindow::externalEditorDone(const QString& str) {
+ QByteArray rawStr = session_->unicode2bbs_smart(str);
+ session_->write(rawStr, rawStr.length());
+}
+
+
+void FQTermWindow::copyArticle() {
+ if (!isConnected()) {
+ return ;
+ }
+
+ session_->copyArticle();
+}
+
+void FQTermWindow::setColor() {
+ addrDialog set(this, session_->param());
+
+ set.setCurrentTabIndex(addrDialog::Display);
+ int res = set.exec();
+ if (res != 0) {
+ updateSetting(set.param());
+ if (res == 2)
+ saveSetting(false);
+ }
+
+}
+
+void FQTermWindow::disconnect() {
+ session_->close();
+
+ connectionClosed();
+}
+
+void FQTermWindow::showIP(bool show) {
+ pageViewMessage_->hide();
+ if (!show) {
+ return;
+ }
+ QString country, city;
+ QString url = session_->getIP();
+ FQTermIPLocation *ipLocation = FQTermIPLocation::getInstance();
+
+ QRect screenRect = screen_->rect();
+ QPoint messagePos;
+ QRect globalIPRectangle = QRect(screen_->mapToRect(ipRectangle_));
+ QFontMetrics fm(qApp->font());
+ int charHeight = fm.height();
+
+ int midLine = (screenRect.top() + screenRect.bottom()) / 2;
+ int ipMidLine = (globalIPRectangle.top() + globalIPRectangle.bottom()) / 2;
+ if (ipMidLine < midLine) {
+ // "There is Plenty of Room at the Bottom." -- Feyman, 1959
+ messagePos.setY(globalIPRectangle.bottom() + 0.618 * charHeight);
+ } else {
+ messagePos.setY(globalIPRectangle.top()
+ - 0.618 * charHeight
+ - pageViewMessage_->size().height());
+ }
+
+ QString displayText;
+ if (ipLocation == NULL) {
+ displayText = tr("IP database file does NOT exist");
+ } else if (!ipLocation->getLocation(url, country, city)) {
+ displayText = tr("Invalid IP");
+ } else {
+ displayText = country + " " + city;
+ }
+
+ QRect messageSize(pageViewMessage_->displayCheck(displayText,
+ PageViewMessage::Info));
+ PageViewMessage::Alignment ali;
+ if (messageSize.width() + globalIPRectangle.left() >= screenRect.right()) {
+ //"But There is No Room at the Right" -- Curvelet, 2007
+ messagePos.setX(globalIPRectangle.right());
+ ali = PageViewMessage::TopRight;
+ } else {
+ messagePos.setX(globalIPRectangle.left());
+ ali = PageViewMessage::TopLeft;
+ }
+
+ pageViewMessage_->display(
+ displayText,
+ PageViewMessage::Info,
+ 0, messagePos, ali);
+}
+
+void FQTermWindow::runScript() {
+ // get the previous dir
+ QStringList fileList;
+ FQTermFileDialog fileDialog(config_);
+
+ fileList = fileDialog.getOpenNames("Choose a Javascript file", "JavaScript File (*.js)");
+
+ if (!fileList.isEmpty() && fileList.count() == 1) {
+ runScript(fileList.at(0));
+ }
+}
+
+void FQTermWindow::stopScript() {
+ script_engine_->stopScript();
+}
+
+void FQTermWindow::viewMessages() {
+ msgDialog msg(this);
+
+ QByteArray dlgSize =
+// frame_->config()->getItemValue("global", "msgdialog").toLatin1();
+ config_->getItemValue("global", "msgdialog").toLatin1();
+ const char *dsize = dlgSize.constData();
+ if (!dlgSize.isEmpty()) {
+ int x, y, cx, cy;
+ sscanf(dsize, "%d %d %d %d", &x, &y, &cx, &cy);
+ msg.resize(QSize(cx, cy));
+ msg.move(QPoint(x, y));
+ } else {
+ msg.resize(QSize(300, 500));
+ msg.move(QPoint(20,20));
+ }
+
+ msg.setMessageText(allMessages_);
+ msg.exec();
+
+ QString strSize = QString("%1 %2 %3 %4").arg(msg.x()).arg(msg.y()).arg
+ (msg.width()).arg(msg.height());
+// frame_->config()->setItemValue("global", "msgdialog", strSize);
+ config_->setItemValue("global", "msgdialog", strSize);
+}
+
+void FQTermWindow::setting() {
+ addrDialog set(this, session_->param());
+ int res = set.exec();
+ if (res != 0) {
+ updateSetting(set.param());
+ if (res == 2)
+ saveSetting(false);
+ }
+}
+
+void FQTermWindow::toggleAntiIdle() {
+ session_->setAntiIdle(!session_->isAntiIdle());
+}
+
+void FQTermWindow::toggleAutoReply() {
+ session_->setAutoReply(!session_->isAutoReply());
+}
+
+void FQTermWindow::toggleAutoReconnect() {
+ session_->setAutoReconnect(!session_->param().isAutoReconnect_);
+}
+
+void FQTermWindow::connectionClosed() {
+ stopBlink();
+
+ pageViewMessage_->display(tr("Connection closed"), screen_->mapToPixel(QPoint(1, 1)));
+
+ frame_->updateMenuToolBar();
+
+ setCursor(cursors_[FQTermSession::kNormal]);
+
+ refreshScreen();
+
+ if (!getSession()->param().isAutoReconnect_ && getSession()->param().isAutoCloseWin_) {
+ emit(connectionClosed(this));
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* Events */
+/* */
+/* ------------------------------------------------------------------------ */
+
+void FQTermWindow::articleCopied(int e, const QString content) {
+ if (e == DAE_FINISH) {
+// articleDialog article(frame_->config(), this);
+ articleDialog article(config_, this);
+
+ // Fix focus-losing bug.
+ // dsize should be a pointer to a non-temprary object.
+ QByteArray dlgSize =
+// frame_->config()->getItemValue("global", "articledialog").toLatin1();
+ config_->getItemValue("global", "articledialog").toLatin1();
+
+ const char *dsize = dlgSize.constData();
+
+ if (!dlgSize.isEmpty()) {
+ int x, y, cx, cy;
+ sscanf(dsize, "%d %d %d %d", &x, &y, &cx, &cy);
+ article.resize(QSize(cx, cy));
+ article.move(QPoint(x, y));
+ } else {
+ article.resize(QSize(300, 500));
+ article.move(20,20);
+ }
+ article.articleText_ = content;
+
+ article.ui_.textBrowser->setPlainText(article.articleText_);
+ article.exec();
+ QString strSize = QString("%1 %2 %3 %4").arg(article.x()).arg(article.y())
+ .arg(article.width()).arg(article.height());
+// frame_->config()->setItemValue("global", "articledialog", strSize);
+ config_->setItemValue("global", "articledialog", strSize);
+ } else if (e == DAE_TIMEOUT) {
+ QMessageBox::warning(this, "timeout", "download article timeout, aborted");
+#ifdef HAVE_PYTHON
+ } else if (e == PYE_ERROR) {
+ QMessageBox::warning(this, "Python script error", pythonErrorMessage_);
+ } else if (e == PYE_FINISH) {
+ QMessageBox::information(this, "Python script finished",
+ "Python script file executed successfully");
+#endif //HAVE_PYTHON
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* Aux Func */
+/* */
+/* ------------------------------------------------------------------------ */
+
+QByteArray FQTermWindow::parseString(const QByteArray &cstr, int *len) {
+ QByteArray parsed = "";
+
+ if (len != 0) {
+ *len = 0;
+ }
+
+ for (uint i = 0; (long)i < cstr.length(); i++) {
+ if (cstr.at(i) == '^') {
+ i++;
+ if ((long)i < cstr.length()) {
+ parsed += FQTERM_CTRL(cstr.at(i));
+ if (len != 0) {
+ *len = *len + 1;
+ }
+ }
+ } else if (cstr.at(i) == '\\') {
+ i++;
+ if ((long)i < cstr.length()) {
+ if (cstr.at(i) == 'n') {
+ parsed += CHAR_CR;
+ } else if (cstr.at(i) == 'r') {
+ parsed += CHAR_LF;
+ } else if (cstr.at(i) == 't') {
+ parsed += CHAR_TAB;
+ }
+ if (len != 0) {
+ *len = *len + 1;
+ }
+ }
+ } else {
+ parsed += cstr.at(i);
+ if (len != 0) {
+ *len = *len + 1;
+ }
+ }
+ }
+
+ return parsed;
+}
+
+void FQTermWindow::messageAutoReplied() {
+ pageViewMessage_->display("You have messages", PageViewMessage::Info, 0);
+}
+
+void FQTermWindow::saveSetting(bool ask /* = true*/) {
+ if (addressIndex_ == -1) {
+ return ;
+ }
+
+ //save these options silently
+ FQTermConfig pConf(getPath(USER_CONFIG) + "address.cfg");
+ FQTermParam param;
+ loadAddress(&pConf, addressIndex_, param);
+ param.isAutoCopy_ = session_->param().isAutoCopy_;
+ param.isAutoWrap_ = session_->param().isAutoWrap_;
+ param.isRectSelect_ = session_->param().isRectSelect_;
+ param.isColorCopy_ = session_->param().isColorCopy_;
+ saveAddress(&pConf, addressIndex_, param);
+ pConf.save(getPath(USER_CONFIG) + "address.cfg");
+
+ if (param == session_->param()) {
+ return;
+ }
+
+ QMessageBox mb("FQTerm", "Setting changed do you want to save it?",
+ QMessageBox::Warning, QMessageBox::Yes | QMessageBox::Default,
+ QMessageBox::No | QMessageBox::Escape, 0, this);
+ if (!ask || mb.exec() == QMessageBox::Yes) {
+ saveAddress(&pConf, addressIndex_, session_->param());
+ pConf.save(getPath(USER_CONFIG) + "address.cfg");
+ }
+}
+
+int FQTermWindow::externInput(const QByteArray &cstrText) {
+ QByteArray cstrParsed = parseString(cstrText);
+ return session_->write(cstrParsed, cstrParsed.length());
+}
+
+int FQTermWindow::externInput(const QString &cstrText) {
+ return externInput(session_->unicode2bbs_smart(cstrText));
+}
+
+int FQTermWindow::writeRawString(const QString& str) {
+ QByteArray rawStr = session_->unicode2bbs_smart(str);
+ return session_->write(rawStr, rawStr.length());
+}
+
+void FQTermWindow::sendParsedString(const char *str) {
+ int length;
+ QByteArray cstr = parseString(str, &length);
+ session_->write(cstr, length);
+}
+
+
+bool FQTermWindow::postQtScriptCallback(const QString& func, const QScriptValueList & args) {
+ return script_engine_->scriptCallback(func, args);
+}
+
+#ifdef HAVE_PYTHON
+bool FQTermWindow::postPythonCallback( const QString& func, PyObject* pArgs )
+{
+ return pythonCallback(func, pArgs);
+}
+#endif //HAVE_PYTHON
+
+// void FQTermWindow::setMouseMode(bool on) {
+// isMouseX11_ = on;
+// }
+
+// /* 0-left 1-middle 2-right 3-relsase 4/5-wheel
+// *
+// */
+// //void FQTermWindow::sendMouseState( int num,
+// // Qt::ButtonState btnstate, Qt::ButtonState keystate, const QPoint& pt )
+// void FQTermWindow::sendMouseState(int num, Qt::KeyboardModifier btnstate,
+// Qt::KeyboardModifier keystate, const QPoint &pt) {
+// /*
+// if(!m_bMouseX11)
+// return;
+//
+// QPoint ptc = screen_->mapToChar(pt);
+//
+// if(btnstate&Qt::LeftButton)
+// num = num==0?0:num;
+// else if(btnstate&Qt::MidButton)
+// num = num==0?1:num;
+// else if(btnstate&Qt::RightButton)
+// num = num==0?2:num;
+//
+// int state = 0;
+// if(keystate&Qt::ShiftModifier)
+// state |= 0x04;
+// if(keystate&Qt::MetaModifier)
+// state |= 0x08;
+// if(keystate&Qt::ControlModifier)
+// state |= 0x10;
+//
+// // normal buttons are passed as 0x20 + button,
+// // mouse wheel (buttons 4,5) as 0x5c + button
+// if(num>3) num += 0x3c;
+//
+// char mouse[10];
+// sprintf(mouse, "\033[M%c%c%c",
+// num+state+0x20,
+// ptc.x()+1+0x20,
+// ptc.y()+1+0x20);
+// m_pTelnet->write( mouse, strlen(mouse) );
+// */
+// }
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* Python Func */
+/* */
+/* ------------------------------------------------------------------------ */
+#ifdef HAVE_PYTHON
+
+
+void FQTermWindow::runPythonScript() {
+ QStringList fileList;
+ FQTermFileDialog fileDialog(config_);
+
+ fileList = fileDialog.getOpenNames("Choose a Python file", "Python File (*.py)");
+
+ if (!fileList.isEmpty() && fileList.count() == 1) {
+ runPythonScriptFile(fileList.at(0));
+ }
+}
+
+void FQTermWindow::runPythonScriptFile(const QString& file) {
+ QString str(QString("%1").arg(long(this)));
+ char* lp = fq_strdup(str.toUtf8().data());
+ char *argv[2]={lp,NULL};
+ // get the global python thread lock
+ PyEval_AcquireLock();
+
+ PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp;
+
+ // create a thread state object for this thread
+ PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
+ PyThreadState_Swap(myThreadState);
+
+
+ PySys_SetArgv(1, argv);
+
+ runPythonFile(file);
+
+ //Clean up this thread's python interpreter reference
+ PyThreadState_Swap(NULL);
+ PyThreadState_Clear(myThreadState);
+ PyThreadState_Delete(myThreadState);
+ PyEval_ReleaseLock();
+ free((void*)lp);
+}
+
+bool FQTermWindow::pythonCallback(const QString & func, PyObject* pArgs) {
+ if(!pythonScriptLoaded_) {
+ Py_DECREF(pArgs);
+ return false;
+ };
+
+ bool done = false;
+ // get the global lock
+ PyEval_AcquireLock();
+ // get a reference to the PyInterpreterState
+
+ //Python thread references
+
+ PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp;
+ // create a thread state object for this thread
+ PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
+ PyThreadState_Swap(myThreadState);
+
+ PyObject *pF = PyString_FromString(func.toUtf8());
+ PyObject *pFunc = PyDict_GetItem(pDict, pF);
+ Py_DECREF(pF);
+
+ if (pFunc && PyCallable_Check(pFunc))
+ {
+ PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
+ Py_DECREF(pArgs);
+ if (pValue != NULL)
+ {
+ if (PyBool_Check(pValue) && pValue == Py_True)
+ done = true;
+ Py_DECREF(pValue);
+ }
+ else
+ {
+ //QMessageBox::warning(this,"Python script error", getException());
+ printf("%p: Python script error\n", this, getException().toUtf8().data());
+ }
+ }
+ else
+ {
+ PyErr_Print();
+ printf("Cannot find python %s callback function\n", func.toUtf8().data());
+ }
+
+ // swap my thread state out of the interpreter
+ PyThreadState_Swap(NULL);
+ // clear out any cruft from thread state object
+ PyThreadState_Clear(myThreadState);
+ // delete my thread state object
+ PyThreadState_Delete(myThreadState);
+ // release the lock
+ PyEval_ReleaseLock();
+
+ if (func == "autoReply")
+ startBlink();
+
+ return done;
+}
+
+
+int FQTermWindow::runPythonFile( const QString& file )
+{
+ QString buffer("def work_thread():\n"
+ "\ttry:\n\t\texecfile('");
+ buffer += QString(file).replace("\\", "\\\\");
+
+ /* Have to do it like this. PyRun_SimpleFile requires you to pass a
+ * stdio file pointer, but Vim and the Python DLL are compiled with
+ * different options under Windows, meaning that stdio pointers aren't
+ * compatible between the two. Yuk.
+ *
+ * Put the string "execfile('file')" into buffer. But, we need to
+ * escape any backslashes or single quotes in the file name, so that
+ * Python won't mangle the file name.
+ * ---- kafa
+ */
+
+ /* Put in the terminating "')" and a null */
+ buffer += "',{})\n\0";
+
+ buffer += QString("\texcept:\n"
+ "\t\texc, val, tb = sys.exc_info()\n"
+ "\t\tlines = traceback.format_exception(exc, val, tb)\n"
+ "\t\terr = string.join(lines)\n"
+ "\t\tprint err\n"
+ "\t\tf=open('%1','w')\n"
+ "\t\tf.write(err)\n"
+ "\t\tf.close()\n").arg(getErrOutputFile(this));
+
+ buffer += QString("\t\tfqterm.formatError(%1)\n").arg((long)this);
+ buffer += "\t\texit\n";
+
+ /* Execute the file */
+ PyRun_SimpleString("import thread,string,sys,traceback,fqterm");
+ PyRun_SimpleString(buffer.toUtf8());
+ PyRun_SimpleString( "thread.start_new_thread(work_thread,())\n");
+
+ return 0;
+}
+
+void FQTermWindow::initPython(const QString& file) {
+
+ // get the global python thread lock
+ PyEval_AcquireLock();
+
+ // get a reference to the PyInterpreterState
+ PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp;
+
+
+
+ // create a thread state object for this thread
+ PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
+ PyThreadState_Swap(myThreadState);
+
+ Py_InitModule4("fqterm", fqterm_methods,
+ NULL,(PyObject*)NULL,PYTHON_API_VERSION);
+
+ PyImport_AddModule("fqterm");
+
+ if(!file.isEmpty() )
+ {
+ QFileInfo info(file);
+ PyRun_SimpleString("import sys");
+ PyRun_SimpleString(QString("sys.path.append(\"%1/\")").arg(info.absolutePath()).toUtf8().data());
+ PyObject *pName = PyString_FromString(info.baseName().toUtf8().data());
+ pModule = PyImport_Import(pName);
+ //PyErr_Print();
+ Py_DECREF(pName);
+ if (pModule != NULL)
+ pDict = PyModule_GetDict(pModule);
+ else
+ {
+ //printf("Failed to PyImport_Import\n");
+ }
+
+ if(pDict != NULL )
+ pythonScriptLoaded_ = true;
+ else
+ {
+ //printf("Failed to PyModule_GetDict\n");
+ }
+ }
+
+ //Clean up this thread's python interpreter reference
+ PyThreadState_Swap(NULL);
+ PyThreadState_Clear(myThreadState);
+ PyThreadState_Delete(myThreadState);
+ PyEval_ReleaseLock();
+
+}
+
+void FQTermWindow::finalizePython()
+{
+ // get the global python thread lock
+ PyEval_AcquireLock();
+
+ // get a reference to the PyInterpreterState
+ PyInterpreterState * mainInterpreterState = frame_->getPythonHelper()->getPyThreadState()->interp;
+
+ // create a thread state object for this thread
+ PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
+ PyThreadState_Swap(myThreadState);
+
+ //Displose of current python module so we can reload in constructor.
+ if(pModule!=NULL)
+ Py_DECREF(pModule);
+
+ //Clean up this thread's python interpreter reference
+ PyThreadState_Swap(NULL);
+ PyThreadState_Clear(myThreadState);
+ PyThreadState_Delete(myThreadState);
+ PyEval_ReleaseLock();
+}
+
+#endif //HAVE_PYTHON
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* HTTP Func */
+/* */
+/* ------------------------------------------------------------------------ */
+
+void FQTermWindow::openLink() {
+ QString url = session_->getUrl();
+ if (!url.isEmpty()) {
+ openUrlImpl(url);
+ }
+}
+
+void FQTermWindow::saveLink() {
+ QString url = session_->getUrl();
+ if (!url.isEmpty())
+ getHttpHelper(url, false);
+}
+
+void FQTermWindow::openUrl(QString url)
+{
+ QString caption = tr("URL Dialog");
+ QString strUrl = url;
+ QTextEdit *textEdit = new QTextEdit();
+ textEdit->setPlainText(strUrl);
+ //textEdit->setFocus();
+ textEdit->setTabChangesFocus(true);
+ textEdit->moveCursor(QTextCursor::End);
+
+
+ QPushButton *okButton = new QPushButton(tr("&Open URL"));
+ QPushButton *cancelButton = new QPushButton(tr("&Cancel"));
+// okButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+// cancelButton->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+
+
+ QGridLayout *layout = new QGridLayout;
+ layout->addWidget(textEdit, 0, 0, 1, -1);
+ layout->addWidget(okButton, 1, 3);
+ layout->addWidget(cancelButton, 1, 4);
+
+ QDialog dlg(this);
+
+ QFontMetrics fm(qApp->font());
+
+
+ connect(okButton, SIGNAL(pressed()), &dlg, SLOT(accept()));
+ connect(cancelButton, SIGNAL(pressed()), &dlg, SLOT(reject()));
+
+
+ dlg.setWindowTitle(caption);
+ dlg.setLayout(layout);
+ dlg.resize(fm.width(QString(30, 'W')), fm.height() * (fm.width(strUrl) / fm.width(QString(30, 'W')) + 5));
+ textEdit->clearFocus();
+ okButton->setFocus(Qt::TabFocusReason);
+ if (dlg.exec()) {
+ openUrlImpl(textEdit->toPlainText());
+ }
+}
+
+
+void FQTermWindow::openUrlImpl(QString url)
+{
+ const QString &httpBrowser = FQTermPref::getInstance()->httpBrowser_;
+ if (httpBrowser.isNull() || httpBrowser.isEmpty()) {
+#if QT_VERSION >= 0x040400
+ QDesktopServices::openUrl(QUrl::fromEncoded(url.toLocal8Bit()));
+#else
+ QDesktopServices::openUrl(url);
+#endif
+ } else {
+ runProgram(httpBrowser, url);
+ }
+}
+
+
+void FQTermWindow::previewLink() {
+ getHttpHelper(session_->getUrl(), true);
+}
+
+void FQTermWindow::copyLink() {
+ QString strUrl;
+ strUrl = session_->bbs2unicode(session_->getUrl().toLatin1());
+
+ QClipboard *clipboard = QApplication::clipboard();
+
+ clipboard->setText(strUrl, QClipboard::Selection);
+ clipboard->setText(strUrl, QClipboard::Clipboard);
+}
+
+void FQTermWindow::getHttpHelper(const QString &url, bool preview) {
+
+ const QString &strPool = FQTermPref::getInstance()->poolDir_;
+
+ FQTermHttp *http = new FQTermHttp(config_, this, strPool, session_->param().serverEncodingID_);
+ if (getSession()->param().proxyType_ != 0) {
+ QString host = getSession()->param().proxyHostName_;
+ int port = getSession()->param().proxyPort_;
+ bool auth = getSession()->param().isAuthentation_;
+ QString user = auth ? getSession()->param().proxyUserName_ : QString();
+ QString pass = auth ? getSession()->param().proxyPassword_ : QString();
+ switch (getSession()->param().proxyType_)
+ {
+ case 1:
+ case 2:
+ //no support in qt.
+ FQ_TRACE("network", 0) << "proxy type not supported by qt, download will not use proxy.";
+ break;
+ case 3:
+ http->setProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, host, port, user, pass));
+ break;
+ case 4:
+ http->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, host, port, user, pass));
+ break;
+ }
+ }
+ FQTerm::StatusBar::instance()->newProgressOperation(http).setDescription(tr("Waiting header...")).setAbortSlot(http, SLOT(cancel())).setMaximum(100);
+ FQTerm::StatusBar::instance()->resetMainText();
+ FQTerm::StatusBar::instance()->setProgress(http, 0);
+
+ FQ_VERIFY(connect(http, SIGNAL(headerReceived(FQTermHttp *, const QString &)),
+ this, SLOT(startHttpDownload(FQTermHttp*,const QString&))));
+
+ FQ_VERIFY(connect(http,SIGNAL(done(QObject*)),this,SLOT(httpDone(QObject*))));
+
+ FQ_VERIFY(connect(http, SIGNAL(message(const QString &)),
+ pageViewMessage_, SLOT(showText(const QString &))));
+
+ FQ_VERIFY(connect(http, SIGNAL(done(QObject*)),
+ FQTerm::StatusBar::instance(),
+ SLOT(endProgressOperation(QObject*))));
+
+ FQ_VERIFY(connect(http, SIGNAL(percent(int)),
+ FQTerm::StatusBar::instance(), SLOT(setProgress(int))));
+
+ FQ_VERIFY(connect(http, SIGNAL(previewImage(const QString &, bool, bool)),
+ this, SLOT(httpPreviewImage(const QString &, bool, bool))));
+
+
+ http->getLink(url, preview);
+}
+
+void FQTermWindow::startHttpDownload(
+ FQTermHttp *pHttp, const QString &filedesp) {
+ FQTerm::StatusBar::instance()->newProgressOperation(pHttp).setDescription
+ (filedesp).setAbortSlot(pHttp, SLOT(cancel())).setMaximum(100);
+
+ FQTerm::StatusBar::instance()->resetMainText();
+}
+
+void FQTermWindow::httpDone(QObject *pHttp) {
+ pHttp->deleteLater();
+}
+
+void FQTermWindow::httpPreviewImage(const QString &filename, bool raiseViewer, bool done)
+{
+ if (config_->getItemValue("preference", "image").isEmpty() || done) {
+ previewImage(filename, raiseViewer);
+ }
+}
+
+void FQTermWindow::previewImage(const QString &filename, bool raiseViewer) {
+// QString strViewer = frame_->config()->getItemValue("preference", "image");
+ QString strViewer = config_->getItemValue("preference", "image");
+
+ if (strViewer.isEmpty()) {
+ frame_->viewImages(filename, raiseViewer);
+ } else if(raiseViewer) {
+ runProgram(strViewer, filename);
+ }
+
+}
+
+void FQTermWindow::beep() {
+ if (session_->param().isBeep_) {
+ if (session_->param().isBuzz_) {
+ frame_->buzz(this);
+ }
+ if (FQTermPref::getInstance()->beepSoundFileName_.isEmpty() ||
+ FQTermPref::getInstance()->openBeep_ == 3) {
+ qApp->beep();
+ }
+ else {
+ sound_ = NULL;
+
+ switch (FQTermPref::getInstance()->beepMethodID_) {
+ case 0:
+ sound_ =
+ new FQTermSystemSound(FQTermPref::getInstance()->beepSoundFileName_);
+ break;
+ case 1:
+ sound_ =
+ new FQTermExternalSound(FQTermPref::getInstance()->beepPlayerName_,
+ FQTermPref::getInstance()->beepSoundFileName_);
+ break;
+ }
+
+ if (sound_) {
+ sound_->start();
+ }
+ }
+ }
+
+ QString strMsg = session_->getMessage();
+ if (!strMsg.isEmpty()) {
+ allMessages_ += strMsg + "\n\n";
+ }
+
+ session_->setSendingMessage();
+}
+
+
+void FQTermWindow::onTitleSet(const QString& title) {
+ setWindowTitle(title);
+}
+
+
+void FQTermWindow::startBlink() {
+ if (FQTermPref::getInstance()->openTabBlinking_) {
+ if (!tabBlinkTimer_->isActive()) {
+ tabBlinkTimer_->start(500);
+ }
+ }
+}
+
+void FQTermWindow::stopBlink() {
+ if (tabBlinkTimer_->isActive()) {
+ tabBlinkTimer_->stop();
+ emit blinkTheTab(this, TRUE);
+ }
+}
+
+void FQTermWindow::setCursorType(const QPoint& mousePosition) {
+ QRect rcOld;
+ bool isUrl = false;
+ if (FQTermPref::getInstance()->openUrlCheck_) {
+ showIP(session_->isIP(ipRectangle_, rcOld));
+ if (session_->isUrl(urlRectangle_, rcOld)) {
+ setCursor(Qt::PointingHandCursor);
+ isUrl = true;
+ }
+ }
+ if (!isUrl) {
+ FQTermSession::CursorType cursorType =
+ session_->getCursorType(screen_->mapToChar(mousePosition));
+ setCursor(cursors_[cursorType]);
+ }
+}
+
+void FQTermWindow::setCursorPosition(const QPoint& mousePosition) {
+ // set cursor pos, repaint if state changed
+ QRect rc;
+ if (session_->setCursorPos(screen_->mapToChar(mousePosition), rc)) {
+ screen_->repaint(screen_->mapToRect(rc));
+
+ //re-check whether the cursor is still on the selected rectangle -- dp
+ QPoint localPos = mapFromGlobal(QCursor::pos()); //local.
+ if (!session_->getMenuRect().contains(screen_->mapToChar(localPos)))
+ {
+ QRect dummyRect;
+ rc = session_->getMenuRect();
+ session_->setCursorPos(screen_->mapToChar(localPos), dummyRect);
+ screen_->repaint(screen_->mapToRect(rc));
+ //restore the state.
+ session_->setCursorPos(screen_->mapToChar(mousePosition), dummyRect);
+ }
+ }
+}
+
+void FQTermWindow::refreshScreen() {
+ screen_->setPaintState(FQTermScreen::NewData);
+ screen_->update();
+}
+
+void FQTermWindow::repaintScreen() {
+
+ screen_->setPaintState(FQTermScreen::Repaint);
+ if (clientRect_ != QRect()) {
+ screen_->repaint(screen_->mapToRect(clientRect_));
+ } else {
+ screen_->repaint();
+ }
+ clientRect_ = QRect();
+// screen_->update(clientRect_);
+}
+
+void FQTermWindow::enterMenuItem() {
+ char cr = CHAR_CR;
+ QRect rc = session_->getMenuRect();
+ FQTermSession::PageState ps = session_->getPageState();
+ switch (ps) {
+ case FQTermSession::Menu:
+ case FQTermSession::MailMenu:
+ case FQTermSession::TOP10:
+ if (!rc.isEmpty()) {
+ char cMenu = session_->getMenuChar();
+ session_->write(&cMenu, 1);
+ session_->write(&cr, 1);
+ }
+ break;
+ case FQTermSession::ArticleList:
+ case FQTermSession::BoardList:
+ case FQTermSession::FriendMailList:
+ case FQTermSession::EliteArticleList:
+ if (!rc.isEmpty()) {
+ int n = rc.y() - session_->getBuffer()->getCaretLine();
+ // scroll lines
+ int cursorType = n>0?FQTermSession::kDown:FQTermSession::kUp;
+ n = qAbs(n);
+ while (n) {
+ session_->write(directions_[cursorType], 4);
+ n--;
+ }
+ }
+ session_->write(&cr, 1);
+ break;
+ default:
+ // TODO: process other PageState.
+ break;
+ }
+}
+
+void FQTermWindow::processLClick(const QPoint& cellClicked) {
+ int cursorType = session_->getCursorType(cellClicked);
+ switch(cursorType)
+ {
+ case FQTermSession::kHome:
+ case FQTermSession::kEnd:
+ case FQTermSession::kPageUp:
+ case FQTermSession::kPageDown:
+ session_->writeStr(directions_[cursorType]);
+ break;
+ case FQTermSession::kUp:
+ case FQTermSession::kDown:
+ case FQTermSession::kLeft:
+ session_->writeStr(directions_[cursorType]);
+ break;
+ case FQTermSession::kRight: //Hand
+ enterMenuItem();
+ break;
+ case FQTermSession::kNormal:
+ char cr = CHAR_CR;
+ session_->write(&cr, 1);
+ break;
+ }
+}
+
+void FQTermWindow::startSelecting(const QPoint& mousePosition) {
+ // clear the selected before
+ session_->clearSelect();
+ sessionUpdated();
+
+ // set the selecting flag
+ isSelecting_ = true;
+ lastMouseCell_ = screen_->mapToChar(mousePosition);
+}
+
+void FQTermWindow::onSelecting(const QPoint& mousePosition) {
+ if (mousePosition.y() < childrenRect().top()) {
+ screen_->scrollLine(-1);
+ }
+ if (mousePosition.y() > childrenRect().bottom()) {
+ screen_->scrollLine(1);
+ }
+
+ QPoint curMouseCell = screen_->mapToChar(mousePosition);
+ session_->setSelect(lastMouseCell_, curMouseCell);
+ sessionUpdated();
+}
+
+void FQTermWindow::finishSelecting(const QPoint& mousePosition) {
+ QPoint currentMouseCell = screen_->mapToChar(mousePosition);
+ session_->setSelect(currentMouseCell, lastMouseCell_);
+ refreshScreen();
+ if (session_->param().isAutoCopy_) {
+ copy();
+ }
+ isSelecting_ = false;
+}
+
+void FQTermWindow::sendKey(const int keyCode, const Qt::KeyboardModifiers modifier,
+ const QString &t) {
+ if (keyCode == Qt::Key_Shift || keyCode == Qt::Key_Control
+ || keyCode == Qt::Key_Meta || keyCode == Qt::Key_Alt) {
+ return;
+ }
+
+ int key = keyCode;
+ QString text = t;
+
+#ifdef __APPLE__
+ // On Mac, pressing Command Key (Apple Key) will set the ControlModifier flag.
+ bool alt_on = ((modifier & Qt::ControlModifier) || (modifier & Qt::AltModifier));
+ bool ctrl_on = (modifier & Qt::MetaModifier);
+#else
+ bool alt_on = ((modifier & Qt::MetaModifier) || (modifier & Qt::AltModifier));
+ bool ctrl_on = (modifier & Qt::ControlModifier);
+#endif
+ bool shift_on = (modifier & Qt::ShiftModifier);
+
+#ifdef __APPLE__
+ // Bullshit! Qt4.4.0 on Mac generates weird key evnets.
+ // fix them here.
+
+ if (ctrl_on) {
+ static const char char_map[][2] = {
+ {'@', '\x00'}, {'A', '\x01'}, {'B', '\x02'}, {'C', '\x03'}, {'D', '\x04'},
+ {'E', '\x05'}, {'F', '\x06'}, {'G', '\x07'}, {'H', '\x08'}, {'J', '\x0a'},
+ {'K', '\x0b'}, {'L', '\x0c'}, {'N', '\x0e'}, {'O', '\x0f'}, {'P', '\x10'},
+ {'Q', '\x11'}, {'R', '\x12'}, {'S', '\x13'}, {'T', '\x14'}, {'U', '\x15'},
+ {'V', '\x16'}, {'W', '\x17'}, {'X', '\x18'}, {'Y', '\x19'}, {'Z', '\x1a'},
+ {'\\', '\x1c'}, {']', '\x1d'}, {'^', '\x1e'}, {'_', '\x1f'}
+ };
+
+ const int num = sizeof(char_map)/2;
+
+ int expected_key = key;
+
+ for (int i = 0; i < num; ++i) {
+ const char *c = char_map[i];
+ if (c[0] == key) {
+ expected_key = c[1];
+ break;
+ }
+ }
+
+ if (expected_key != key) {
+ FQ_TRACE("sendkey", 5) << "translate the key code from "
+ << (int)key << "(" << (char)key << ")"
+ << " to "
+ << (int)expected_key
+ << "(" << (char)expected_key << ")"
+ << ", and change the text appropriately." ;
+ key = expected_key;
+ text.clear();
+ text.append((char) expected_key);
+ }
+ }
+
+ if (!ctrl_on && alt_on && !shift_on) {
+ if (text.size() == 0 && 0 <= key && key <= 128) {
+ FQ_TRACE("sendkey", 5)
+ << "add appropriate text according to the key code.";
+ text.append((char)key);
+ }
+ }
+
+ if (!ctrl_on && alt_on && shift_on) {
+ // fix the key code when both shift key and meta/alt key are pressed.
+ static const char char_map[][2] = {
+ {'`', '~'}, {'1', '!'}, {'2', '@'}, {'3', '#'}, {'4', '$'},
+ {'5', '%'}, {'6', '^'}, {'7', '&'}, {'8', '*'}, {'9', '('},
+ {'0', ')'}, {'-', '_'}, {'=', '+'}, {'[', '{'}, {']', '}'},
+ {'\\', '|'}, {';', ':'}, {'\'', '"'}, {',', '<'},{'.', '>'},
+ {'/', '?'}
+ };
+ const int num = sizeof(char_map)/2;
+
+ int expected_key = key;
+
+ for (int i = 0; i < num; ++i) {
+ const char *c = char_map[i];
+ if (c[0] == key) {
+ expected_key = c[1];
+ break;
+ }
+ }
+
+ if (expected_key != key) {
+ FQ_TRACE("sendkey", 5) << "translate the key code from "
+ << (int)key << "(" << (char)key << ")"
+ << " to "
+ << (int)expected_key
+ << "(" << (char)expected_key << ")";
+ key = expected_key;
+ }
+
+ if (text.size() == 0) {
+ text.append(key);
+ } else {
+ text[0] = key;
+ }
+ FQ_TRACE("sendkey", 5)
+ << "set the text for this key event as the keycode.";
+ }
+#endif
+
+ FQ_TRACE("sendkey", 5) << "(alt " << (alt_on? " on": "off")
+ << ", ctrl " << (ctrl_on? " on": "off")
+ << ", shift " << (shift_on? " on": "off") << ")"
+ << " key: " << key
+ << " text: " << (text.size() == 0 ? "NULL" : text)
+ << " (in hex: "
+ << dumpHexString << text.toStdString()
+ << dumpNormalString << ")";
+
+ if (session_->getBuffer()->isAnsiMode()) {
+ if (session_->getBuffer()->isCursorMode()) {
+ switch(key) {
+ case Qt::Key_Up:
+ session_->writeStr("\x1bOA");
+ return;
+ case Qt::Key_Down:
+ session_->writeStr("\x1bOB");
+ return;
+ case Qt::Key_Left:
+ session_->writeStr("\x1bOD");
+ return;
+ case Qt::Key_Right:
+ session_->writeStr("\x1bOC");
+ return;
+ }
+ } else {
+ switch(key) {
+ case Qt::Key_Up:
+ session_->writeStr("\x1b[A");
+ return;
+ case Qt::Key_Down:
+ session_->writeStr("\x1b[B");
+ return;
+ case Qt::Key_Left:
+ session_->writeStr("\x1b[D");
+ return;
+ case Qt::Key_Right:
+ session_->writeStr("\x1b[C");
+ return;
+ }
+ }
+ } else {
+ // VT52 mode
+ switch(key) {
+ case Qt::Key_Up:
+ // Do NOT change the parameter to "\x1bA".
+ session_->writeStr("\x1b" "A");
+ return;
+ case Qt::Key_Down:
+ // Do NOT change the parameter to "\x1bB".
+ session_->writeStr("\x1b" "B");
+ return;
+ case Qt::Key_Left:
+ // Do NOT change the parameter to "\x1bD".
+ session_->writeStr("\x1b" "D");
+ return;
+ case Qt::Key_Right:
+ // Do NOT change the parameter to "\x1bC".
+ session_->writeStr("\x1b" "C");
+ return;
+ }
+ }
+
+ if (!session_->getBuffer()->isNumericMode() &&
+ (modifier & Qt::KeypadModifier)) {
+ switch(key) {
+ case Qt::Key_0:
+ case Qt::Key_1:
+ case Qt::Key_2:
+ case Qt::Key_3:
+ case Qt::Key_4:
+ case Qt::Key_5:
+ case Qt::Key_6:
+ case Qt::Key_7:
+ case Qt::Key_8:
+ case Qt::Key_9:
+ {
+ char tmp[] = "\x1bOp";
+ tmp[2] = 'p' + key - Qt::Key_0;
+ session_->writeStr(tmp);
+ }
+ return;
+ case Qt::Key_Plus:
+ session_->writeStr("\x1bOl");
+ return;
+ case Qt::Key_Minus:
+ session_->writeStr("\x1bOm");
+ return;
+ case Qt::Key_Period:
+ session_->writeStr("\x1bOn");
+ return;
+ case Qt::Key_Asterisk:
+ session_->writeStr("\x1bOM");
+ return;
+ }
+ }
+
+ switch (key) {
+ case Qt::Key_Home:
+ session_->writeStr(directions_[0]);
+ return;
+ case Qt::Key_End:
+ session_->writeStr(directions_[1]);
+ return;
+ case Qt::Key_PageUp:
+ session_->writeStr(directions_[2]);
+ return;
+ case Qt::Key_PageDown:
+ session_->writeStr(directions_[3]);
+ return;
+ case Qt::Key_Up:
+ session_->writeStr(directions_[4]);
+ return;
+ case Qt::Key_Down:
+ session_->writeStr(directions_[5]);
+ return;
+ case Qt::Key_Left:
+ session_->writeStr(directions_[6]);
+ return;
+ case Qt::Key_Right:
+ session_->writeStr(directions_[7]);
+ return;
+ case Qt::Key_F1:
+ session_->writeStr("\x1b[11~");
+ return;
+ case Qt::Key_F2:
+ session_->writeStr("\x1b[12~");
+ return;
+ case Qt::Key_F3:
+ session_->writeStr("\x1b[13~");
+ return;
+ case Qt::Key_F4:
+ session_->writeStr("\x1b[14~");
+ return;
+ case Qt::Key_F5:
+ session_->writeStr("\x1b[15~");
+ return;
+ case Qt::Key_F6:
+ session_->writeStr("\x1b[17~");
+ return;
+ case Qt::Key_F7:
+ session_->writeStr("\x1b[18~");
+ return;
+ case Qt::Key_F8:
+ session_->writeStr("\x1b[19~");
+ return;
+ case Qt::Key_F9:
+ session_->writeStr("\x1b[20~");
+ return;
+ case Qt::Key_F10:
+ session_->writeStr("\x1b[21~");
+ return;
+ case Qt::Key_F11:
+ session_->writeStr("\x1b[23~");
+ return;
+ case Qt::Key_F12:
+ session_->writeStr("\x1b[24~");
+ return;
+ }
+
+ if (text.length() > 0) {
+ if (alt_on) {
+ // Use ESC to emulate Alt-XX key.
+ session_->writeStr("\x1b");
+ }
+
+ if (ctrl_on) {
+ switch(key) {
+ case Qt::Key_At: // Ctrl-@
+ case Qt::Key_Space: // Ctrl-SPACE
+ // send NULL
+ session_->write("\x0", 1);
+ return;
+ case Qt::Key_AsciiCircum: // Ctrl-^
+ case Qt::Key_AsciiTilde: // Ctrl-~
+ case Qt::Key_QuoteLeft: // Ctrl-`
+ // send RS
+ session_->write("\x1e", 1);
+ return;
+ case Qt::Key_Underscore: // Ctrl-_
+ case Qt::Key_Question: // Ctrl-?
+ // send US
+ session_->write("\x1f", 1);
+ return;
+ }
+ }
+
+ if (key == Qt::Key_Backspace) {
+ if (shift_on) {
+ session_->writeStr("\x1b[3~");
+ } else {
+ if (session_->param().backspaceType_ == 0)
+ session_->writeStr("\x08");
+ else
+ session_->writeStr("\x7f");
+ }
+ return;
+ }
+
+ if (key == Qt::Key_Delete) {
+ if (shift_on) {
+ if (session_->param().backspaceType_ == 0)
+ session_->writeStr("\x08");
+ else
+ session_->writeStr("\x7f");
+ } else {
+ session_->writeStr("\x1b[3~");
+ }
+ return;
+ }
+
+ if (key == Qt::Key_Return) {
+ if (session_->getBuffer()->isNewLineMode()) {
+ session_->write("\r\n", 2);
+ } else {
+ session_->write("\r", 1);
+ }
+ return;
+ }
+
+ QByteArray cstrTmp = session_->unicode2bbs_smart(text);
+ session_->write(cstrTmp, cstrTmp.length());
+ }
+ return;
+}
+
+void FQTermWindow::forcedRepaintScreen() {
+ QResizeEvent *re = new QResizeEvent(screen_->size(), screen_->size());
+ QApplication::postEvent(screen_, re);
+}
+
+void FQTermWindow::updateSetting(const FQTermParam& param) {
+ session_->updateSetting(param);
+ screen_->setTermFont(true,
+ QFont(param.englishFontName_,
+ param.englishFontSize_));
+ screen_->setTermFont(false,
+ QFont(param.otherFontName_,
+ param.otherFontSize_));
+ screen_->setSchema();
+
+ setWindowTitle(param.name_);
+
+ forcedRepaintScreen();
+}
+
+void FQTermWindow::setFont()
+{
+ bool isEnglish =
+ ((QAction*)(sender()))->data().toBool();
+ setFont(isEnglish);
+}
+
+void FQTermWindow::setFont(bool isEnglish) {
+ bool ok;
+ QString& fontName = isEnglish?session_->param().englishFontName_:session_->param().otherFontName_;
+ int& fontSize = isEnglish?session_->param().englishFontSize_:session_->param().otherFontSize_;
+ QFont font(fontName, fontSize);
+ font = QFontDialog::getFont(&ok, font, this, tr("Font Selector")
+#ifdef __APPLE__
+, QFontDialog::DontUseNativeDialog
+#endif
+ );
+ if (ok == true) {
+ if (FQTermPref::getInstance()->openAntiAlias_) {
+ font.setStyleStrategy(QFont::PreferAntialias);
+ }
+ screen_->setTermFont(isEnglish, font);
+ fontName = font.family();
+ fontSize = font.pointSize();
+ forcedRepaintScreen();
+ }
+}
+
+
+void FQTermWindow::runScript(const QString &filename) {
+ script_engine_->runScript(filename);
+}
+
+//-----------
+static int translateQtModifiers(Qt::KeyboardModifiers modifiers) {
+ int state = 0;
+ if (modifiers &Qt::AltModifier) {
+ state |= SBS_ALT;
+ }
+ if (modifiers &Qt::ControlModifier) {
+ state |= SBS_CTRL;
+ }
+ if (modifiers &Qt::ShiftModifier) {
+ state |= SBS_SHIFT;
+ }
+ return state;
+}
+
+static int translateQtButton(Qt::MouseButtons btnstate) {
+ int state = 0;
+ if(btnstate&Qt::LeftButton)
+ state |= SBS_LEFT_BUTTON;
+ if(btnstate&Qt::RightButton)
+ state |= SBS_RIGHT_BUTTON;
+ if(btnstate&Qt::MidButton)
+ state |= SBS_MID_BUTTON;
+ return state;
+}
+
+bool FQTermWindow::scriptKeyEvent( QKeyEvent *keyevent ){
+ bool res = false;
+ int state = 0;
+ state |= translateQtModifiers(keyevent->modifiers());
+
+ res = postScriptCallback(SFN_KEY_EVENT
+#ifdef HAVE_PYTHON
+ ,Py_BuildValue("liii", this, SKET_KEY_PRESS, state, keyevent->key())
+#endif //HAVE_PYTHON
+ ,QScriptValueList() << SKET_KEY_PRESS << state << keyevent->key());
+ return res;
+}
+
+bool FQTermWindow::scriptMouseEvent(QMouseEvent *mouseevent){
+ int type = SMET_UNKOWN;
+ switch (mouseevent->type())
+ {
+ case QEvent::MouseButtonPress:
+ type = SMET_MOUSE_PRESS;
+ break;
+ case QEvent::MouseButtonRelease:
+ type = SMET_MOUSE_RELEASE;
+ break;
+ case QEvent::MouseButtonDblClick:
+ type = SMET_MOUSE_DBCLICK;
+ break;
+ case QEvent::MouseMove:
+ type = SMET_MOUSE_MOVE;
+ break;
+ }
+
+ int delta = 0;
+ int state=0;
+
+ state |= translateQtButton(mouseevent->button());
+ state |= translateQtModifiers(mouseevent->modifiers());
+
+ QPoint ptc = screen_->mapToChar(mouseevent->pos());
+ ptc.setY(ptc.y() - screen_->getBufferStart());
+ int res = postScriptCallback(SFN_MOUSE_EVENT
+#ifdef HAVE_PYTHON
+ ,Py_BuildValue("liiiii", this, type, state, ptc.x(), ptc.y(),delta)
+#endif //HAVE_PYTHON
+ ,QScriptValueList() << type << state << ptc.x() << ptc.y() << delta);
+ return res;
+}
+
+bool FQTermWindow::scriptWheelEvent( QWheelEvent *wheelevent ) {
+ int type = SMET_WHEEL;
+ int delta = 0;
+ int state=0;
+ state |= translateQtModifiers(wheelevent->modifiers());
+ QPoint ptc = screen_->mapToChar(wheelevent->pos());
+ ptc.setY(ptc.y() - screen_->getBufferStart());
+ int res = postScriptCallback(SFN_MOUSE_EVENT
+#ifdef HAVE_PYTHON
+ ,Py_BuildValue("liiiii", this, type, state, ptc.x(), ptc.y(),wheelevent->delta())
+#endif //HAVE_PYTHON
+ ,QScriptValueList() << type << state << ptc.x() << ptc.y() << wheelevent->delta());
+ return res;
+}
+
+const QString FQTermExternalEditor::textEditName_ = "external editor input";
+
+FQTermExternalEditor::FQTermExternalEditor(QWidget* parent)
+: QObject(parent),
+ editorProcess_(NULL),
+ started_(false) {
+ editorProcess_ = new QProcess(this);
+ FQ_VERIFY(connect(editorProcess_, SIGNAL(stateChanged(QProcess::ProcessState)),
+ this, SLOT(stateChanged(QProcess::ProcessState))));
+ clearTempFileContent();
+}
+
+FQTermExternalEditor::~FQTermExternalEditor() {
+ editorProcess_->kill();
+ QFile::remove(getTempFilename());
+ delete editorProcess_;
+}
+
+void FQTermExternalEditor::execDialog() {
+ QDialog *dialog = new QDialog((QWidget *)parent());
+ QGridLayout *layout = new QGridLayout(dialog);
+ QTextEdit *text = new QTextEdit(dialog);
+ text->setObjectName(textEditName_);
+ layout->addWidget(text);
+ QBoxLayout *rowLayout = new QBoxLayout(QBoxLayout::LeftToRight, dialog);
+ layout->addLayout(rowLayout, 1, 0, Qt::AlignHCenter);
+ QPushButton *ok = new QPushButton(tr("OK"), dialog);
+ QPushButton *cancel = new QPushButton(tr("Cancel"), dialog);
+ rowLayout->addWidget(ok);
+ rowLayout->addWidget(cancel);
+ FQ_VERIFY(connect(ok, SIGNAL(clicked()),
+ dialog, SLOT(accept())));
+ FQ_VERIFY(connect(cancel, SIGNAL(clicked()),
+ dialog, SLOT(reject())));
+ FQ_VERIFY(connect(dialog, SIGNAL(accepted()),
+ this, SLOT(readDialogData())));
+ FQ_VERIFY(connect(dialog, SIGNAL(rejected()),
+ this, SLOT(closeDialog())));
+ dialog->setModal(true);
+ dialog->exec();
+}
+
+void FQTermExternalEditor::readDialogData() {
+ QDialog *dialog = (QDialog*)sender();
+ QTextEdit* edit = (QTextEdit*)dialog->findChild<QTextEdit*>(textEditName_);
+ if (edit) {
+ emit done(edit->toPlainText());
+ }
+ closeDialog();
+}
+
+void FQTermExternalEditor::closeDialog() {
+ sender()->deleteLater();
+}
+
+void FQTermExternalEditor::start() {
+ if (FQTermPref::getInstance()->externalEditor_.isEmpty()) {
+ execDialog();
+ return;
+ }
+ if (started_)
+ return;
+ started_ = true;
+ if (FQTermPref::getInstance()->externalEditorArg_.isEmpty()) {
+ editorProcess_->start(FQTermPref::getInstance()->externalEditor_, QStringList() << getTempFilename());
+ } else {
+ FQ_TRACE("editor", 5) << FQTermPref::getInstance()->externalEditorArg_.arg(getTempFilename());
+ editorProcess_->start(FQTermPref::getInstance()->externalEditor_ + " " + FQTermPref::getInstance()->externalEditorArg_.arg(getTempFilename()));
+ }
+}
+
+
+QString FQTermExternalEditor::getTempFilename() {
+ return getPath(USER_CONFIG) + "tmp_do_not_use.txt";
+}
+
+void FQTermExternalEditor::clearTempFileContent() {
+ QFile file(getTempFilename());
+ file.open(QIODevice::Truncate | QIODevice::WriteOnly);
+ file.write("\xEF\xBB\xBF");
+ file.flush();
+ file.close();
+}
+
+void FQTermExternalEditor::stateChanged( QProcess::ProcessState state ) {
+ //FQ_TRACE("editor", 0) << "stateChanged: " << state << editorProcess_->readAllStandardOutput() << editorProcess_->readAllStandardError();
+ if (!started_ || state != QProcess::NotRunning)
+ return;
+ QFile file(getTempFilename());
+ file.open(QIODevice::ReadOnly);
+ QString result = U82U(file.readAll());
+ file.close();
+#if !defined(WIN32) && !defined(__APPLE__)
+ if (result.endsWith(OS_NEW_LINE)) {
+ result.resize(result.size() - 1);
+ }
+#endif
+ emit done(result);
+ clearTempFileContent();
+ started_ = false;
+}
+} // namespace FQTerm
+#include "fqterm_window.moc"