diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/CMakeLists.txt | 36 | ||||
-rw-r--r-- | src/common/common.cpp | 53 | ||||
-rw-r--r-- | src/common/common.h | 64 | ||||
-rw-r--r-- | src/common/fqterm.h | 350 | ||||
-rw-r--r-- | src/common/fqterm_config.cpp | 181 | ||||
-rw-r--r-- | src/common/fqterm_config.h | 61 | ||||
-rw-r--r-- | src/common/fqterm_exif_extractor.cpp | 647 | ||||
-rw-r--r-- | src/common/fqterm_exif_extractor.h | 126 | ||||
-rw-r--r-- | src/common/fqterm_filedialog.cpp | 157 | ||||
-rw-r--r-- | src/common/fqterm_filedialog.h | 49 | ||||
-rw-r--r-- | src/common/fqterm_font.cpp | 261 | ||||
-rw-r--r-- | src/common/fqterm_font.h | 34 | ||||
-rw-r--r-- | src/common/fqterm_param.cpp | 274 | ||||
-rw-r--r-- | src/common/fqterm_param.h | 221 | ||||
-rw-r--r-- | src/common/fqterm_path.cpp | 601 | ||||
-rw-r--r-- | src/common/fqterm_path.h | 46 | ||||
-rw-r--r-- | src/common/fqterm_shortcuthelper.cpp | 298 | ||||
-rw-r--r-- | src/common/fqterm_shortcuthelper.h | 175 | ||||
-rw-r--r-- | src/common/fqterm_sound.cpp | 733 | ||||
-rw-r--r-- | src/common/fqterm_sound.h | 79 | ||||
-rw-r--r-- | src/common/fqterm_trace.cpp | 328 | ||||
-rw-r--r-- | src/common/fqterm_trace.h | 331 |
22 files changed, 5105 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt new file mode 100644 index 0000000..d3f0c09 --- /dev/null +++ b/src/common/CMakeLists.txt @@ -0,0 +1,36 @@ +set(fqterm_common_SRCS + common.h + common.cpp + fqterm.h + fqterm_trace.h + fqterm_trace.cpp + fqterm_config.h + fqterm_config.cpp + fqterm_sound.h + fqterm_sound.cpp + fqterm_param.h + fqterm_param.cpp + fqterm_path.h + fqterm_path.cpp + fqterm_font.h + fqterm_font.cpp + fqterm_exif_extractor.h + fqterm_exif_extractor.cpp + fqterm_filedialog.h + fqterm_filedialog.cpp + fqterm_shortcuthelper.h + fqterm_shortcuthelper.cpp +) + +qt4_automoc(${fqterm_common_SRCS}) + +include_directories( + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR} + ${QT_QTGUI_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +add_library(fqterm_common + ${fqterm_common_SRCS} +) diff --git a/src/common/common.cpp b/src/common/common.cpp new file mode 100644 index 0000000..ec08bef --- /dev/null +++ b/src/common/common.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** + * 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 <QString> +#include <QProcess> +#include <QStringList> +#include "common.h" + +namespace FQTerm { + +void runProgram(const QString &cmd, const QString& arg, bool bg) { + if (bg) { + QProcess::startDetached(cmd, QStringList(arg)); + } else { + QProcess::execute(cmd, QStringList(arg)); + } + + return; + /* +#if defined(WIN32) + QString strCmd = "\"\"" + cmd + "\" \"" + arg + "\"\""; +#else + QString strCmd = "'" + cmd + "' '" + arg + "'"; +#endif +#if !defined(WIN32) + if (bg) { + strCmd += " &"; + } +#endif + system(strCmd.toLocal8Bit()); + */ +} + +} // namespace FQTerm diff --git a/src/common/common.h b/src/common/common.h new file mode 100644 index 0000000..5720ddc --- /dev/null +++ b/src/common/common.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_COMMON_H +#define FQTERM_COMMON_H + +#if defined(WIN32) +#define OS_NEW_LINE "\r\n" +#elif defined(__APPLE__) +#define OS_NEW_LINE "\r" +#else +#define OS_NEW_LINE "\n" +#endif + +class QString; + +namespace FQTerm { + +enum Directions { + kHome = 0, + kEnd = 1, + kPageUp = 2, + kPageDown = 3, + kUp = 4, + kDown = 5, + kLeft = 6, + kRight = 7 +}; + +const char * const kDirections[] = { + // 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 +}; + +void runProgram(const QString &cmd, const QString& arg = "", bool bg = true); + +} // namespace FQTerm + +#endif // FQTERM_COMMON_H diff --git a/src/common/fqterm.h b/src/common/fqterm.h new file mode 100644 index 0000000..515cedc --- /dev/null +++ b/src/common/fqterm.h @@ -0,0 +1,350 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_GLOBAL_H +#define FQTERM_GLOBAL_H + +#ifndef BUFSIZE +#define BUFSIZE (1024) +#endif + +#include <QTextCodec> +#include <QString> +#include "fqterm_trace.h" + +namespace FQTerm { + +#if defined(WIN32) && (_MSC_VER >= 1400) + //Using vc2005 or + +#define fq_strdup _strdup +#else +#define fq_strdup strdup +#endif + +#ifdef FOUND_PYTHON +//#define HAVE_PYTHON +#endif //FOUND_PYTHON + +#define USE_GLOBAL_HOTKEY + +//code convert +enum EncodingID {FQTERM_ENCODING_GBK = 0, FQTERM_ENCODING_BIG5 = 1, + FQTERM_ENCODING_UTF8 = 2, FQTERM_ENCODING_HKSCS = 3, + FQTERM_ENCODING_UAO = 4}; + +#if QT_VERSION >= 0X040700 +#define GBK_CODECS_NAME "GB18030" +#else +#define GBK_CODECS_NAME "GBK" +#endif + +#define G2U(s) ( QTextCodec::codecForName(GBK_CODECS_NAME)->toUnicode(s) ) +#define U2G(s) ( QTextCodec::codecForName(GBK_CODECS_NAME)->fromUnicode(s) ) +#define B2U(s) ( QTextCodec::codecForName("Big5")->toUnicode(s) ) +#define U2B(s) ( QTextCodec::codecForName("Big5")->fromUnicode(s) ) +#define H2U(s) ( QTextCodec::codecForName("Big5-HKSCS")->toUnicode(s) ) +#define U2H(s) ( QTextCodec::codecForName("Big5-HKSCS")->fromUnicode(s) ) +#define U2U8(s) ( s.toUtf8() ) +#define U82U(s) ( QString::fromUtf8(s) ) +#define A2U(s) (QTextCodec::codecForName("UAO")->toUnicode(s) ) +#define U2A(s) ( QTextCodec::codecForName("UAO")->fromUnicode(s) ) + +inline QByteArray unicode2encoding(const QString &text, int encoding) { + switch(encoding) + { + case FQTERM_ENCODING_GBK: + return(U2G(text)); + case FQTERM_ENCODING_BIG5: + return(U2B(text)); + case FQTERM_ENCODING_UTF8: + return(U2U8(text)); + case FQTERM_ENCODING_HKSCS: + return (U2H(text)); + case FQTERM_ENCODING_UAO: + return (U2A(text)); + } + + return ""; +} + +inline QString encoding2unicode(const QByteArray &text, int encoding) { + switch(encoding) + { + case FQTERM_ENCODING_GBK: + return(G2U(text)); + case FQTERM_ENCODING_BIG5: + return(B2U(text)); + case FQTERM_ENCODING_UTF8: + return(U82U(text)); + case FQTERM_ENCODING_HKSCS: + return (H2U(text)); + case FQTERM_ENCODING_UAO: + return (A2U(text)); + } + + return ""; +} + +#define FQTERM_CTRL(c) ((c)&0x1f) + +// every character has a 16-bit description +// low 8 for colors +// hight 8 for attributes +#define COLORMASK 0x00ff +#define ATTRMASK 0xff00 + +// color 8-bit +// bit 0-2 foreground +// 0 black +// 1 red +// 2 green +// 3 yellow +// 4 blue +// 5 magenta +// 6 cyan +// 7 white +// bit 3 highlight foreground +// 0 no +// 1 highlight +// bit 4-6 background +// 0 black +// 1 red +// 2 green +// 3 yellow +// 4 blue +// 5 magenta +// 6 cyan +// 7 white +// bit 7 highlight background (unused) +// 0 no +// 1 highlight + +#define FGMASK 0x0f +#define BGMASK 0xf0 +#define FG_HIGHLIGHT_MASK 0x08 +#define BG_HIGHLIGHT_MASK 0x80 + +//set color +#define SETFG(c) ( (c) & FGMASK ) +#define SETBG(c) ( ( (c) << 4 ) & BGMASK ) +#define SET_FG_HIGHLIGHT(c) ( ( (c) << 3 ) & FG_HIGHLIGHT_MASK ) +#define SET_BG_HIGHLIGHT(c) ( ( (c) << 7 ) & BG_HIGHLIGHT_MASK ) + +//get color +#define GETFG(c) ( (c) & FGMASK ) +#define GETBG(c) ( ( (c) & BGMASK ) >> 4 ) + +#define GET_FG_HIGHLIGHT(c) ( ( (c) & FG_HIGHLIGHT_MASK ) >> 3 ) +#define GET_BG_HIGHLIGHT(c) ( ( (c) & BG_HIGHLIGHT_MASK ) >> 7 ) + +//#define GET_INVERSE_COLOR(c) ( SETFG( (7 - (c & 0x7)) | (c & 0x08) ) | SETBG(15-GETBG(c)) ) +#define GET_INVERSE_COLOR(c) ( SETFG(15-GETFG(c)) | SETBG(15-GETBG(c)) ) + +// mask for attr +#define BRIGHTMASK 0x01 +#define DIMMASK 0x02 +#define UNDERLINEMASK 0x08 +#define BLINKMASK 0x10 +#define RAPIDBLINKMASK 0x20 +#define REVERSEMASK 0x40 +#define INVISIBLEMASK 0x80 + +//set attributes +#define SETBRIGHT(a) ( (a) | BRIGHTMASK ) +#define SETDIM(a) ( (a) | DIMMASK ) +#define SETUNDERLINE(a) ( (a) | UNDERLINEMASK ) +#define SETBLINK(a) ( (a) | BLINKMASK ) +#define SETRAPIDBLINK(a) ( (a) | RAPIDBLINKMASK ) +#define SETREVERSE(a) ( (a) | REVERSEMASK ) +#define SETINVISIBLE(a) ( (a) | INVISIBLEMASK ) + +//get attributes +#define GETBRIGHT(a) ( (a) & BRIGHTMASK ) +#define GETDIM(a) ( (a) & DIMMASK ) +#define GETUNDERLINE(a) ( (a) & UNDERLINEMASK ) +#define GETBLINK(a) ( (a) & BLINKMASK ) +#define GETRAPIDBLINK(a) ( (a) & RAPIDBLINKMASK ) +#define GETREVERSE(a) ( (a) & REVERSEMASK ) +#define GETINVISIBLE(a) ( (a) & INVISIBLEMASK ) + +//default color +#define NO_COLOR ( SETFG(7) | SETBG(0) ) +//default attribute +#define NO_ATTR 0x04 + +// other definations +#ifndef NULL +#define NULL 0 +#endif + +#define DAE_FINISH 10001 +#define DAE_TIMEOUT 10002 + +#define PYE_ERROR 10003 +#define PYE_FINISH 10004 + +// some keys +#define CHAR_NUL 0x00 // ^@ +#define CHAR_ENQ 0x05 // ^E +#define CHAR_BELL 0x07 // ^G +#define CHAR_BS 0x08 // ^H +#define CHAR_TAB 0x09 // ^I +#define CHAR_LF 0x0a // ^J +#define CHAR_VT 0x0b // ^K +#define CHAR_FF 0x0c // ^L +#define CHAR_CR 0x0d // ^M +#define CHAR_SO 0x0e // ^N +#define CHAR_SI 0x0f // ^O +#define CHAR_CAN 0x18 // ^X +#define CHAR_ESC 0x1b // ^[ +#define CHAR_DEL 0x7f // DEL + +#define CHAR_NORMAL -1 + +const char ANSWERBACK_MESSAGE[] = "This is fqterm."; + +// telnet state +#define TSRESOLVING 30 +#define TSHOSTFOUND 31 +#define TSHOSTNOTFOUND 32 +#define TSCONNECTING 33 +#define TSHOSTCONNECTED 34 +#define TSPROXYCONNECTED 35 +#define TSPROXYAUTH 36 +#define TSPROXYFAIL 38 +#define TSREFUSED 39 +#define TSREADERROR 40 +#define TSCLOSED 41 +#define TSCLOSEFINISH 42 +#define TSCONNECTVIAPROXY 43 +#define TSEGETHOSTBYNAME 44 +#define TSEINIWINSOCK 45 +#define TSERROR 46 +#define TSPROXYERROR 47 +#define TSWRITED 48 + +// zmodem types +#define RcvByteCount 0 /* value is # bytes received */ +#define SndByteCount 1 /* value is # bytes sent */ +#define RcvTimeout 2 /* receiver did not respond, aborting */ +#define SndTimeout 3 /* value is # of consecutive send timeouts */ +#define RmtCancel 4 /* remote end has cancelled */ +#define ProtocolErr 5 /* protocol error has occurred, val=hdr */ +#define RemoteMessage 6 /* message from remote end */ +#define DataErr 7 /* data error, val=error count */ +#define FileErr 8 /* error writing file, val=errno */ +#define FileBegin 9 /* file transfer begins, str=name */ +#define FileEnd 10 /* file transfer ends, str=name */ +#define FileSkip 11 /* file being skipped, str=name */ + + +// proxy type +#define NOPROXY 0 +#define WINGATE 1 +#define SOCKS4 2 +#define SOCKS5 3 +#define HTTP 4 + +// UI ID +#define ID_FILE_CONNECT 0x00 +#define ID_FILE_DISCONNECT 0x01 +#define ID_FILE_ADDRESS 0x02 +#define ID_FILE_QUICK 0x03 +#define ID_FILE_EXIT 0x04 + +#define ID_EDIT_COPY 0x10 +#define ID_EDIT_PASTE 0x11 +#define ID_EDIT_COLOR 0x12 +#define ID_EDIT_RECT 0x13 +#define ID_EDIT_AUTO 0x14 +#define ID_EDIT_WW 0x15 + +#define ID_EDIT_ESC_NO 0x17 +#define ID_EDIT_ESC_ESC 0x18 +#define ID_EDIT_ESC_U 0x19 +#define ID_EDIT_ESC_CUS 0x1a + +#define ID_EDIT_CODEC_GBK 0x1b +#define ID_EDIT_CODEC_BIG5 0x1c + + +#define ID_VIEW_FONT 0x20 +#define ID_VIEW_COLOR 0x21 +#define ID_VIEW_REFRESH 0x22 +#define ID_VIEW_LANG 0x23 +#define ID_VIEW_FULL 0x24 +#define ID_VIEW_BOSS 0x25 +#define ID_VIEW_SCROLL_HIDE 0x26 +#define ID_VIEW_SCROLL_LEFT 0x27 +#define ID_VIEW_SCROLL_RIGHT 0x28 +#define ID_VIEW_SWITCH 0x29 +#define ID_VIEW_STATUS 0x3a + +#define ID_OPTION_CURRENT 0x30 +#define ID_OPTION_DEFAULT 0x31 +#define ID_OPTION_PREF 0x32 + +#define ID_SPEC_ANTI 0x40 +#define ID_SPEC_AUTO 0x41 +#define ID_SPEC_MESSAGE 0x42 +#define ID_SPEC_BEEP 0x43 +#define ID_SPEC_MOUSE 0x44 +#define ID_SPEC_ARTICLE 0x45 + +#define ID_SCRIPT_RUN 0x50 +#define ID_SCRIPT_STOP 0x51 + +#define ID_HELP_ABOUT 0x60 +#define ID_HELP_HOMEPAGE 0x61 + +//for open last addr +#define LAST_ADDRESS_INDEX -321 + +//script function names: +#define SFN_ANTI_IDLE "antiIdle" +#define SFN_ON_BELL "onBell" +#define SFN_AUTO_REPLY "autoReply" +#define SFN_DATA_EVENT "dataEvent" +#define SFN_KEY_EVENT "keyEvent" +#define SFN_MOUSE_EVENT "mouseEvent" +#define SFN_DETECT_MENU "detectMenu" + +//script key event type +#define SKET_KEY_PRESS 0 + +//script mouse event type +#define SMET_UNKOWN -1 +#define SMET_MOUSE_PRESS 0 +#define SMET_MOUSE_RELEASE 1 +#define SMET_MOUSE_MOVE 2 +#define SMET_MOUSE_DBCLICK 3 +#define SMET_WHEEL 4 + +//script button state & key modifier +#define SBS_LEFT_BUTTON 0x01 +#define SBS_RIGHT_BUTTON 0x02 +#define SBS_MID_BUTTON 0x04 +#define SBS_ALT 0x08 +#define SBS_CTRL 0x10 +#define SBS_SHIFT 0x20 + +} // namespace FQTerm + +#endif // FQTERM_GLOBAL_H diff --git a/src/common/fqterm_config.cpp b/src/common/fqterm_config.cpp new file mode 100644 index 0000000..19e0db4 --- /dev/null +++ b/src/common/fqterm_config.cpp @@ -0,0 +1,181 @@ +/*************************************************************************** + * 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 <QTextStream> +#include <QFile> +#include <QString> +#include <QTextCodec> + +#include "fqterm_trace.h" +#include "fqterm_config.h" + +namespace FQTerm { + +FQTermConfig::FQTermConfig(const QString &szFileName) { + load(szFileName); +} + +FQTermConfig::~FQTermConfig(){ + +} + +bool FQTermConfig::save(const QString &szFileName) { + QFile file(szFileName); + if (!file.open(QIODevice::WriteOnly)) { + FQ_TRACE("config", 0) << "Failed to open the file for writing: " + << szFileName; + return false; + } + + QTextStream os; + os.setDevice(&file); + saveToStream(os); + // os.unsetDevice(); + file.close(); + + + return true; +} + +bool FQTermConfig::loadFromStream(QTextStream &is) { + QString strLine, strSection; + + data.clear(); + + is.setCodec(QTextCodec::codecForName("UTF-8")); + + while (!is.atEnd()) { + strLine = is.readLine().trimmed(); + if (strLine.isEmpty() || strLine[0] == '#') { + continue; + } + + if (strLine.left(1) == "[" && strLine.right(1) == "]") { + strSection = strLine.mid(1, strLine.length() - 2); + addSection(strSection); + } else { + QString strValue = strLine.section('=', 1).trimmed(); + setItemValue(strSection, strLine.section('=', 0, 0).trimmed(), + strValue.isNull() ? QString(""): strValue); + } + } + return true; +} + +bool FQTermConfig::saveToStream(QTextStream &os) { + QString strLine, strSection; + Section::iterator iStr; + + os.setCodec(QTextCodec::codecForName("UTF-8")); + + for (StrSecMap::iterator iSec = data.begin(); iSec != data.end(); ++iSec) { + os << '[' << iSec.key() << "]\n"; + for (iStr = iSec.value().begin(); iStr != iSec.value().end(); ++iStr) { + os << iStr.key() << '=' << iStr.value() << '\n'; + } + os << '\n'; + } + return true; +} + + +bool FQTermConfig::addSection(const QString &szSection) { + if (hasSection(szSection)) { + return false; + } + Section sec; + data[szSection] = sec; + return true; +} + +bool FQTermConfig::hasSection(const QString &szSection) const +{ + return data.find(szSection) != data.end(); +} + +bool FQTermConfig::setItemValue(const QString &szSection, const QString + &szItemName, const QString &szItemValue) { + if (!hasSection(szSection)) + if (!addSection(szSection)) { + return false; + } + + data[szSection][szItemName] = szItemValue; + return true; +} + +QString FQTermConfig::getItemValue(const QString &szSection, + const QString &szItemName) const { + if (hasSection(szSection)) + if (data[szSection].find(szItemName) != data[szSection].end()) + if (!data[szSection][szItemName].isEmpty()) { + return data[szSection][szItemName]; + } + return ""; +} + +bool FQTermConfig::renameSection(const QString &szSection, const QString + &szNewName) { + if (hasSection(szNewName) || !hasSection(szSection)) { + return false; + } + + if (!addSection(szNewName)) { + return false; + } + data[szNewName] = data[szSection]; + + return deleteSection(szSection); +} + +bool FQTermConfig::deleteSection(const QString &szSection) { + if (hasSection(szSection)) { + data.remove(szSection); + return true; + } + return false; +} + +bool FQTermConfig::deleteItem(const QString &szSection, const QString + &szItemName) { + if (hasSection(szSection)) + if (data[szSection].find(szItemName) != data[szSection].end()) { + data[szSection].remove(szItemName); + return true; + } + return false; +} + +bool FQTermConfig::load(const QString &filename) { + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + FQ_TRACE("config", 0) << "Failed to open the file for reading " + << filename; + return false; + } + QTextStream is; + is.setDevice(&file); + loadFromStream(is); + //is.unsetDevice(); + file.close(); + return true; +} + +} // namespace FQTerm diff --git a/src/common/fqterm_config.h b/src/common/fqterm_config.h new file mode 100644 index 0000000..2f88602 --- /dev/null +++ b/src/common/fqterm_config.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_CFG_H +#define FQTERM_CFG_H + +#include <QTextStream> +#include <QMap> +#include <QObject> + +namespace FQTerm { +typedef QMap<QString, QString> Section; +typedef QMap<QString, Section> StrSecMap; + +class FQTermConfig { + private: + StrSecMap data; + bool loadFromStream(QTextStream &); + bool saveToStream(QTextStream &); + + bool addSection(const QString §ionName); + public: + FQTermConfig(const QString &fileName); + ~FQTermConfig(); + + bool load(const QString &filename); + bool save(const QString &fileName); + + bool setItemValue(const QString §ionName, const QString &itemName, + const QString &itemValue); + + QString getItemValue(const QString §ionName, + const QString &itemName) const; + + bool deleteItem(const QString §ionName, const QString &itemName); + bool deleteSection(const QString §ionName); + + bool renameSection(const QString §ionName, const QString &newName); + bool hasSection(const QString §ionName) const; +}; + +} // namespace FQTerm + +#endif // FQTERM_CFG_H diff --git a/src/common/fqterm_exif_extractor.cpp b/src/common/fqterm_exif_extractor.cpp new file mode 100644 index 0000000..05d318e --- /dev/null +++ b/src/common/fqterm_exif_extractor.cpp @@ -0,0 +1,647 @@ +/*************************************************************************** + * 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 "fqterm_exif_extractor.h" + +namespace FQTerm { + +const ExifExtractor::uint16 ExifExtractor::IFD0Tag[16] = {0x010e, 0x010f, 0x0110, 0x0112, 0x011a, + 0x011b, 0x0128, 0x0131, 0x0132, 0x013e, + 0x013f, 0x0211, 0x0213, 0x0214, 0x8298, 0x8769 +}; + +const char ExifExtractor::IFD0TagName[16][30] = { "ImageDescription", "Make", "Model", "Orientation", + "XResolution", "YResolution", "ResolutionUnit", "Software", + "DateTime", "WhitePoint", "PrimaryChromaticities", "YCbCrCoefficients", + "YCbCrPositioning", "ReferenceBlackWhite", "Copyright", "ExifOffset" +}; + +const ExifExtractor::uint16 ExifExtractor::SubIFDTag[38] = {0x829a,0x829d,0x8822,0x8827,0x9000,0x9003,0x9004,0x9101,0x9102,0x9201,0x9202,0x9203,0x9204, + 0x9205,0x9206,0x9207,0x9208,0x9209,0x920a,0x927c,0x9286,0x9290,0x9291,0x9292,0xa000,0xa001, + 0xa002,0xa003,0xa004,0xa005,0xa20e,0xa20f,0xa210,0xa215,0xa217,0xa300,0xa301,0xa302}; + +const char ExifExtractor::SubIFDTagName[38][30] = {"ExposureTime","FNumber","ExposureProgram","ISOSpeedRatings","ExifVersion","DateTimeOriginal","DateTimeDigitized", + "ComponentsConfiguration","CompressedBitsPerPixel","ShutterSpeedValue","ApertureValue","BrightnessValue","ExposureBiasValue", + "MaxApertureValue","SubjectDistance","MeteringMode","LightSource","Flash","FocalLength","MakerNote","UserComment","SubsecTime", + "SubsecTimeOriginal","SubsecTimeDigitized","FlashPixVersion","ColorSpace","ExifImageWidth","ExifImageHeight","RelatedSoundFile", + "ExifInteroperabilityOffset","FocalPlaneXResolution","FocalPlaneYResolution","FocalPlaneResolutionUnit","ExposureIndex", + "SensingMethod","FileSource","SceneType","CFAPattern"}; + +const char ExifExtractor::exifHeaderStandard[6] = {'E', 'x', 'i', 'f', '\0', '\0'}; + +ExifExtractor::ExifExtractor() +{ + exifFile_ = NULL; + reset(); +} + +ExifExtractor::~ExifExtractor() +{ + reset(); +} + +std::string ExifExtractor::extractExifInfo(std::string fileName) { + return extractExifInfo(fopen(fileName.c_str(), "rb")); +} + +std::string ExifExtractor::extractExifInfo(FILE* file) { + reset(); + exifFile_ = file; + if (!exifFile_ || !isReadable() || !checkEndian()) { + return exifInformation_; + } + if (!readIFD0()) + return exifInformation_; + readSubIFD(); + postRead(); + std::map<std::string, std::string>::iterator ii; + for (ii = exifKeyValuePairs_.begin(); + ii != exifKeyValuePairs_.end(); + ++ii) { + if ((*ii).first == "UserComment") { + continue; + } + exifInformation_ += (*ii).first + " : " + (*ii).second + "\n"; + } + fclose(exifFile_); + exifFile_ = NULL; + return exifInformation_; +} +std::string ExifExtractor::info() { + return exifInformation_; +} + +std::string ExifExtractor::operator[]( const std::string& key ) { + std::map<std::string, std::string>::iterator ii; + if ((ii = exifKeyValuePairs_.find(key)) != exifKeyValuePairs_.end()) { + return (*ii).second; + } + return ""; +} + +void ExifExtractor::postRead() { + std::map<std::string, std::string>::iterator ii; + if ((ii = exifKeyValuePairs_.find("Orientation")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "1st row - 1st col : top - left side"; break; + case '2': (*ii).second = "1st row - 1st col : top - right side"; break; + case '3': (*ii).second = "1st row - 1st col : bottom - right side"; break; + case '4': (*ii).second = "1st row - 1st col : bottom - left side"; break; + case '5': (*ii).second = "1st row - 1st col : left side - top"; break; + case '6': (*ii).second = "1st row - 1st col : right side - top"; break; + case '7': (*ii).second = "1st row - 1st col : right side - bottom"; break; + case '8': (*ii).second = "1st row - 1st col : left side - bottom"; break; + default: exifKeyValuePairs_.erase(ii); break; + + } + } + } + if ((ii = exifKeyValuePairs_.find("ResolutionUnit")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "no-unit"; break; + case '2': (*ii).second = "inch"; break; + case '3': (*ii).second = "centimeter"; break; + default: (*ii).second = "inch"; break; + } + } + } + if ((ii = exifKeyValuePairs_.find("DateTime")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + for (size_t i = 0; i < (*ii).second.length() && i < 11; ++i) { + if ((*ii).second[i] == ':'){ + (*ii).second[i] = '.'; + } + } + } + } + if ((ii = exifKeyValuePairs_.find("DateTimeOriginal")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + for (size_t i = 0; i < (*ii).second.length() && i < 11; ++i) { + if ((*ii).second[i] == ':'){ + (*ii).second[i] = '.'; + } + } + } + } + if ((ii = exifKeyValuePairs_.find("DateTimeDigitized")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + for (size_t i = 0; i < (*ii).second.length() && i < 11; ++i) { + if ((*ii).second[i] == ':'){ + (*ii).second[i] = '.'; + } + } + } + } + if ((ii = exifKeyValuePairs_.find("YCbCrPositioning")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "The center of pixel array"; break; + case '2': (*ii).second = "The datum point"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("MeteringMode")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + uint16 value = 123; + sscanf((*ii).second.c_str(), "%hu", &value); + switch(value) { + case 0: (*ii).second = "Unknown"; break; + case 1: (*ii).second = "Average"; break; + case 2: (*ii).second = "CenterWeightedAverage"; break; + case 3: (*ii).second = "Spot"; break; + case 4: (*ii).second = "Multi-spot"; break; + case 5: (*ii).second = "Pattern"; break; + case '6': (*ii).second = "Partial"; break; + case 255: (*ii).second = "Other"; break; + default: exifKeyValuePairs_.erase(ii); break; + + } + } + } + if ((ii = exifKeyValuePairs_.find("LightSource")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + uint16 value = 123; + sscanf((*ii).second.c_str(), "%hu", &value); + switch(value) { + case 0: (*ii).second = "unknown"; break; + case 1: (*ii).second = "daylight"; break; + case 2: (*ii).second = "fluorescent"; break; + case 3: (*ii).second = "tungsten"; break; + case 10: (*ii).second = "flash"; break; + case 17: (*ii).second = "standard light A"; break; + case 18: (*ii).second = "standard light B"; break; + case 19: (*ii).second = "standard light C"; break; + case 20: (*ii).second = "D55"; break; + case 21: (*ii).second = "D65"; break; + case 22: (*ii).second = "D75"; break; + case 255: (*ii).second = "other"; break; + default: exifKeyValuePairs_.erase(ii); break; + + } + } + } + if ((ii = exifKeyValuePairs_.find("Flash")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + uint16 value = 123; + sscanf((*ii).second.c_str(), "%hu", &value); + value &= 0x07; + switch(value) { + case 0: (*ii).second = "Flash did not fire"; break; + case 1: (*ii).second = "Flash fired"; break; + case 5: (*ii).second = "Flash fired but strobe return light not detected"; break; + case 7: (*ii).second = "Flash fired and strobe return light detected"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("ColorSpace")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "sRGB color space"; break; + case '6': (*ii).second = "Uncalibrated"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("FocalPlaneResolutionUnit")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '1': (*ii).second = "no-unit"; break; + case '2': (*ii).second = "inch"; break; + case '3': (*ii).second = "centimeter"; break; + default: exifKeyValuePairs_.erase(ii); break; + } + } + } + if ((ii = exifKeyValuePairs_.find("SensingMethod")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 1) { + exifKeyValuePairs_.erase(ii); + } else { + switch((*ii).second[0]) { + case '2': (*ii).second = "1 chip color area sensor"; break; + default: (*ii).second = "other"; break; + } + } + } + if ((ii = exifKeyValuePairs_.find("ExifVersion")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + (*ii).second = 'V' + (*ii).second.substr(0, 2) + '.' + (*ii).second.substr(2); + } + } + if ((ii = exifKeyValuePairs_.find("ComponentsConfiguration")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + static const char CCName[7][10] = {"", "[Y]", "[Cb]", "[Cr]", "[Red]", "[Green]", "[Blue]"}; + std::string cc; + for(int i = 0; i < 4; ++i) { + int index = (*ii).second[i]; + if (index < 0 || index >= 7) { + index = 0; + } + cc += CCName[index]; + } + } + } + if ((ii = exifKeyValuePairs_.find("ExifVersion")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + (*ii).second = 'V' + (*ii).second.substr(0, 2) + '.' + (*ii).second.substr(2); + } + } + if ((ii = exifKeyValuePairs_.find("MakerNote")) != exifKeyValuePairs_.end()) { + exifKeyValuePairs_.erase(ii); + } + if ((ii = exifKeyValuePairs_.find("CFAPattern")) != exifKeyValuePairs_.end()) { + exifKeyValuePairs_.erase(ii); + } + if ((ii = exifKeyValuePairs_.find("UserComment")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() < 8) { + exifKeyValuePairs_.erase(ii); + } else { + //Leave it to higher level which can deal with encoding. + //"\0x41\0x53\0x43\0x49\0x49\0x00\0x00\0x00"//ASCII + //"\0x4a\0x49\0x53\0x00\0x00\0x00\0x00\0x00"//JIS + //"\0x55\0x4e\0x49\0x43\0x4f\0x44\0x45\0x00"//Unicode + //"\0x00\0x00\0x00\0x00\0x00\0x00\0x00\0x00"//Undefined + } + } + if ((ii = exifKeyValuePairs_.find("FlashPixVersion")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 4) { + exifKeyValuePairs_.erase(ii); + } else { + (*ii).second = 'V' + (*ii).second.substr(0, 2) + '.' + (*ii).second.substr(2); + } + } + //FileSource + if ((ii = exifKeyValuePairs_.find("FileSource")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 1) { + exifKeyValuePairs_.erase(ii); + } else { + if ((*ii).second[0] == '\003') { + (*ii).second = "Digital still camera"; + } else { + exifKeyValuePairs_.erase(ii); + } + } + } + if ((ii = exifKeyValuePairs_.find("SceneType")) != exifKeyValuePairs_.end()) { + if ((*ii).second.length() != 1) { + exifKeyValuePairs_.erase(ii); + } else { + if ((*ii).second[0] == '\001') { + (*ii).second = "Directly photographed"; + } else { + exifKeyValuePairs_.erase(ii); + } + } + } + +} + +std::string ExifExtractor::readInfo() { + uint32 count; + uint32 offset; + uint16 shortValue; + uint32 longValue; + uint32 urationalp; + uint32 urationalc; + uint32 urationalgcd; + int32 rationalp; + int32 rationalc; + int32 rationalgcd; + int32 sign; + DATATYPE dataType; + char* buffer; + std::string ret = ""; + + if (!read(&shortValue, 2,1) || shortValue == 0 || shortValue > MAXGUARD) { + return ret; + } + dataType = (DATATYPE)shortValue; + + if (!read(&count, 4,1)) { + return ret; + } + + switch(dataType) { + case UNDEFINED: + buffer = new char[count + 1]; + + if (count < 4) { + if (!read(buffer, 1, count)) { + return ret; + } + } else { + if (!read(&offset, 4, 1)) { + return ret; + } + seek(12 + offset, SEEK_SET); + memset(buffer, 0, count + 1); + read(buffer, 1, count); + } + ret = std::string(buffer, count); + delete []buffer; + break; + case ASCIISTRING: + if (!read(&offset, 4, 1)) { + break; + } + seek(12 + offset, SEEK_SET); + buffer = new char[count + 1]; + memset(buffer, 0, count + 1); + read(buffer, 1, count); + ret = buffer; + delete []buffer; + break; + case UNSIGNEDINT16: + if (!read(&shortValue, 2, 1)) { + break; + } + buffer = new char[256]; + sprintf(buffer, "%hu", shortValue); + ret = buffer; + delete []buffer; + break; + case UNSIGNEDINT32: + if (!read(&longValue, 4, 1)) { + break; + } + buffer = new char[256]; + sprintf(buffer, "%u", longValue); + ret = buffer; + delete []buffer; + + break; + case UNSIGNEDRATIONAL: + if (!read(&offset, 4, 1)) { + break; + } + seek(12 + offset, SEEK_SET); + if (!read(&urationalc, 4, 1)) { + break; + } + if (!read(&urationalp, 4, 1)) { + break; + } + urationalgcd = gcd(urationalp, urationalc); + if (urationalgcd == 0) urationalgcd = 1; + buffer = new char[256]; + sprintf(buffer, "%u/%u", urationalc / urationalgcd, urationalp / urationalgcd); + ret = buffer; + delete []buffer; + break; + case RATIONAL: + if (!read(&offset, 4, 1)) { + break; + } + sign = 1; + seek(12 + offset, SEEK_SET); + if (!read(&rationalc, 4, 1)) { + break; + } + if (rationalc < 0) { + sign *= -1; + rationalc = -rationalc; + } + if (!read(&rationalp, 4, 1)) { + break; + } + if (rationalp < 0) { + sign *= -1; + rationalp = -rationalp; + } + rationalgcd = gcd(rationalp, rationalc); + if (rationalgcd == 0) rationalgcd = 1; + buffer = new char[256]; + sprintf(buffer, "%d/%d", sign * rationalc / rationalgcd, rationalp / rationalgcd); + ret = buffer; + delete []buffer; + break; + default: + break; + } + return ret; +} + +bool ExifExtractor::analyzeIFD0TagInfo() { + bool res = true; + uint16 tag; + if (!read(&tag, 2, 1)) + res = false; + int index; + for (index = 0; index < 16; ++index) { + if (IFD0Tag[index] == tag) { + break; + } + } + if (index == 16) { + res = false; + } + long pos = ftell(exifFile_) + 10; + + if (res) { + std::string info = readInfo(); + if (info != "") + exifKeyValuePairs_[IFD0TagName[index]] = info; + } + + seek(pos, SEEK_SET); + return res; +} + +bool ExifExtractor::analyzeSubIFDTagInfo() { + bool res = true; + uint16 tag; + if (!read(&tag, 2, 1)) + res = false; + int index; + for (index = 0; index < 38; ++index) { + if (SubIFDTag[index] == tag) { + break; + } + } + if (index == 38) { + res = false; + } + long pos = ftell(exifFile_) + 10; + + if (res) { + std::string info = readInfo(); + if (info != "") + exifKeyValuePairs_[SubIFDTagName[index]] = info; + } + + seek(pos, SEEK_SET); + return res; +} + +bool ExifExtractor::readIFD0() { + seek(16, SEEK_SET); + if (!read(&ifdOffset_, 4, 1)) { + return false; + } + seek(ifdOffset_ + 12, SEEK_SET); + uint16 entryCount = 0; + if (!read(&entryCount, 2, 1)) { + return false; + } + int app1Entry = entryCount; + while (app1Entry >= 0) { + analyzeIFD0TagInfo(); + app1Entry--; + } + return true; +} + +bool ExifExtractor::readSubIFD() { + std::map<std::string, std::string>::iterator ii; + if ((ii = exifKeyValuePairs_.find("ExifOffset")) == exifKeyValuePairs_.end()) { + return false; + } + uint32 exifOffset = 0; + sscanf((*ii).second.c_str(), "%u", &exifOffset); + seek(12 + exifOffset, SEEK_SET); + + uint16 entryCount = 0; + if (!read(&entryCount, 2, 1)) { + return false; + } + int app1Entry = entryCount; + while (app1Entry >= 0) { + analyzeSubIFDTagInfo(); + app1Entry--; + } + return true; +} + +bool ExifExtractor::isReadable() { + rewind(); + unsigned char soi[2]; + if (!read(soi, 2, 1)) + return false; + if (soi[0] != 0xFF || soi[1] != 0xD8) { + return false; + } + unsigned char app1[2]; + if (!read(app1, 2, 1)) + return false; + if (app1[0] != 0xFF || app1[1] != 0xE1) { + return false; + } + seek(2, SEEK_CUR); + char exifHeader[6]; + if (!read(exifHeader, 1, 6)) { + return false; + } + for (int i = 0; i < 6; ++i) { + if (exifHeader[i] != exifHeaderStandard[i]) + return false; + } + return true; +} + +bool ExifExtractor::checkEndian() { + toggle_ = false; + seek(12, SEEK_SET); + uint16 endian = 0; + if (!read(&endian, 2, 1)) { + return false; + } + if (endian == 0x4949) { + //II + toggle_ = false; + } + else if (endian == 0x4d4d) { + //MM + toggle_ = true; + } + return true; +} + +void ExifExtractor::toggleEndian( void* buf, size_t s ) { + char* buffer = (char*)buf; + if (!toggle_) { + return; + } + for (size_t i = 0; i < s / 2; ++i) { + char tmp; + tmp = buffer[i]; + buffer[i] = buffer[s - i - 1]; + buffer[s - i - 1] = tmp; + } +} + +void ExifExtractor::reset() { + toggle_ = false; + exifKeyValuePairs_.clear(); + if (exifFile_) { + fclose(exifFile_); + exifFile_ = NULL; + } + ifdOffset_ = 0; + exifInformation_.clear(); +} + +bool ExifExtractor::read( void* buffer, size_t elementSize, size_t count ) { + for (size_t i = 0; i < count; ++i) { + if (fread((char*)buffer + i * elementSize, elementSize, 1, exifFile_) != 1) + return false; + toggleEndian((char*)buffer + i * elementSize, elementSize); + } + return true; +} + +void ExifExtractor::seek( long offset, int origin ) { + fseek(exifFile_, offset, origin); +} + +void ExifExtractor::rewind() { + ::rewind(exifFile_); +} +} //namespace FQTerm diff --git a/src/common/fqterm_exif_extractor.h b/src/common/fqterm_exif_extractor.h new file mode 100644 index 0000000..7f05798 --- /dev/null +++ b/src/common/fqterm_exif_extractor.h @@ -0,0 +1,126 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_EXIF_EXTRACTOR +#define FQTERM_EXIF_EXTRACTOR + +//#include <QtGlobal> + +#include "fqterm_trace.h" + +#include <iostream> +#include <vector> +#include <stdio.h> +#include <stdlib.h> +#include <algorithm> +#include <map> +#include <string> +//using namespace std; +#ifdef __GXX_EXPERIMENTAL_CXX0X__
+#include <cstdint>
+#endif + +namespace FQTerm { + +class ExifExtractor +{ +public: + +#ifdef __GXX_EXPERIMENTAL_CXX0X__
+ typedef std::uint32_t uint32;
+ typedef std::uint16_t uint16;
+ typedef std::int32_t int32;
+ typedef std::int16_t int16; +#elif defined(QT_VERSION) + typedef quint32 uint32; + typedef quint16 uint16; + typedef qint32 int32; + typedef qint16 int16; +#else + typedef unsigned int uint32; + typedef unsigned short int uint16; + typedef short int int16; + typedef int int32; +#endif + + enum DATATYPE {ZEORGARD = 0, UNSIGNEDCHAR = 1, ASCIISTRING = 2, UNSIGNEDINT16 = 3, UNSIGNEDINT32 = 4, + UNSIGNEDRATIONAL = 5, SIGNEDCHAR = 6, UNDEFINED = 7, SIGNEDSHORT = 8, SIGNEDLONG = 9, RATIONAL = 10, + SIGNEDFLOAT = 11, DOUBLEFLOAT = 12, MAXGUARD = 13}; + + + ExifExtractor(); + ~ExifExtractor(); + std::string extractExifInfo(std::string fileName); + std::string extractExifInfo(FILE* file); + + std::string info(); + + std::string operator[](const std::string& key); + +private: + void postRead(); + + std::string readInfo(); + bool analyzeIFD0TagInfo(); + + bool analyzeSubIFDTagInfo(); + + bool readIFD0(); + bool readSubIFD(); + bool isReadable(); + bool checkEndian(); + void toggleEndian(void* buf, size_t s); + + void reset(); + + bool read(void* buffer, size_t elementSize, size_t count); + + void seek(long offset, int origin); + + void rewind(); + + template<class T> + T gcd(T a, T b) { + if (a == 0 || b == 0) + return a + b; + return gcd(b, a % b); + } + + + bool toggle_; + std::map<std::string, std::string> exifKeyValuePairs_; + FILE* exifFile_; + uint32 ifdOffset_; + uint32 subIfdOffset_; + + static const uint16 IFD0Tag[16]; + static const char IFD0TagName[16][30]; + static const uint16 SubIFDTag[38]; + static const char SubIFDTagName[38][30]; + static const char exifHeaderStandard[6]; + + std::string exifInformation_; +}; + + + +} //namespace FQTerm + +#endif diff --git a/src/common/fqterm_filedialog.cpp b/src/common/fqterm_filedialog.cpp new file mode 100644 index 0000000..958fff9 --- /dev/null +++ b/src/common/fqterm_filedialog.cpp @@ -0,0 +1,157 @@ +/*************************************************************************** + * 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 "fqterm_filedialog.h" +#include "fqterm_trace.h" +#include "fqterm_path.h" +#include "fqterm_config.h" + +/* + * Constructs a articleDialog as a child of 'parent', with the + * name 'name' and widget flags set to 'f'. + * + * The dialog will by default be modeless, unless you set 'modal' to + * TRUE to construct a modal dialog. + */ + +namespace FQTerm { + +FQTermFileDialog::FQTermFileDialog(FQTermConfig *config, QWidget *parent, Qt::WFlags fl) + : QFileDialog(parent, fl) { + + configDir = getPath(USER_CONFIG) + "/"; + userConfig = configDir + "fqterm.cfg"; + strSection = "previous"; + strSave = "save"; + strOpen = "open"; + config_ = config; +} + +/* + * Destroys the object and frees any allocated resources + */ +FQTermFileDialog::~FQTermFileDialog() { + // no need to delete child widgets, Qt does it all for us +} + + + +QString FQTermFileDialog::getSaveName(const QString &fileToSave, const QString &hints, QWidget *widget) { + QString saveFile; + QString strPrevSave, saveName; + QFileDialog fileDialog(widget); + + if (config_->load(userConfig)) { + strPrevSave = config_->getItemValue(strSection, strSave); + } + + QString strTmp(fileToSave); +#if !defined(Q_OS_WIN32) || !defined(_OS_WIN32_) + if (strTmp.toLocal8Bit().contains("/")) { + strTmp.replace(QString("/"), QString("_")); + } +#endif + + if (strPrevSave.isEmpty()) { + saveFile = configDir + strTmp; + } else { + saveFile = strPrevSave + "/" + strTmp; + } + + QString realHints = (hints.isEmpty() ? "*" : hints); + saveName = fileDialog.getSaveFileName(widget, + tr("Save As..."), + saveFile, realHints); + + QFileInfo fi(saveName); + + if (!saveName.isEmpty()) { + config_->setItemValue(strSection, strSave, fi.absolutePath()); + config_->save(userConfig); + } + + return saveName; +} + +QString FQTermFileDialog::getOpenName(const QString &title, const QString &hints, QWidget *widget) { + QString strPrevOpen; + QString openName; + QFileDialog fileDialog(widget); + + strPrevOpen = (config_->load(userConfig) ? config_->getItemValue(strSection, strOpen) : "./"); + + QString realHints = (hints.isEmpty() ? "*" : hints); + QString realTitle = (title.isEmpty() ? "Choose a file to open" : title); + openName = fileDialog.getOpenFileName(widget, realTitle, strPrevOpen, realHints); + + if (!openName.isEmpty()) { + config_->setItemValue(strSection, strOpen, QFileInfo(openName).absolutePath()); + config_->save(userConfig); + } + + return openName; +} + +QStringList FQTermFileDialog::getOpenNames(const QString &title, const QString &hints, QWidget *widget) { + QString openDir, strPrevOpen; + QStringList openNames; + QFileDialog fileDialog(widget); + + strPrevOpen = (config_->load(userConfig) ? config_->getItemValue(strSection, strOpen) : "./"); + + QString realHints = (hints.isEmpty() ? "*" : hints); + QString realTitle = (title.isEmpty() ? "Choose files to open" : title); + openNames = fileDialog.getOpenFileNames(widget, realTitle, strPrevOpen, realHints); + + if (!openNames.isEmpty() && !openNames.at(0).isEmpty()) { + openDir = QFileInfo(openNames.at(0)).absolutePath(); + config_->setItemValue(strSection, strOpen, openDir); + config_->save(userConfig); + } + + return openNames; +} + +QString FQTermFileDialog::getExistingDirectory(const QString &title, const QString &hints, QWidget *widget) { + + QString strPrevOpen; + QFileDialog fileDialog(widget); + + if (hints.isEmpty()) { + strPrevOpen = (config_->load(userConfig) ? config_->getItemValue(strSection, strOpen) : "./"); + } else { + strPrevOpen = hints; + } + + QString realTitle = (title.isEmpty() ? "Open a directory" : title); + QString dir = fileDialog.getExistingDirectory(widget, + realTitle, + strPrevOpen, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if (!dir.isEmpty()) { + config_->setItemValue(strSection, strOpen, QFileInfo(dir).absolutePath()); + config_->save(userConfig); + } + + return dir; +} + +} // namespace FQTerm diff --git a/src/common/fqterm_filedialog.h b/src/common/fqterm_filedialog.h new file mode 100644 index 0000000..5248ffd --- /dev/null +++ b/src/common/fqterm_filedialog.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_FILEDIALOG_H +#define FQTERM_FILEDIALOG_H + +#include <QFileDialog> +#include <QMessageBox> + +namespace FQTerm { + +class FQTermConfig; + +class FQTermFileDialog: public QFileDialog { +public: + FQTermFileDialog(FQTermConfig *config, QWidget *parent_ = 0, Qt::WFlags fl = 0); + ~FQTermFileDialog(); + + QString getSaveName(const QString &filename, const QString &hints, QWidget *widget = 0); + QString getOpenName(const QString &title, const QString &hints, QWidget *widget = 0); + QStringList getOpenNames(const QString &title, const QString &hints, QWidget *widget = 0); + QString getExistingDirectory(const QString &title, const QString &hints, QWidget *widget = 0); + +private: + QString strSection, strSave, strOpen; + FQTermConfig *config_; + QString configDir, userConfig; +}; + +} // name space FQTerm + +#endif // FQTERM_FILEEDIALOG_H diff --git a/src/common/fqterm_font.cpp b/src/common/fqterm_font.cpp new file mode 100644 index 0000000..f2dcfbd --- /dev/null +++ b/src/common/fqterm_font.cpp @@ -0,0 +1,261 @@ +/*************************************************************************** + * 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 <list> +#include <set> +#include <utility> +#include <map> + +#include <QFontDatabase> +#include <QFontInfo> +#include <QFile> +#include <QTextStream> +#include <QTextCodec> +#include <QLocale> + +#include "fqterm_trace.h" +#include "fqterm_font.h" +#include "fqterm_path.h" +#include "fqterm_config.h" + +using namespace std; + +namespace FQTerm { + +namespace Font { + +enum Language{US_ENGLISH = 0, + SIMPLIFIED_CHINESE, + LANGUAGE_COUNT }; + +QString getLanguageName(Language lang) { + switch (lang){ + case US_ENGLISH: + return "en_US"; + case SIMPLIFIED_CHINESE: + return "zh_CN"; + default: + return "C"; + } +} + +Language getLanguageByName(QString langName) { + if (langName == "zh_CN") { + return SIMPLIFIED_CHINESE; + } + if (langName == "en_US") { + return US_ENGLISH; + } + return LANGUAGE_COUNT; +} + +} // namespace Language + +typedef set<Font::Language> LanguageSet; +typedef map<QString, pair<QString, LanguageSet> > FontLanguagesList; + +typedef map<QString, map<Font::Language, QStringList> > FontSets; + +// This function will be called only once. +static const FontSets &getPreferedFontSets() { + static FontSets font_sets; + const QString &res_path = getPath(RESOURCE); + + QString filename = res_path + "default_font.conf"; + + if (!QFile::exists(filename)) { + filename = res_path + "/dict/" + "default_font.conf"; + } + + + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + FQ_TRACE("font", 0) << "Failed to open the default font configurations file:" + << filename; + return font_sets; + } + + QTextStream is; + is.setDevice(&file); + is.setCodec(QTextCodec::codecForName("UTF-8")); + +#if defined(WIN32) + QString expected_section = "Windows"; +#elif defined(__APPLE__) + QString expected_section = "Apple"; +#else + QString expected_section = "Linux"; +#endif + + QString line; + + QString current_section; + while (!is.atEnd()) { + line = is.readLine().trimmed(); + if (line.isEmpty() || line[0] == '#') { + continue; + } + + if (line.left(1) == "[" && line.right(1) == "]") { + current_section = line.mid(1, line.length() - 2); + continue; + } + + if (current_section == expected_section) { + QString en_font = line.section('=', 0, 0).trimmed().toLower(); + QString fonts_for_lang = line.section('=', 1).trimmed(); + + map<Font::Language, QStringList> &font_set = font_sets[en_font]; + + QString lang = fonts_for_lang.section(":", 0, 0).trimmed(); + QString fonts = fonts_for_lang.section(":", 1).trimmed(); + + QStringList font_list = fonts.split(",", QString::SkipEmptyParts); + + for (int i = 0; i < font_list.size(); ++i) { + font_list[i] = font_list[i].trimmed(); + } + + font_set[Font::getLanguageByName(lang)] = font_list; + } + } + + return font_sets; +} + +#if 0 +//Not used +static int outputAllSystemFonts(const QStringList &fonts) { + if (isAllowedCategory("font", 9)) { + for (int i = 0; i < fonts.size(); ++i) { + FQ_TRACE("font", 9) << "Found a font: " + << (QFontInfo(QFont(fonts.at(i))).fixedPitch() ? + "fixed-pitch " : "variable-pitch ") + << fonts.at(i); + } + } + return 0; +} +#endif + +static QStringList &getSystemFontFamilies() { + static QStringList list = QFontDatabase().families(); + // static int tmp = outputAllSystemFonts(list); + + return list; +} + +static FontSets &getUserConfigFontSets() { + static FontSets font_sets = getPreferedFontSets(); + return font_sets; +} + +static QString getEnglishFontFamily() { + static const QStringList &families = getSystemFontFamilies(); + static const FontSets &font_sets = getUserConfigFontSets(); + static QString en_font_name; + + if (!en_font_name.isEmpty()) { + return en_font_name; + } + + FontSets::const_iterator it = font_sets.find("default"); + if (it != font_sets.end()) { + map<Font::Language, QStringList>::const_iterator itt + = it->second.find(Font::US_ENGLISH); + if (itt != it->second.end()) { + for (int i = 0; i < itt->second.size(); ++i) { + const QString &font = itt->second[i]; + if (families.contains(font)) { + en_font_name = font; + break; + } + } + } + } + + return en_font_name; +} + + +static QString getFontFamilyForLang(Font::Language lang) { + static const QStringList &families = getSystemFontFamilies(); + static const FontSets &font_sets = getUserConfigFontSets(); + + const QString en_font_name = getEnglishFontFamily(); + + if (lang == Font::US_ENGLISH) { + return en_font_name; + } + + FontSets::const_iterator it = font_sets.find(en_font_name.toLower()); + if (it != font_sets.end()) { + map<Font::Language, QStringList>::const_iterator itt + = it->second.find(lang); + if (itt != it->second.end()) { + for (int i = 0; i < itt->second.size(); ++i) { + const QString &font = itt->second[i]; + if (families.contains(font)) { + return font; + } else { + FQ_TRACE("font", 5) << "Font " << font << " for " + << en_font_name << " not found."; + } + } + } + } else { + FQ_TRACE("font", 3) << "NO fontset for " << en_font_name << " found."; + } + + return en_font_name; +} + +QString getDefaultFontFamilyForLanguage(bool isEnglish) { + Font::Language lang = isEnglish ? Font::US_ENGLISH : Font::SIMPLIFIED_CHINESE; + + static map<Font::Language, QString> langs_fonts_list; + + map<Font::Language, QString>::iterator it = langs_fonts_list.find(lang); + if (it == langs_fonts_list.end()) { + langs_fonts_list.insert( + make_pair(lang, getFontFamilyForLang(lang))); + it = langs_fonts_list.find(lang); + + FQ_TRACE("font", 3) << "Defaut font for " + << Font::getLanguageName(lang) + << " is: " + << it->second + << " (" << it->second.size() << ")"; + } + + return it->second; +} + +#if 0 +//Not used. +static Font::Language getCurrentSystemLanguage() { + if (QLocale::system().language() == QLocale::Chinese) { + return Font::SIMPLIFIED_CHINESE; + } + + return Font::US_ENGLISH; +} +#endif +} // namespace FQTerm diff --git a/src/common/fqterm_font.h b/src/common/fqterm_font.h new file mode 100644 index 0000000..7d28ffb --- /dev/null +++ b/src/common/fqterm_font.h @@ -0,0 +1,34 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_FONT_H +#define FQTERM_FONT_H + +#include <QString> + +#include "fqterm_param.h" + +namespace FQTerm { + +QString getDefaultFontFamilyForLanguage(bool isEnglish); + +} // namespace FQTerm + +#endif // FQTERM_FONT_H diff --git a/src/common/fqterm_param.cpp b/src/common/fqterm_param.cpp new file mode 100644 index 0000000..9490bdd --- /dev/null +++ b/src/common/fqterm_param.cpp @@ -0,0 +1,274 @@ +/*************************************************************************** + * 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 "fqterm_param.h" +#include "fqterm_font.h" + +namespace FQTerm { + +FQTermParam::FQTermParam() { + name_ = "NEW SMTH"; + hostAddress_ = "newsmth.net"; + port_ = 23; + hostType_ = 0; // 0--BBS 1--*NIX + isAutoLogin_ = false; + preLoginCommand_ = ""; + userName_ = ""; + password_ = ""; + postLoginCommand_ = ""; + // Display + serverEncodingID_ = 0; + isFontAutoFit_ = 1; + isAlwaysHighlight_ = 0; + isAnsiColor_ = 1; + + englishFontName_ = getDefaultFontFamilyForLanguage(true); + englishFontSize_ = 14; + otherFontName_ = getDefaultFontFamilyForLanguage(false); + otherFontSize_ = 14; + alignMode_ = 0; + charSpacing_ = 0; + lineSpacing_ = 0; + //charRatio_ = 0; + + backgroundColor_ = QColor(0, 0, 0); + foregroundColor_ = QColor(198, 195, 198); + schemaFileName_ = ""; + // Terminal + virtualTermType_ = "vt102"; + keyboardType_ = 0; + backspaceType_ = 0; + numColumns_ = 80; + numRows_ = 24; + numScrollLines_ = 240; + cursorType_ = 1; // 0--Block 1--Underline 2--I Type + escapeString_ = "^[^[["; + // Connection + proxyType_ = 0; // 0--None 1--Wingate 2--SOCKS4 3--SOCKS5 4--HTTP + proxyHostName_ = ""; + proxyPort_ = 0; + isAuthentation_ = false; + proxyUserName_ = ""; + proxyPassword_ = ""; + protocolType_ = 0; // 0--Telnet 1--SSH1 2--SSH2 + sshUserName_ = ""; + sshPassword_ = ""; + // Misc + maxIdleSeconds_ = 120; + replyKeyCombination_ = "^Z"; + antiIdleMessage_ = "^@"; + isAntiIdle_ = true; + isAutoReply_ = false; + autoReplyMessage_ = "(FQTerm) Sorry, I am not around"; + isAutoReconnect_ = false; + reconnectInterval_ = 3; + retryTimes_ = 0; + isAutoCloseWin_ = false; + isAutoLoadScript_ = false; + enableZmodem_ = true; + autoLoadedScriptFileName_ = ""; + isBeep_ = true; + isBuzz_ = false; + + // Mouse + isSupportMouse_ = true; + // Mouse + menuType_ = 2; + menuColor_ = QColor(0, 65, 132); + + isColorCopy_ = false; + isRectSelect_ = false; + isAutoCopy_ = true; + isAutoWrap_ = false; +} + +FQTermParam::FQTermParam(const FQTermParam ¶m) { + copy(param); +} + +FQTermParam::~FQTermParam(){} + +FQTermParam &FQTermParam::operator = (const FQTermParam ¶m) { + if (this == ¶m) + return *this; + copy(param); + return *this; +} + +void FQTermParam::copy(const FQTermParam& param) { + name_ = param.name_; + hostAddress_ = param.hostAddress_; + port_ = param.port_; + hostType_ = param.hostType_; // 0--BBS 1--*NIX + isAutoLogin_ = param.isAutoLogin_; + preLoginCommand_ = param.preLoginCommand_; + userName_ = param.userName_; + password_ = param.password_; + postLoginCommand_ = param.postLoginCommand_; + // Display + serverEncodingID_ = param.serverEncodingID_; + isFontAutoFit_ = param.isFontAutoFit_; + isAlwaysHighlight_ = param.isAlwaysHighlight_; + isAnsiColor_ = param.isAnsiColor_; + englishFontName_ = param.englishFontName_; + englishFontSize_ = param.englishFontSize_; + otherFontName_ = param.otherFontName_; + otherFontSize_ = param.otherFontSize_; + alignMode_ = param.alignMode_; + charSpacing_ = param.charSpacing_; + lineSpacing_ = param.lineSpacing_; + //charRatio_ = param.charRatio_; + backgroundColor_ = param.backgroundColor_; + foregroundColor_ = param.foregroundColor_; + schemaFileName_ = param.schemaFileName_; + // Terminal + virtualTermType_ = param.virtualTermType_; + keyboardType_ = param.keyboardType_; + backspaceType_ = param.backspaceType_; + numColumns_ = param.numColumns_; + numRows_ = param.numRows_; + numScrollLines_ = param.numScrollLines_; + cursorType_ = param.cursorType_; // 0--Block 1--Underline 2--I Type + escapeString_ = param.escapeString_; // 0--ESC ESC 1--Ctrl+u + // Connection + proxyType_ = param.proxyType_; + // 0--None 1--Wingate 2--SOCKS4 3--SOCKS5 4--HTTP + proxyHostName_ = param.proxyHostName_; + proxyPort_ = param.proxyPort_; + isAuthentation_ = param.isAuthentation_; + proxyUserName_ = param.proxyUserName_; + proxyPassword_ = param.proxyPassword_; + protocolType_ = param.protocolType_; // 0--Telnet 1--SSH1 2--SSH2 + sshUserName_ = param.sshUserName_; + sshPassword_ = param.sshPassword_; + // Misc + maxIdleSeconds_ = param.maxIdleSeconds_; + replyKeyCombination_ = param.replyKeyCombination_; + antiIdleMessage_ = param.antiIdleMessage_; + isAntiIdle_ = param.isAntiIdle_; + isAutoReply_ = param.isAutoReply_; + autoReplyMessage_ = param.autoReplyMessage_; + isAutoReconnect_ = param.isAutoReconnect_; + reconnectInterval_ = param.reconnectInterval_; + retryTimes_ = param.retryTimes_; + isAutoCloseWin_ = param.isAutoCloseWin_; + isAutoLoadScript_ = param.isAutoLoadScript_; + enableZmodem_ = param.enableZmodem_; + autoLoadedScriptFileName_ = param.autoLoadedScriptFileName_; + isBeep_ = param.isBeep_; + isBuzz_ = param.isBuzz_; + + isSupportMouse_ = param.isSupportMouse_; + // Mouse + menuType_ = param.menuType_; + menuColor_ = param.menuColor_; + + isColorCopy_ = param.isColorCopy_; + isRectSelect_ = param.isRectSelect_; + isAutoCopy_ = param.isAutoCopy_; + isAutoWrap_ = param.isAutoWrap_; +} + +bool FQTermParam::operator==(const FQTermParam& param) +{ + if (name_ != param.name_) return false; + if (hostAddress_ != param.hostAddress_) return false; + if (port_ != param.port_) return false; + if (hostType_ != param.hostType_) return false; + if (isAutoLogin_ != param.isAutoLogin_) return false; + if (preLoginCommand_ != param.preLoginCommand_) return false; + if (userName_ != param.userName_) return false; + if (password_ != param.password_) return false; + if (postLoginCommand_ != param.postLoginCommand_) return false; + if (serverEncodingID_ != param.serverEncodingID_) return false; + if (isFontAutoFit_ != param.isFontAutoFit_) return false; + if (isAlwaysHighlight_ != param.isAlwaysHighlight_) return false; + if (isAnsiColor_ != param.isAnsiColor_) return false; + if (englishFontName_ != param.englishFontName_) return false; + if (englishFontSize_ != param.englishFontSize_) return false; + if (otherFontName_ != param.otherFontName_) return false; + if (otherFontSize_ != param.otherFontSize_) return false; + if (alignMode_ != param.alignMode_) return false; + if (charSpacing_ != param.charSpacing_) return false; + if (lineSpacing_ != param.lineSpacing_) return false; + if (backgroundColor_ != param.backgroundColor_) return false; + if (foregroundColor_ != param.foregroundColor_) return false; + if (schemaFileName_ != param.schemaFileName_) return false; + if (virtualTermType_ != param.virtualTermType_) return false; + if (keyboardType_ != param.keyboardType_) return false; + if (backspaceType_ != param.backspaceType_) return false; + if (numColumns_ != param.numColumns_) return false; + if (numRows_ != param.numRows_) return false; + if (numScrollLines_ != param.numScrollLines_) return false; + if (cursorType_ != param.cursorType_) return false; + if (escapeString_ != param.escapeString_) return false; + if (proxyType_ != param.proxyType_) return false; + if (proxyHostName_ != param.proxyHostName_) return false; + if (proxyPort_ != param.proxyPort_) return false; + if (isAuthentation_ != param.isAuthentation_) return false; + if (proxyUserName_ != param.proxyUserName_) return false; + if (proxyPassword_ != param.proxyPassword_) return false; + if (protocolType_ != param.protocolType_) return false; + if (sshUserName_ != param.sshUserName_) return false; + if (sshPassword_ != param.sshPassword_) return false; + if (maxIdleSeconds_ != param.maxIdleSeconds_) return false; + if (replyKeyCombination_ != param.replyKeyCombination_) return false; + if (antiIdleMessage_ != param.antiIdleMessage_) return false; + if (isAntiIdle_ != param.isAntiIdle_) return false; + if (isAutoReply_ != param.isAutoReply_) return false; + if (autoReplyMessage_ != param.autoReplyMessage_) return false; + if (isAutoReconnect_ != param.isAutoReconnect_) return false; + if (reconnectInterval_ != param.reconnectInterval_) return false; + if (retryTimes_ != param.retryTimes_) return false; + if (isAutoCloseWin_ != param.isAutoCloseWin_) return false; + if (isAutoLoadScript_ != param.isAutoLoadScript_) return false; + if (enableZmodem_ != param.enableZmodem_) return false; + if (isBuzz_ != param.isBuzz_) return false; + if (isBeep_ != param.isBeep_) return false; + if (isSupportMouse_ != param.isSupportMouse_) return false; + if (autoLoadedScriptFileName_ != param.autoLoadedScriptFileName_) return false; + if (menuType_ != param.menuType_) return false; + if (isColorCopy_ != param.isColorCopy_) return false; + if (isRectSelect_ != param.isRectSelect_) return false; + if (isAutoCopy_ != param.isAutoCopy_) return false; + if (isAutoWrap_ != param.isAutoWrap_) return false; + return true; +} + +QString FQTermParam::getLanguageName(bool isEnglish, bool translate /* = true */) +{ + if (isEnglish) { + return QString(translate ? QObject::tr("&English") : "English"); + } + return QString(translate ? QObject::tr("&Non-English") : "Non-English"); +} + +const FQTermParam& FQTermParam::getFQBBSParam() { + static bool inited = false; + static FQTermParam param; + if (!inited) { + param.name_ = "FQTermHelp"; + param.hostAddress_ = "127.0.0.1"; + param.port_ = 35172; + param.serverEncodingID_ = 2; + } + return param; +} +} // namespace FQTerm diff --git a/src/common/fqterm_param.h b/src/common/fqterm_param.h new file mode 100644 index 0000000..ef44f59 --- /dev/null +++ b/src/common/fqterm_param.h @@ -0,0 +1,221 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_PARAM_H +#define FQTERM_PARAM_H + +#include <QString> +#include <QColor> + +namespace FQTerm { + + +//The FQTerm Pref also contains global settings. +//TODO: move all global settings into FQTermPref. +struct FQTermPref { + static FQTermPref* getInstance() + { + //Though Singleton, I didn't define a ctor and make it private + //Why? + //I'm lazy. + static FQTermPref* pThis = new FQTermPref(); + return pThis; + } + int displayOffset_; + int vsetting_; + int imeEncodingID_; // 0--GBK 1--BIG5 + int widthToWrapWord_; + // bool bSmartWW; + bool isWheelSupported_; + bool openWarnOnClose_; + bool openTabBlinking_; + bool replyENQ_; + // bool bLogMsg; + QString httpBrowser_; + int openBeep_; + QString beepSoundFileName_; + int beepMethodID_; + QString beepPlayerName_; + bool openUrlCheck_; + // bool bAutoCopy; + bool openAntiAlias_; + bool openMinimizeToTray_; + bool needClearZmodemPoolOnClose_; + bool useStyleSheet_; + QString styleSheetFile_; + QString zmodemDir_; + QString poolDir_; + QString imageViewerName_; + QString externalEditor_; + QString externalEditorArg_; + QString searchEngine_; + //global settings + bool isBossColor_; + bool isAnsciiEnhance_; + QString escapeString_; + int termScrollBarPosition_; // 0--hide 1--LEFT 2--RIGHT + bool runServer_; +}; + + +class FQTermParam { + public: + FQTermParam(); + FQTermParam(const FQTermParam &); + ~FQTermParam(); + + FQTermParam &operator = (const FQTermParam &); + + bool operator==(const FQTermParam &); + + static const FQTermParam& getFQBBSParam(); + static QString getLanguageName(bool isEnglish, bool translate = true); + // General + // Name + QString name_; + // Address + QString hostAddress_; + // Port + quint16 port_; + // Host Type + int hostType_; // 0--BBS 1--*NIX + // Auto Login + bool isAutoLogin_; + // Pre Login + QString preLoginCommand_; + // User Name + QString userName_; + // Password + QString password_; + // Post Login + QString postLoginCommand_; + + // Display + // {FQTERM_ENCODING_GBK = 0, FQTERM_ENCODING_BIG5 = 1, FQTERM_ENCODING_UTF8 = 2, FQTERM_ENCODING_HKSCS = 3, FQTERM_ENCODING_UAO = 4}; + int serverEncodingID_; + + // 0 - keep column/row, adjust font + // 1 - keep font, adjust column/row + // 2 - keep column/row/font + int isFontAutoFit_; + // Always Highlight + bool isAlwaysHighlight_; + // ANSI Color + bool isAnsiColor_; + // Font Name + QString englishFontName_; + QString otherFontName_; + // Font Size + int englishFontSize_; + int otherFontSize_; + + int alignMode_; //how to align english char/chinese char in vertical direction 0 -- vcenter, 1 -- bottom 2 -- top + int charSpacing_; //additional char spacing for English char. + int lineSpacing_; //additional line spacing + //int charRatio_; //height of english char / width of english char + // Background Color + QColor backgroundColor_; + // Foreground Color + QColor foregroundColor_; + // Schema File + QString schemaFileName_; + + // Terminal + // Terminal Type + QString virtualTermType_; + // Key Type + int keyboardType_; // 0--BBS 1--XTERM 2--VT100 + // Columns & Rows + int numColumns_, numRows_; + // Scroll Lines + int numScrollLines_; + // Curor Type + int cursorType_; // 0--Block 1--Underline 2--I Type + // the esacpe string + QString escapeString_; + + //Keyboard + int backspaceType_; //0--^H 1--^?(127) + + + // Connection + // Proxy Type + int proxyType_; // 0--None 1--Wingate 2--SOCKS4 3--SOCKS5 4--HTTP + // Address + QString proxyHostName_; + // Port + quint16 proxyPort_; + // Authentation + bool isAuthentation_; + // User Name + QString proxyUserName_; + // Password + QString proxyPassword_; + // Protocol + int protocolType_; // 0--Telnet 1--SSH1 2--SSH2 3--Local + // User Name + QString sshUserName_; + // Password + QString sshPassword_; + // Misc + // Max Idle Time %s + int maxIdleSeconds_; + QString replyKeyCombination_; + // Send When Idle + QString antiIdleMessage_; + bool isAntiIdle_; + // wether autoreply + bool isAutoReply_; + // Auto Reply Messages + QString autoReplyMessage_; + // Reconnect When Disconnected By Host + bool isAutoReconnect_; + // Reconnect Interval (s) + int reconnectInterval_; + // Retry times + int retryTimes_; // -1 -- infinite + // Close Window When Disconnected By Host + bool isAutoCloseWin_; + + bool isBeep_; + bool isBuzz_; + + // Mouse + bool isSupportMouse_; + int menuType_; // 0--underline 1--reverse 2--color + QColor menuColor_; + // Script + bool isAutoLoadScript_; + QString autoLoadedScriptFileName_; + // Zmodem + bool enableZmodem_; + + bool isColorCopy_; + bool isRectSelect_; + bool isAutoCopy_; + bool isAutoWrap_; + + private: + void copy(const FQTermParam& parm); +}; + +} // namespace FQTerm + +#endif // FQTERM_PARAM_H diff --git a/src/common/fqterm_path.cpp b/src/common/fqterm_path.cpp new file mode 100644 index 0000000..88ee385 --- /dev/null +++ b/src/common/fqterm_path.cpp @@ -0,0 +1,601 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifdef WIN32 +#include <windows.h> +#include <shlobj.h> +#endif // WIN32 + +#include <QApplication> +#include <QFile> +#include <QDir> +#include <QFont> + +#include "fqterm_config.h" +#include "fqterm_trace.h" +#include "fqterm_param.h" +#include "fqterm_path.h" +#include "fqterm_font.h" + +namespace FQTerm { + +static QString getUserDataDir(); +static QString getInstallPrefix(); +static QString getResourceDir(const QString &prefix); + +const QString &getPath(PathCategory category) { + static QString null_dir = ""; + static QString user_config = getUserDataDir(); + static QString prefix = getInstallPrefix(); + static QString resource = getResourceDir(prefix); + + switch (category) { + case RESOURCE: + return resource; + break; + case USER_CONFIG: + return user_config; + break; + } + return null_dir; +} + +void clearDir(const QString &path) { + QDir dir(path); + if (dir.exists()) { + const QFileInfoList list = dir.entryInfoList(); + //QFileInfoListIterator it( *list ); + //QFileInfo *fi; + foreach(QFileInfo fi, list) { + if (fi.isFile()) { + dir.remove(fi.fileName()); + } + } + } +} + +bool checkPath(const QString &path) { + QDir dir(path); + if (!dir.exists()) { + if (!dir.mkpath(path)) { + FQ_TRACE("path", 0) << "Failed to create directory " << path; + return false; + } + } + return true; +} + +bool checkFile(const QString &src, const QString &dst) { + if (QFile(dst).exists()) { + return true; + } + + if (!QFile::copy(src, dst)) { + FQ_TRACE("path", 0) << "Failed to copy a file from " << src + << " to " << dst; + return false; + } + + FQ_TRACE("path", 5) << "A file copied from " << src + << " to " << dst; + + if (!QFile::setPermissions(dst, QFile::ReadOwner | QFile::WriteOwner)) { + FQ_TRACE("path", 0) << "Failed to change access attributs of "<< dst + << " to make only the owner have rights to " + << "read/write it."; + return false; + } + + return true; +} + +bool iniSettings() { + if (!checkPath(getPath(USER_CONFIG))) { + return false; + } + + if (!checkFile(getPath(RESOURCE) + "userconf/fqterm.cfg.orig", + getPath(USER_CONFIG) + "fqterm.cfg")) { + return false; + } + + if (!checkFile(getPath(RESOURCE) + "userconf/address.cfg.orig", + getPath(USER_CONFIG) + "address.cfg")) { + return false; + } + + if (!checkFile(getPath(RESOURCE) + "userconf/language.cfg.orig", + getPath(USER_CONFIG) + "language.cfg")) { + return false; + } + + //Copy schema files + if (checkPath(getPath(USER_CONFIG) + "schema")) { + checkFile(getPath(RESOURCE) + "schema/default.schema", + getPath(USER_CONFIG) + "schema/default.schema"); + + checkFile(getPath(RESOURCE) + "schema/Linux.schema", + getPath(USER_CONFIG) + "schema/Linux.schema"); + + checkFile(getPath(RESOURCE) + "schema/Softness.schema", + getPath(USER_CONFIG) + "schema/Softness.schema"); + + checkFile(getPath(RESOURCE) + "schema/VIM.schema", + getPath(USER_CONFIG) + "schema/VIM.schema"); + + checkFile(getPath(RESOURCE) + "schema/XTerm.schema", + getPath(USER_CONFIG) + "schema/XTerm.schema"); + } + + + //read settings from fqterm.cfg + FQTermConfig *conf = new FQTermConfig(getPath(USER_CONFIG) + "fqterm.cfg"); + + //set font + QString family = (conf->getItemValue("global", "font")); + + QString pointsize = conf->getItemValue("global", "pointsize"); + QString pixelsize = conf->getItemValue("global", "pixelsize"); + if (!family.isEmpty()) { + QFont font(family); + if (pointsize.toInt() > 0) { + font.setPointSize(pointsize.toInt()); + } + if (pixelsize.toInt() > 0) { + font.setPixelSize(pixelsize.toInt()); + } + QString openAntiAlias_ = conf->getItemValue("global", "antialias"); + if (openAntiAlias_ != "0") { + font.setStyleStrategy(QFont::PreferAntialias); + } + qApp->setFont(font); + } + + // zmodem and pool directory + QString pathZmodem = conf->getItemValue("preference", "zmodem"); + if (pathZmodem.isEmpty()) { + pathZmodem = getPath(USER_CONFIG) + "zmodem"; + } + + if (!checkPath(pathZmodem)) { + return false; + } + + QString pathPool = conf->getItemValue("preference", "pool"); + + if (pathPool.isEmpty()) { + pathPool = getPath(USER_CONFIG) + "pool/"; + } + + if (pathPool.right(1) != "/") { + pathPool.append('/'); + } + + QString pathCache = pathPool + "shadow-cache/"; + + if (!checkPath(pathPool) || !checkPath(pathCache)) { + return false; + } + + delete conf; + return true; +} + +void checkHelpExists(FQTermConfig* pConf) { + QString strTmp = pConf->getItemValue("bbs list", "num"); + int bbsCount = strTmp.toInt(); + + QString strSection; + + for (int i = 0; i < bbsCount; i++) { + strSection.sprintf("bbs %d", i); + strTmp = pConf->getItemValue(strSection, "name"); + if (strTmp == "FQTermHelp") + return; + } + pConf->setItemValue("bbs list", "num", QString("%1").arg(bbsCount + 1)); + saveAddress(pConf, bbsCount, FQTermParam::getFQBBSParam()); + pConf->save(getPath(USER_CONFIG) + "address.cfg"); +} + +void loadNameList(FQTermConfig *pConf, QStringList &listName) { + QString strTmp = pConf->getItemValue("bbs list", "num"); + + QString strSection; + + for (int i = 0; i < strTmp.toInt(); i++) { + strSection.sprintf("bbs %d", i); + listName.append(pConf->getItemValue(strSection, "name")); + } +} + +bool loadAddress(FQTermConfig *pConf, int n, FQTermParam ¶m) { + QString strTmp, strSection; + if (n < 0) { + strSection = "default"; + } else { + strSection.sprintf("bbs %d", n); + } + + if (!pConf->hasSection(strSection)) + return false; + + // check if larger than existence + strTmp = pConf->getItemValue("bbs list", "num"); + if (n >= strTmp.toInt()) { + return false; + } + param.name_ = pConf->getItemValue(strSection, "name"); + param.hostAddress_ = pConf->getItemValue(strSection, "addr"); + strTmp = pConf->getItemValue(strSection, "port"); + param.port_ = strTmp.toUShort(); + strTmp = pConf->getItemValue(strSection, "hosttype"); + param.hostType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "autologin"); + param.isAutoLogin_ = (strTmp != "0"); + param.preLoginCommand_ = pConf->getItemValue(strSection, "prelogin"); + param.userName_ = pConf->getItemValue(strSection, "user"); + param.password_ = pConf->getItemValue(strSection, "password"); + param.postLoginCommand_ = pConf->getItemValue(strSection, "postlogin"); + + strTmp = pConf->getItemValue(strSection, "bbscode"); + param.serverEncodingID_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "autofont"); + if (strTmp == "0") { + param.isFontAutoFit_ = 0; + } else if (strTmp == "2") { + param.isFontAutoFit_ = 2; + } else { + param.isFontAutoFit_ = 1; + } + strTmp = pConf->getItemValue(strSection, "alwayshighlight"); + param.isAlwaysHighlight_ = (strTmp != "0"); + strTmp = pConf->getItemValue(strSection, "ansicolor"); + param.isAnsiColor_ = (strTmp != "0"); + QString language; + QString font_name; + QString font_size; + language = FQTermParam::getLanguageName(true, false); + font_name = pConf->getItemValue(strSection, language + "fontname"); + font_size = pConf->getItemValue(strSection, language + "fontsize"); + if (!font_name.isEmpty()) { + param.englishFontName_ = font_name; + } + if (!font_size.isEmpty()) { + param.englishFontSize_ = font_size.toInt(); + } + //FIXME: Should be removed in next release!!!!! (Since 0.9.7) + if (font_name.isEmpty()) { + language = FQTermParam::getLanguageName(true); + font_name = pConf->getItemValue(strSection, language + "fontname"); + if (!font_name.isEmpty()) { + param.englishFontName_ = font_name; + } + } + + language = FQTermParam::getLanguageName(false, false); + font_name = pConf->getItemValue(strSection, language + "fontname"); + font_size = pConf->getItemValue(strSection, language + "fontsize"); + if (!font_name.isEmpty()) { + param.otherFontName_ = font_name; + } + if (!font_size.isEmpty()) { + param.otherFontSize_ = font_size.toInt(); + } + + //FIXME: Should be removed in next release!!!!! + if (font_name.isEmpty()) { + language = FQTermParam::getLanguageName(false); + font_name = pConf->getItemValue(strSection, language + "fontname"); + if (!font_name.isEmpty()) { + param.englishFontName_ = font_name; + } + } + + param.foregroundColor_.setNamedColor(pConf->getItemValue(strSection, "fgcolor")); + param.backgroundColor_.setNamedColor(pConf->getItemValue(strSection, "bgcolor")); + param.schemaFileName_ = pConf->getItemValue(strSection, "schemafile"); + + param.virtualTermType_ = pConf->getItemValue(strSection, "termtype"); + strTmp = pConf->getItemValue(strSection, "keytype"); + param.keyboardType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "backspacetype"); + param.backspaceType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "column"); + param.numColumns_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "row"); + param.numRows_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "scroll"); + param.numScrollLines_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "cursor"); + param.cursorType_ = strTmp.toInt(); + param.escapeString_ = pConf->getItemValue(strSection, "escape"); + + strTmp = pConf->getItemValue(strSection, "proxytype"); + param.proxyType_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "proxyauth"); + param.isAuthentation_ = (strTmp != "0"); + param.proxyHostName_ = pConf->getItemValue(strSection, "proxyaddr"); + strTmp = pConf->getItemValue(strSection, "proxyport"); + param.proxyPort_ = strTmp.toInt(); + param.proxyUserName_ = pConf->getItemValue(strSection, "proxyuser"); + param.proxyPassword_ = pConf->getItemValue(strSection, "proxypassword"); + strTmp = pConf->getItemValue(strSection, "protocol"); + param.protocolType_ = strTmp.toInt(); + param.sshUserName_ = pConf->getItemValue(strSection, "sshuser"); + param.sshPassword_ = pConf->getItemValue(strSection, "sshpassword"); + + strTmp = pConf->getItemValue(strSection, "maxidle"); + param.maxIdleSeconds_ = strTmp.toInt(); + param.replyKeyCombination_ = pConf->getItemValue(strSection, "replykey"); + if (param.replyKeyCombination_.isNull()) { + Q_ASSERT(false); + } + + param.antiIdleMessage_ = pConf->getItemValue(strSection, "antiidlestring"); + strTmp = pConf->getItemValue(strSection, "isantiidle"); + param.isAntiIdle_ = (strTmp != "0"); + param.autoReplyMessage_ = pConf->getItemValue(strSection, "autoreply"); + strTmp = pConf->getItemValue(strSection, "bautoreply"); + param.isAutoReply_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "reconnect"); + param.isAutoReconnect_ = (strTmp != "0"); + strTmp = pConf->getItemValue(strSection, "interval"); + param.reconnectInterval_ = strTmp.toInt(); + strTmp = pConf->getItemValue(strSection, "retrytimes"); + param.retryTimes_ = strTmp.toInt(); + + strTmp = pConf->getItemValue(strSection, "autoclosewin"); + param.isAutoCloseWin_ = (strTmp == "1"); + + strTmp = pConf->getItemValue(strSection, "alignmode"); + param.alignMode_ = strTmp.toInt(); + + + strTmp = pConf->getItemValue(strSection, "charspacing"); + param.charSpacing_ = strTmp.toInt(); + + strTmp = pConf->getItemValue(strSection, "linespacing"); + param.lineSpacing_ = strTmp.toInt(); + + strTmp = pConf->getItemValue(strSection, "loadscript"); + param.isAutoLoadScript_ = (strTmp != "0"); + param.autoLoadedScriptFileName_ = pConf->getItemValue(strSection, "scriptfile"); + + strTmp = pConf->getItemValue(strSection, "enablezmodem"); + param.enableZmodem_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "isbeep"); + param.isBeep_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "isbuzz"); + param.isBuzz_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "ismouse"); + param.isSupportMouse_ = (strTmp != "0"); + + strTmp = pConf->getItemValue(strSection, "menutype"); + param.menuType_ = strTmp.toInt(); + param.menuColor_.setNamedColor(pConf->getItemValue(strSection, "menucolor")); + + param.isColorCopy_ = (pConf->getItemValue(strSection, "colorcopy") != "0"); + param.isAutoCopy_ = (pConf->getItemValue(strSection, "autocopy") != "0"); + param.isRectSelect_ = (pConf->getItemValue(strSection, "rectselect") != "0"); + param.isAutoWrap_ = (pConf->getItemValue(strSection, "autowrap" ) == "1"); + + return true; +} + +void saveAddress(FQTermConfig *pConf, int n, const FQTermParam ¶m) { + QString strTmp, strSection; + if (n < 0) { + strSection = "default"; + } else { + strSection.sprintf("bbs %d", n); + } + + pConf->setItemValue(strSection, "name", param.name_); + pConf->setItemValue(strSection, "addr", param.hostAddress_); + strTmp.setNum(param.port_); + pConf->setItemValue(strSection, "port", strTmp); + strTmp.setNum(param.hostType_); + pConf->setItemValue(strSection, "hosttype", strTmp); + pConf->setItemValue(strSection, "autologin", param.isAutoLogin_ ? "1" : "0"); + pConf->setItemValue(strSection, "prelogin", param.preLoginCommand_); + pConf->setItemValue(strSection, "user", param.userName_); + pConf->setItemValue(strSection, "password", param.password_); + pConf->setItemValue(strSection, "postlogin", param.postLoginCommand_); + + strTmp.setNum(param.serverEncodingID_); + pConf->setItemValue(strSection, "bbscode", strTmp); + pConf->setItemValue(strSection, "autofont", strTmp.setNum(param.isFontAutoFit_)); + pConf->setItemValue(strSection, "alwayshighlight", param.isAlwaysHighlight_ ? + "1" : "0"); + pConf->setItemValue(strSection, "ansicolor", param.isAnsiColor_ ? "1" : "0"); + + pConf->setItemValue(strSection, FQTermParam::getLanguageName(true, false) + "fontname", param.englishFontName_); + strTmp.setNum(param.englishFontSize_); + pConf->setItemValue(strSection, FQTermParam::getLanguageName(true, false) + "fontsize", strTmp); + + pConf->setItemValue(strSection, FQTermParam::getLanguageName(false, false) + "fontname", param.otherFontName_); + strTmp.setNum(param.otherFontSize_); + pConf->setItemValue(strSection, FQTermParam::getLanguageName(false, false) + "fontsize", strTmp); + + pConf->setItemValue(strSection, "alignmode", strTmp.setNum(param.alignMode_)); + pConf->setItemValue(strSection, "charspacing", strTmp.setNum(param.charSpacing_)); + pConf->setItemValue(strSection, "linespacing", strTmp.setNum(param.lineSpacing_)); + + pConf->setItemValue(strSection, "bgcolor", param.backgroundColor_.name()); + pConf->setItemValue(strSection, "fgcolor", param.foregroundColor_.name()); + + pConf->setItemValue(strSection, "schemafile", param.schemaFileName_); + + pConf->setItemValue(strSection, "termtype", param.virtualTermType_); + strTmp.setNum(param.keyboardType_); + pConf->setItemValue(strSection, "keytype", strTmp); + strTmp.setNum(param.backspaceType_); + pConf->setItemValue(strSection, "backspacetype", strTmp); + strTmp.setNum(param.numColumns_); + pConf->setItemValue(strSection, "column", strTmp); + strTmp.setNum(param.numRows_); + pConf->setItemValue(strSection, "row", strTmp); + strTmp.setNum(param.numScrollLines_); + pConf->setItemValue(strSection, "scroll", strTmp); + strTmp.setNum(param.cursorType_); + pConf->setItemValue(strSection, "cursor", strTmp); + pConf->setItemValue(strSection, "escape", param.escapeString_); + + strTmp.setNum(param.proxyType_); + pConf->setItemValue(strSection, "proxytype", strTmp); + pConf->setItemValue(strSection, "proxyauth", param.isAuthentation_ ? "1" : "0"); + pConf->setItemValue(strSection, "proxyaddr", param.proxyHostName_); + strTmp.setNum(param.proxyPort_); + pConf->setItemValue(strSection, "proxyport", strTmp); + pConf->setItemValue(strSection, "proxyuser", param.proxyUserName_); + pConf->setItemValue(strSection, "proxypassword", param.proxyPassword_); + strTmp.setNum(param.protocolType_); + pConf->setItemValue(strSection, "protocol", strTmp); + pConf->setItemValue(strSection, "sshuser", param.sshUserName_); + pConf->setItemValue(strSection, "sshpassword", param.sshPassword_); + + strTmp.setNum(param.maxIdleSeconds_); + pConf->setItemValue(strSection, "maxidle", strTmp); + pConf->setItemValue(strSection, "replykey", param.replyKeyCombination_); + pConf->setItemValue(strSection, "antiidlestring", param.antiIdleMessage_); + pConf->setItemValue(strSection, "isantiidle", param.isAntiIdle_?"1" : "0"); + pConf->setItemValue(strSection, "bautoreply", param.isAutoReply_ ? "1" : "0"); + pConf->setItemValue(strSection, "autoreply", param.autoReplyMessage_); + pConf->setItemValue(strSection, "reconnect", param.isAutoReconnect_? "1" : "0"); + strTmp.setNum(param.reconnectInterval_); + pConf->setItemValue(strSection, "interval", strTmp); + strTmp.setNum(param.retryTimes_); + pConf->setItemValue(strSection, "retrytimes", strTmp); + pConf->setItemValue(strSection, "autoclosewin", param.isAutoCloseWin_? "1" : "0"); + + pConf->setItemValue(strSection, "loadscript", param.isAutoLoadScript_ ? "1" : "0"); + pConf->setItemValue(strSection, "scriptfile", param.autoLoadedScriptFileName_); + + pConf->setItemValue(strSection, "enablezmodem", param.enableZmodem_? "1" : "0"); + + pConf->setItemValue(strSection, "isbeep", param.isBeep_? "1" : "0"); + pConf->setItemValue(strSection, "isbuzz", param.isBuzz_? "1" : "0"); + pConf->setItemValue(strSection, "ismouse", param.isSupportMouse_? "1" : "0"); + + strTmp.setNum(param.menuType_); + pConf->setItemValue(strSection, "menutype", strTmp); + pConf->setItemValue(strSection, "menucolor", param.menuColor_.name()); + + pConf->setItemValue(strSection, "colorcopy", param.isColorCopy_? "1" : "0"); + pConf->setItemValue(strSection, "autocopy", param.isAutoCopy_? "1" : "0"); + pConf->setItemValue(strSection, "rectselect", param.isRectSelect_? "1" : "0"); + pConf->setItemValue(strSection, "autowrap", param.isAutoWrap_?"1":"0"); + +} + +static QString getResourceDir(const QString &prefix) { + QString res; + + std::string fqterm_resource; + + char *p = NULL; + if ((p = getenv("FQTERM_RESOURCE")) != NULL) + fqterm_resource = p; + + if (fqterm_resource.size() == 0) { +#if defined(WIN32) + res = prefix; +#elif defined(__APPLE__) + res = prefix + "../Resources/"; +#else + res = prefix + "share/FQTerm/"; +#endif + } else { + res = QString::fromLocal8Bit(fqterm_resource.c_str()); + } + + if (res[res.size() - 1] != '/') + res += '/'; + + return res; +} + +static QString getInstallPrefix() { + QString res; + + std::string fqterm_prefix; + + char *p = NULL; + if ((p = getenv("FQTERM_PREFIX")) != NULL) + fqterm_prefix = p; + + if (fqterm_prefix.size() == 0) { + res = QCoreApplication::applicationDirPath() + "/"; + } else { + res = QString::fromLocal8Bit(fqterm_prefix.c_str()); + } + + if (res[res.size() - 1] != '/') + res += '/'; + + return res; +} + +static QString getUserDataDir() { + char *evnDataDir = NULL; + if ((evnDataDir = getenv("FQTERM_DATADIR")) != NULL) { + std::string fqterm_data = evnDataDir; + if (fqterm_data[fqterm_data.size() - 1] != '/' +#ifdef WIN32 + || fqterm_data[fqterm_data.size() - 1] != '\\' +#endif + ) + fqterm_data += '/'; + if (fqterm_data.length() != 0) { + return QString::fromLocal8Bit(fqterm_data.c_str()); + } + } + +#ifdef WIN32 + char buffer[MAX_PATH]; + SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, buffer); + std::string dir(buffer); + + if (dir[dir.size() - 1] != '\\') { + dir += '\\'; + } + return QString::fromLocal8Bit(dir.c_str()) + "FQTerm/"; +#else + char *p = NULL; + + std::string home; + if ((p = getenv("HOME")) != NULL) + home = p; + if (home.size() == 0) + home = "/root/"; + + if (home[home.size() - 1] != '/') + home += '/'; + + return QString::fromLocal8Bit(home.c_str()) + ".fqterm/"; +#endif +} + +} // namespace FQTerm diff --git a/src/common/fqterm_path.h b/src/common/fqterm_path.h new file mode 100644 index 0000000..08611be --- /dev/null +++ b/src/common/fqterm_path.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_PATH_H +#define FQTERM_PATH_H + +class QString; +class QStringList; + +class FQTermConfig; +class FQTermParam; + +namespace FQTerm { + +enum PathCategory {RESOURCE, USER_CONFIG}; + +const QString &getPath(PathCategory category); + +bool iniSettings(); + +void checkHelpExists(FQTermConfig*); +void loadNameList(FQTermConfig *, QStringList &); +bool loadAddress(FQTermConfig *, int, FQTermParam &); +void saveAddress(FQTermConfig *, int, const FQTermParam &); + +void clearDir(const QString &path); +} // namespace FQTerm + +#endif // FQTERM_PATH_H diff --git a/src/common/fqterm_shortcuthelper.cpp b/src/common/fqterm_shortcuthelper.cpp new file mode 100644 index 0000000..8c18643 --- /dev/null +++ b/src/common/fqterm_shortcuthelper.cpp @@ -0,0 +1,298 @@ +/*************************************************************************** + * 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 "fqterm_shortcuthelper.h" +#include "fqterm_config.h" +#include "fqterm_path.h" + +#include <QWidget> +#include <QAction> +#include <QPixmap> +namespace FQTerm +{ + +FQTermShortcutHelper::FQTermShortcutHelper(FQTermConfig* config, QWidget* actionParent) : + config_(config), + actionParent_(actionParent) +{ + initShortcutDescriptionTable(); +} + +QString FQTermShortcutHelper::getShortcutText(int shortcut) +{ + if (!config_) + return ""; + QString result = getShortcutConfig(shortcut); + if (result == "") + result = getShortcutDefaultText(shortcut); + else if (result == "Undefined") + result = ""; + return result; +} + +void FQTermShortcutHelper::initShortcutDescriptionTable() +{ + initShortcutDescriptionTableEntry(CONNECT, "connect", tr(""), tr("Connect Host"), "connect"); + initShortcutDescriptionTableEntry(CASCADEWINDOWS, "cascadewindows", tr(""), tr("Cascade Windows")); + initShortcutDescriptionTableEntry(TILEWINDOWS, "tilewindows", tr(""), tr("Tils Windows")); + initShortcutDescriptionTableEntry(DISCONNECT, "disconnect", tr(""), tr("Disconnect Host"), "disconnect"); + initShortcutDescriptionTableEntry(ADDRESSBOOK, "addressbook", tr("F2"), tr("Address Book"), "address_book"); + initShortcutDescriptionTableEntry(QUICKLOGIN, "quicklogin", tr("F3"), tr("Quick Login"), "quick_login"); +#if defined(__APPLE__) + initShortcutDescriptionTableEntry(COPY, "copy", tr("Ctrl+C"), tr("Copy"), "copy"); + initShortcutDescriptionTableEntry(PASTE, "paste", tr("Ctrl+V"), tr("Paste"), "paste"); +#else + initShortcutDescriptionTableEntry(COPY, "copy", tr("Ctrl+Ins"), tr("Copy"), "copy"); + initShortcutDescriptionTableEntry(PASTE, "paste", tr("Shift+Insert"), tr("Paste"), "paste"); +#endif + initShortcutDescriptionTableEntry(COPYWITHCOLOR, "copywithcolor", tr(""), tr("Copy With Color"), "copy_with_color"); + getAction(COPYWITHCOLOR)->setCheckable(true); + initShortcutDescriptionTableEntry(RECTANGLESELECTION, "rectangleselection", tr(""), tr("Rectangle Selection"), "rectangle_selection"); + getAction(RECTANGLESELECTION)->setCheckable(true); + initShortcutDescriptionTableEntry(AUTOCOPYSELECTION, "autocopyselection", tr(""), tr("Auto Copy Selection")); + getAction(AUTOCOPYSELECTION)->setCheckable(true); + initShortcutDescriptionTableEntry(PASTEWORDWRAP, "pastewordwrap", tr(""), tr("Paste With Word Wrap")); + getAction(PASTEWORDWRAP)->setCheckable(true); + initShortcutDescriptionTableEntry(ENGLISHFONT, "englishfont", tr(""), tr("Set English Font")); + initShortcutDescriptionTableEntry(OTHERFONT, "nonenglishfont", tr(""), tr("Set Other Font")); + initShortcutDescriptionTableEntry(COLORSETTING, "colorsetting", tr(""), tr("Color Setting"), "ansi_color"); + initShortcutDescriptionTableEntry(REFRESHSCREEN, "refreshscreen", tr(""), tr("Refresh Screen"), "refresh"); + initShortcutDescriptionTableEntry(ANSICOLOR, "ansicolor", tr(""), tr("Toggle Ansi Color"), "toggle_ansi_color"); + getAction(ANSICOLOR)->setCheckable(true); + initShortcutDescriptionTableEntry(UIFONT, "uifont", tr(""), tr("Set UI Font")); + initShortcutDescriptionTableEntry(FULLSCREEN, "fullscreen", tr("F6"), tr("Toggle Full Screen")); + getAction(FULLSCREEN)->setCheckable(true); + initShortcutDescriptionTableEntry(BOSSCOLOR, "bosscolor", tr("F12"), tr("Toggle Boss Color")); + getAction(BOSSCOLOR)->setCheckable(true); + initShortcutDescriptionTableEntry(SWITCHBAR, "switchbar", tr(""), tr("Toggle Switch Bar")); + getAction(SWITCHBAR)->setCheckable(true); + initShortcutDescriptionTableEntry(CURRENTSETTING, "currentsetting", tr(""), tr("Current Session Setting"), "preferences"); + initShortcutDescriptionTableEntry(SEARCHIT, "googleit", tr("Ctrl+Alt+G"), tr("Google selected words")); + initShortcutDescriptionTableEntry(WEIBOSHARE, "shareit", tr("Alt+`"), tr("Share selected text and highlighted URL to weibo")); + initShortcutDescriptionTableEntry(EXTERNALEDITOR, "externaleditor", tr("Ctrl+Alt+E"), tr("Invoke external editor")); + initShortcutDescriptionTableEntry(FASTPOST, "fastpost", tr("Ctrl+Alt+F"), tr("Fast post from clipboard")); + initShortcutDescriptionTableEntry(DEFAULTSETTING, "defaultsetting", tr(""), tr("Default Setting")); + initShortcutDescriptionTableEntry(PREFERENCE, "preference", tr(""), tr("Preference"), "preferences"); + initShortcutDescriptionTableEntry(EDITSCHEMA, "schema", tr(""), tr("Edit Schema")); + initShortcutDescriptionTableEntry(SHORTCUTSETTING, "shortcut", tr(""), tr("Shorcut Setting")); + initShortcutDescriptionTableEntry(COPYARTICLE, "copyarticle", tr("F9"), tr("Copy Article"), "get_article_fulltext"); + initShortcutDescriptionTableEntry(ANTIIDLE, "antiidle", tr(""), tr("Toggle Anti Idle"), "anti_idle"); + getAction(ANTIIDLE)->setCheckable(true); + initShortcutDescriptionTableEntry(AUTOREPLY, "autoreply", tr(""), tr("Toggle Auto Reply"), "auto_reply"); + getAction(AUTOREPLY)->setCheckable(true); + initShortcutDescriptionTableEntry(VIEWMESSAGE, "viewmessage", tr("F10"), tr("View Messages"), "view_messages"); + initShortcutDescriptionTableEntry(IPLOOKUP, "iplookup", tr(""), tr("IP Lookup")); + initShortcutDescriptionTableEntry(BEEP, "beep", tr(""), tr("Toggle Beep"), "beep"); + getAction(BEEP)->setCheckable(true); + initShortcutDescriptionTableEntry(MOUSESUPPORT, "mousesupport", tr(""), tr("Toggle Mouse Support"), "mouse"); + getAction(MOUSESUPPORT)->setCheckable(true); + initShortcutDescriptionTableEntry(IMAGEVIEWER, "imageviewer", tr(""), tr("Image Viewer"), "image_viewer"); + initShortcutDescriptionTableEntry(RUNSCRIPT, "runscript", tr("F7"), tr("Run Script")); + initShortcutDescriptionTableEntry(STOPSCRIPT, "stop", tr("F8"), tr("Stop Script")); +#ifdef HAVE_PYTHON + initShortcutDescriptionTableEntry(RUNPYTHONSCRIPT, "runpythonscript", tr("Ctrl+F1"), tr("Run Python Script")); +#endif //HAVE_PYTHON + initShortcutDescriptionTableEntry(ABOUT, "about", tr("Shift+F1"), tr("About")); + initShortcutDescriptionTableEntry(HOMEPAGE, "homepage", tr(""), tr("Homepage")); + initShortcutDescriptionTableEntry(EXIT, "exit", tr(""), tr("Exit FQTerm")); + initShortcutDescriptionTableEntry(COLORCTL_NO, "colorctlno", tr(""), tr("Set Color Ctrl to None")); + getAction(COLORCTL_NO)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_SMTH, "colorctlsmth", tr(""), tr("Set Color Ctrl to **[")); + getAction(COLORCTL_SMTH)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_PTT, "colorctlptt", tr(""), tr("Set Color Ctrl to ^u[")); + getAction(COLORCTL_PTT)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_OLD_CUSTOM, "colorctloldcustom", tr(""), tr("Set Color Ctrl to old custom")); + getAction(COLORCTL_OLD_CUSTOM)->setCheckable(true); + initShortcutDescriptionTableEntry(COLORCTL_CUSTOM, "colorctlcustom", tr(""), tr("Set Color Ctrl to custom")); + getAction(COLORCTL_CUSTOM)->setCheckable(false); + initShortcutDescriptionTableEntry(AUTORECONNECT, "autoreconnect", tr(""), tr("Toggle Auto Reconnect"), "auto_reconnect"); + getAction(AUTORECONNECT)->setCheckable(true); + initShortcutDescriptionTableEntry(SCROLLBAR_LEFT, "scrollbarleft", tr(""), tr("Set Scrollbar to Left")); + getAction(SCROLLBAR_LEFT)->setCheckable(true); + initShortcutDescriptionTableEntry(SCROLLBAR_RIGHT, "scrollbarright", tr(""), tr("Set Scrollbar to Right")); + getAction(SCROLLBAR_RIGHT)->setCheckable(true); + initShortcutDescriptionTableEntry(SCROLLBAR_HIDDEN, "scrollbarhidden", tr(""), tr("Set Scrollbar Hidden")); + getAction(SCROLLBAR_HIDDEN)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_GOOGLE, "searchgoogle", tr(""), tr("Use Google")); + getAction(SEARCH_GOOGLE)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_BAIDU, "searchbaidu", tr(""), tr("Use Baidu")); + getAction(SEARCH_BAIDU)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_BING, "searchbing", tr(""), tr("Use Bing")); + getAction(SEARCH_BING)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_YAHOO, "searchyahoo", tr(""), tr("Use Yahoo!")); + getAction(SEARCH_YAHOO)->setCheckable(true); + initShortcutDescriptionTableEntry(SEARCH_CUSTOM, "searchcustom", tr(""), tr("Use Customized SE")); + getAction(SEARCH_CUSTOM)->setCheckable(true); + initShortcutDescriptionTableEntry(LANGUAGE_ENGLISH, "languageenglish", tr(""), tr("Choose UI Language: English")); + getAction(LANGUAGE_ENGLISH)->setCheckable(true); + initShortcutDescriptionTableEntry(SAVESETTING, "savesetting", tr(""), tr("Save Current Session Setting"), "save_setting"); + +#if defined(__APPLE__) + QString opt(tr("Ctrl")); +#else + QString opt(tr("Alt")); +#endif + + initShortcutDescriptionTableEntry(NEXTWINDOW, "nextwindow", opt + tr("+Right"), tr("Next Window")); + initShortcutDescriptionTableEntry(PREVWINDOW, "prevwindow", opt + tr("+Left"), tr("Prev Window")); + + initShortcutDescriptionTableEntry(GLOBAL_SHOW_FQTERM, "showfqterm", tr("Ctrl+Alt+Q"), tr("Show FQTerm")); + //index, key, default shortcut, descritption + + retranslateActions(); +} + +void FQTermShortcutHelper::retranslateAction(int shortcut, const QString& text) +{ + if (getAction(shortcut)) + getAction(shortcut)->setText(text); +} + +void FQTermShortcutHelper::retranslateActions() { + retranslateAction(CONNECT, tr("&Connect")); + retranslateAction(DISCONNECT, tr("&Disconnect")); + retranslateAction(ADDRESSBOOK, tr("&Address book")); + retranslateAction(QUICKLOGIN, tr("&Quick login")); + retranslateAction(COPY, tr("&Copy")); + retranslateAction(PASTE, tr("&Paste")); + retranslateAction(COPYWITHCOLOR, tr("C&opy with color")); + retranslateAction(RECTANGLESELECTION, tr("&Rectangle select")); + retranslateAction(AUTOCOPYSELECTION, tr("Auto copy &select")); + retranslateAction(PASTEWORDWRAP, tr("P&aste with wordwrap")); + retranslateAction(ENGLISHFONT, tr("&English Font")); + retranslateAction(OTHERFONT, tr("O&ther Font")); + retranslateAction(COLORSETTING, tr("&Color Setting")); + retranslateAction(ANSICOLOR, tr("&Use ANSI Color")); + retranslateAction(REFRESHSCREEN, tr("&Refresh")); + retranslateAction(UIFONT, tr("U&I font")); + retranslateAction(FULLSCREEN, tr("Fullscree&n")); + retranslateAction(BOSSCOLOR, tr("B&oss Color")); + retranslateAction(SWITCHBAR, tr("S&witch Bar")); + retranslateAction(SEARCHIT, tr("&Search It")); + retranslateAction(WEIBOSHARE, tr("Sha&re It")); + retranslateAction(EXTERNALEDITOR, tr("E&xternal Editor")); + retranslateAction(FASTPOST, tr("&Fast Post")); + retranslateAction(CURRENTSETTING, tr("&Setting for current session")); + retranslateAction(DEFAULTSETTING, tr("&Default setting")); + retranslateAction(PREFERENCE, tr("&Preferences...")); + retranslateAction(SHORTCUTSETTING, tr("Short&cut Setting")); + retranslateAction(EDITSCHEMA, tr("&Edit Schema")); + retranslateAction(COPYARTICLE, tr("&Copy article")); + retranslateAction(ANTIIDLE, tr("Anti &idle")); + retranslateAction(AUTOREPLY, tr("Auto &reply")); + retranslateAction(VIEWMESSAGE, tr("&View messages")); + retranslateAction(IPLOOKUP, tr("I&P Lookup")); + retranslateAction(BEEP, tr("&Beep")); + retranslateAction(MOUSESUPPORT, tr("&Mouse support")); + retranslateAction(IMAGEVIEWER, tr("Ima&ge viewer")); + retranslateAction(RUNSCRIPT, tr("&Run...")); + retranslateAction(STOPSCRIPT, tr("&Stop")); + retranslateAction(RUNPYTHONSCRIPT, tr("Run &Python...")); + retranslateAction(ABOUT, tr("About &FQTerm")); + retranslateAction(HOMEPAGE, tr("FQTerm's &Homepage")); + retranslateAction(CASCADEWINDOWS, tr("&Cascade")); + retranslateAction(TILEWINDOWS, tr("&Tile")); + retranslateAction(EXIT, tr("&Exit")); + retranslateAction(COLORCTL_NO, tr("&None")); + retranslateAction(COLORCTL_SMTH, tr("&ESC ESC [")); + retranslateAction(COLORCTL_PTT, tr("Ctrl+&U[")); + retranslateAction(COLORCTL_CUSTOM, tr("&Custom...")); + retranslateAction(AUTORECONNECT, tr("Reconnect When Disconnected By Host")); + retranslateAction(NEXTWINDOW, tr("Next Window")); + retranslateAction(PREVWINDOW, tr("Prev Window")); + retranslateAction(LANGUAGE_ENGLISH, tr("&English")); + retranslateAction(SCROLLBAR_HIDDEN, tr("&Hide")); + retranslateAction(SCROLLBAR_RIGHT, tr("&Right")); + retranslateAction(SCROLLBAR_LEFT, tr("&Left")); + retranslateAction(SEARCH_GOOGLE, tr("&Google")); + retranslateAction(SEARCH_BAIDU, tr("&Baidu")); + retranslateAction(SEARCH_BING, tr("&Bing")); + retranslateAction(SEARCH_YAHOO, tr("&Yahoo!")); + retranslateAction(SEARCH_CUSTOM, tr("&Custom")); + retranslateAction(SAVESETTING, tr("Save Settin&g")); +} + + +void FQTermShortcutHelper::resetAllShortcutText() +{ + for (int i = FQTERM_APPLICATION_SHORTCUT_START + 1; i < FQTERM_APPLICATION_SHORTCUT_END; ++i) + { + resetShortcutText(i); + } +} + +void FQTermShortcutHelper::resetShortcutText(int shortcut) +{ + if (!config_) + return; + setShortcutText(shortcut, getShortcutDefaultText(shortcut)); +} + +void FQTermShortcutHelper::setShortcutText(int shortcut, const QString& text) +{ + if (!config_) + return; + QString val = text.trimmed(); + if (val == "") + val = "Undefined"; + setShortcutConfig(shortcut, val); + if (getAction(shortcut)) + getAction(shortcut)->setShortcut(val); +} + +FQTermShortcutHelper::~FQTermShortcutHelper() +{ +} + +QString FQTermShortcutHelper::getShortcutConfig(int shortcut) +{ + return config_->getItemValue(getShortcutSection(), getShortcutKey(shortcut)); +} + +void FQTermShortcutHelper::setShortcutConfig(int shortcut, const QString& text) +{ + config_->setItemValue(getShortcutSection(), getShortcutKey(shortcut), text); +} + +void FQTermShortcutHelper::initShortcutDescriptionTableEntry(int index, const QString& key, const QString& defaultshortcuttext, const QString& description, const QString& actionSkin) { + shortcutDescriptionTable_[index] = ShortcutDescriptionEntry(key, defaultshortcuttext, description); + shortcutDescriptionTable_[index].action_ = new QAction(actionParent_); + if (actionParent_) { + actionParent_->addAction(shortcutDescriptionTable_[index].action_); + } + shortcutDescriptionTable_[index].action_->setShortcut(getShortcutText(index)); + if (actionSkin != QString::null) + shortcutDescriptionTable_[index].action_->setIcon(QPixmap(getPath(RESOURCE) + "pic/" + actionSkin + ".png")); +} + + +FQTermShortcutHelper::ShortcutDescriptionEntry::ShortcutDescriptionEntry(const QString& key /*= QString("")*/, + const QString& defaultshortcuttext /*= QString("")*/, + const QString& description /*= QString("")*/) : + key_(key), + defaultshortcuttext_(defaultshortcuttext), + description_(description), + action_(NULL) {} + +FQTermShortcutHelper::ShortcutDescriptionEntry::~ShortcutDescriptionEntry() { + delete action_; +} +}//namespace FQTerm + +#include "fqterm_shortcuthelper.moc"
\ No newline at end of file diff --git a/src/common/fqterm_shortcuthelper.h b/src/common/fqterm_shortcuthelper.h new file mode 100644 index 0000000..7e77df7 --- /dev/null +++ b/src/common/fqterm_shortcuthelper.h @@ -0,0 +1,175 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef __FQTERM_SHORTCUTHELPER__ +#define __FQTERM_SHORTCUTHELPER__ + +#include "fqterm.h" +#include <QObject> +#include <QString> +#include <QMap> + +class QWidget; +class QAction; +namespace FQTerm +{ +class FQTermConfig; + + +#define FQTERM_ADDACTION(WIDGET, NAME, RECEIVER, FUNCTION) \ + do{ \ + QAction *action = getAction((FQTermShortcutHelper::NAME));\ + QObject::disconnect(action, SIGNAL(triggered()), (RECEIVER), SLOT(FUNCTION())); \ + FQ_VERIFY(connect(action, SIGNAL(triggered()), (RECEIVER), SLOT(FUNCTION()))); \ + (WIDGET)->addAction(action);\ + } while(0) + + + +class FQTermShortcutHelper : public QObject +{ + Q_OBJECT; +public: + enum FQTERM_SHORTCUT + { + FQTERM_APPLICATION_SHORTCUT_START = 0, + CONNECT, + DISCONNECT, + ADDRESSBOOK, //F2 + QUICKLOGIN, //F3 + COPY, //Ctrl+Ins under lin & win, Ctrl+C under mac + PASTE, //Shift+Insert under lin & win, Ctrl+V under mac + COPYWITHCOLOR, + RECTANGLESELECTION, + AUTOCOPYSELECTION, + PASTEWORDWRAP, + ENGLISHFONT, + OTHERFONT, + COLORSETTING, + ANSICOLOR, + REFRESHSCREEN, //F5 + UIFONT, + FULLSCREEN, //F6 + BOSSCOLOR, //F12 + SWITCHBAR, + SEARCHIT, //Ctrl+Alt+G + WEIBOSHARE, + EXTERNALEDITOR, //Ctrl+Alt+E + FASTPOST, //Ctrl+Alt+F + CURRENTSETTING, + DEFAULTSETTING, + SAVESETTING, + PREFERENCE, + SHORTCUTSETTING, + EDITSCHEMA, + COPYARTICLE, //F9 + ANTIIDLE, + AUTOREPLY, + VIEWMESSAGE, //F10 + IPLOOKUP, + BEEP, + MOUSESUPPORT, + IMAGEVIEWER, + RUNSCRIPT, //F7 + STOPSCRIPT, //F8 + RUNPYTHONSCRIPT, //Ctrl+F1 + ABOUT, //F1 + HOMEPAGE, + CASCADEWINDOWS, + TILEWINDOWS, + EXIT, + COLORCTL_NO, + COLORCTL_SMTH, + COLORCTL_PTT, + COLORCTL_OLD_CUSTOM, + COLORCTL_CUSTOM, + AUTORECONNECT, + SCROLLBAR_LEFT, + SCROLLBAR_RIGHT, + SCROLLBAR_HIDDEN, + SEARCH_GOOGLE, + SEARCH_BAIDU, + SEARCH_BING, + SEARCH_YAHOO, + SEARCH_CUSTOM, + LANGUAGE_ENGLISH, + NEXTWINDOW, + PREVWINDOW, + GLOBAL_SHOW_FQTERM, + FQTERM_APPLICATION_SHORTCUT_END, + }; + + +public: + FQTermShortcutHelper(FQTermConfig* config, QWidget* actionParent); + ~FQTermShortcutHelper(); + +private: + struct ShortcutDescriptionEntry + { + ShortcutDescriptionEntry(const QString& key = QString(""), const QString& defaultshortcuttext = QString(""), const QString& description = QString("")); + ~ShortcutDescriptionEntry(); + QString key_; + QString defaultshortcuttext_; + QString description_; + QAction* action_; + }; + void initShortcutDescriptionTable(); + FQTermConfig* config_; + QWidget* actionParent_; + QMap<int, ShortcutDescriptionEntry> shortcutDescriptionTable_; + void initShortcutDescriptionTableEntry(int index, const QString& key, const QString& defaultshortcuttext, const QString& description, const QString& actionSkin = QString::null); + +public: + + QString getShortcutText(int shortcut) ; + QString getShortcutDescription(int shortcut) { + return shortcutDescriptionTable_[shortcut].description_; + } + QString getShortcutDefaultText(int shortcut) { + return shortcutDescriptionTable_[shortcut].defaultshortcuttext_; + } + void setShortcutText(int shortcut, const QString& text); + void resetShortcutText(int shortcut); + void resetAllShortcutText(); + + QAction* getAction(int shortcut) { + return shortcutDescriptionTable_[shortcut].action_; + } + void retranslateActions(); +private: + //These functions are used to save shortcut + QString getShortcutSection() { + return QString("shortcutsettings"); + } + QString getShortcutKey(int shortcut) { + return shortcutDescriptionTable_[shortcut].key_; + } + + QString getShortcutConfig(int shortcut); + void setShortcutConfig(int shortcut, const QString& text); + void retranslateAction(int shortcut, const QString& text); +}; + + +}//namespace FQTerm + + +#endif diff --git a/src/common/fqterm_sound.cpp b/src/common/fqterm_sound.cpp new file mode 100644 index 0000000..96bcc83 --- /dev/null +++ b/src/common/fqterm_sound.cpp @@ -0,0 +1,733 @@ +/*************************************************************************** + * 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 <QSound> +#include <QFile> +#include <QMessageBox> +#include <stdio.h> +#include <stdlib.h> + +/*******************************************************/ +/********** OSS code is from OpenSound System **********/ +/*******************************************************/ +#ifdef AUDIO_OSS +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> + +#if defined(_OS_FREEBSD_) || defined(_OS_LINUX_) +#include <sys/soundcard.h> +#define FQ_AUDIO_DEV "/dev/dsp" +#else +#include <machine/soundcard.h> +#define FQ_AUDIO_DEV "/dev/audio" +#endif + +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_ADPCM 0x0002 +#define WAVE_FORMAT_ALAW 0x0006 +#define WAVE_FORMAT_MULAW 0x0007 +#define WAVE_FORMAT_IMA_ADPCM 0x0011 + +#ifndef AFMT_S32_LE +#define AFMT_S32_LE 0x00001000 /* Little endian signed 32-bit */ +#endif + +typedef struct { + int coeff1, coeff2; +} adpcm_coeff; + +#endif /* AUDIO_OSS */ + +/* 2008.07.06, ecore.cn@gmail.com, alsa sound for FQTerm ... */ +#ifdef AUDIO_ALSA +#include <alsa/asoundlib.h> +#include <stdint.h> +typedef struct tag_FQ_WAVE_FILE_HEADER { + uint32_t rid; /* RIFF ID */ + uint32_t rsz; /* RIFF SIZE */ + uint32_t wid; /* WAVE ID */ +} +FQWFH; + +typedef struct tag_FQ_WAVE_FORMAT_HEADER { + uint32_t fid; /* FORMAT ID */ + uint32_t fsz; /* FORMAT SIZE */ + uint16_t aid; /* AUDIO ID */ + uint16_t ach; /* AUDIO CHANNELS */ + uint32_t asr; /* AUDIO SAMPLE RATE */ + uint32_t abr; /* AUDIO BYTE RATE */ + uint16_t aba; /* AUDIO BLOCK ALIGNMENT */ + uint16_t abps; /* AUDIO BITS PER SAMPLE */ +} +FQWMH; + +typedef struct tag_FQ_WAVE_DATA_HEADER { + uint32_t did; /* DATA ID */ + uint32_t dsz; /* DATA SIZE */ +} +FQWDH; + +#endif /* AUDIO_ALSA */ + +#include "common.h" +#include "fqterm_sound.h" + +namespace FQTerm { + +FQTermSound::FQTermSound(const QString &filename, QObject *parent, + const char *name) + : QThread(parent), soundFile_(filename) { + connect(this, SIGNAL(finished()), SLOT(deleteInstance())); + connect(this, SIGNAL(terminated()), SLOT(deleteInstance())); +} + +FQTermSound::~FQTermSound() { +} + +void FQTermSound::deleteInstance() { + FQ_TRACE("sound", 3) << "sound instance [" << (void*)this << "] is to be deleted!"; + delete this; +} + +void FQTermSound::run() { + if (QFile::exists(soundFile_)) { +#if !defined(AUDIO_OSS) && !defined(AUDIO_ALSA) + QSound::play(soundFile_); +#else + this->play(); +#endif + } +} + +void FQTermExternalSound::setPlayer(const QString &playername) { + playerName_ = playername; +} + +void FQTermExternalSound::play() { + if (QFile::exists(soundFile_)) { + runProgram(playerName_, soundFile_, false); + } +} + +/*******************************************************/ +/********** OSS code is from OpenSound System **********/ +/*******************************************************/ +#ifdef AUDIO_OSS +static int le_int (unsigned char *p, int l) { + + int i, val; + val = 0; + + for (i = l - 1; i >= 0; i--) { + val = (val << 8) | p[i]; + } + + return val; +} + +static int setupDevice(int audiofd, int channels, int bits, int speed) { + + int tmp; + + tmp = bits; + if (ioctl(audiofd, SNDCTL_DSP_SETFMT, &tmp) == -1) { + return 0; + } + + if (tmp != bits) { + return 0; + } + + tmp = channels; + if (ioctl(audiofd, SNDCTL_DSP_CHANNELS, &tmp) == -1) { + return 0; + } + + if (tmp != channels) { + return 0; + } + + tmp = speed; + if (ioctl(audiofd, SNDCTL_DSP_SPEED, &tmp) == -1) { + return 0; + } + + return 1; +} + +static void dumpData(int audiofd, int soundfd, int filesize) { + + int bsize, l; + unsigned char buf[1024]; + bsize = sizeof(buf); + + while (filesize) { + + l = bsize; + + if (l > filesize) { + l = filesize; + } + + if ((l = read(soundfd, buf, l)) <= 0) { + return; + } + + if (write(audiofd, buf, l) == -1) { + return; + } + + filesize -= l; + } +} + +static void dumpData24 (int audiofd, int soundfd, int filesize) { + + int bsize, i, l; + unsigned char buf[1024]; + int outbuf[1024], outlen=0; + int sample_s32; + bsize = sizeof(buf); + + filesize -= filesize % 3; + + while(filesize >= 3) { + + l = bsize - bsize % 3; + if (l > filesize) { + l = filesize; + } + + if(l < 3) { + break; + } + + if ((l = read(soundfd, buf, l)) <= 0) { + return; + } + + outlen=0; + + for(i=0; i<l; i+= 3) { + + unsigned int *u32 = (unsigned int *)&sample_s32; /* Alias */ + + /* Read the litle endian input samples */ + *u32 = (buf[i] << 8) | (buf[i+1] << 16) | (buf[i+2]<<24); + outbuf[outlen++]=sample_s32; + + } + + if (write(audiofd, outbuf, outlen*sizeof(int)) == -1) { + return; + } + + filesize -= l; + } +} + +static void playAdpcmWave(int audiofd, int soundfd, unsigned char *hdr, int l) { + + int i, n, dataleft, x; + + adpcm_coeff coeff[32]; + static int AdaptionTable[] = { 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 + }; + + unsigned char buf[4096]; + + int channels = 1; + int bits = 8; + int speed = 11025; + int p = 12, max, outp; + int nBlockAlign, wSamplesPerBlock, wNumCoeff; + int fmt = -1; + int nib; + + unsigned char outbuf[64 * 1024]; + + while (p < l - 16 && memcmp(&hdr[p], "data", 4) != 0) { + + n = le_int(&hdr[p + 4], 4); + if (memcmp(&hdr[p], "fmt ", 4) == 0) { + + fmt = le_int(&hdr[p + 8], 2); + channels = le_int(&hdr[p + 10], 2); + speed = le_int(&hdr[p + 12], 4); + nBlockAlign = le_int(&hdr[p + 20], 2); + bits = AFMT_S16_LE; + wSamplesPerBlock = le_int(&hdr[p + 26], 2); + wNumCoeff = le_int(&hdr[p + 28], 2); + + x = p + 30; + + for (i = 0; i < wNumCoeff; i++) { + + coeff[i].coeff1 = (short)le_int(&hdr[x], 2); + x += 2; + coeff[i].coeff2 = (short)le_int(&hdr[x], 2); + x += 2; + } + } + + p += n + 8; + } + + if (p < l - 16 && memcmp(&hdr[p], "data", 4) == 0) { + + dataleft = n = le_int(&hdr[p + 4], 4); + p += 8; + + if (lseek(soundfd, p, SEEK_SET) == -1) { + return; + } + + if (fmt != WAVE_FORMAT_ADPCM) { + return; + } + + if (!setupDevice(audiofd, channels, bits, speed)) { + return; + } + +#define OUT_SAMPLE(s) { \ + if (s>32767)s=32767;else if(s<-32768)s=-32768; \ + outbuf[outp++] = (unsigned char)(s & 0xff); \ + outbuf[outp++] = (unsigned char)((s>>8) & 0xff); \ + n+=2; \ + if (outp>=max){write(audiofd, outbuf, outp);outp=0;}\ + } + +#define GETNIBBLE \ + ((nib==0) ? \ + (buf[x + nib++] >> 4) & 0x0f : \ + buf[x++ + --nib] & 0x0f \ + ) + + max = 1024; + outp = 0; + + while (dataleft > nBlockAlign && + read(soundfd, buf, nBlockAlign) == nBlockAlign) { + + int predictor[2], delta[2], samp1[2], samp2[2]; + int x = 0; + dataleft -= nBlockAlign; + + nib = 0; + n = 0; + + for (i = 0; i < channels; i++) { + predictor[i] = buf[x]; + x++; + } + + for (i = 0; i < channels; i++) { + delta[i] = (short)le_int(&buf[x], 2); + x += 2; + } + + for (i = 0; i < channels; i++) { + samp1[i] = (short)le_int(&buf[x], 2); + x += 2; + OUT_SAMPLE(samp1[i]); + } + + for (i = 0; i < channels; i++) { + samp2[i] = (short)le_int(&buf[x], 2); + x += 2; + OUT_SAMPLE(samp2[i]); + } + + while (n < (wSamplesPerBlock * 2 * channels)) { + + for (i = 0; i < channels; i++) { + + int pred, new_pred, error_delta, i_delta; + + pred = ((samp1[i] * coeff[predictor[i]].coeff1) + + (samp2[i] * coeff[predictor[i]].coeff2)) / 256; + i_delta = error_delta = GETNIBBLE; + + if (i_delta & 0x08) { + i_delta -= 0x10; /* Convert to signed */ + } + + new_pred = pred + (delta[i] * i_delta); + OUT_SAMPLE(new_pred); + + delta[i] = delta[i] * AdaptionTable[error_delta] / 256; + if (delta[i] < 16) { + delta[i] = 16; + } + + samp2[i] = samp1[i]; + samp1[i] = new_pred; + } + } + } + } + + if (outp > 0) { + write (audiofd, outbuf, outp /*(outp+3) & ~3 */ ); + } +} + +static void playWave(int audiofd, int soundfd, unsigned char *hdr, int l) { + + int filelen; + int n; + int channels = 1; + int bits = 8; + int file_bits = 8; + int speed = 11025; + int p = 12; + int fmt = -1; + + filelen = le_int(&hdr[4], 4); + + while(p < l - 16 && memcmp(&hdr[p], "data", 4) != 0) { + + n = le_int(&hdr[p + 4], 4); + + if (memcmp(&hdr[p], "fmt ", 4) == 0) { + + fmt = le_int(&hdr[p + 8], 2); + channels = le_int(&hdr[p + 10], 2); + speed = le_int(&hdr[p + 12], 4); + bits = le_int(&hdr[p + 22], 2); + + if (fmt == WAVE_FORMAT_ADPCM) { + playAdpcmWave(audiofd, soundfd, hdr, l); + return; + } + + p += n + 8; + } else { + break; + } + } + + if (p < l - 16 && memcmp(&hdr[p], "data", 4) == 0) { + + n = le_int(&hdr[p + 4], 4); + p += 8; + + if (lseek(soundfd, p, SEEK_SET) == -1) { + return; + } + + if (fmt != WAVE_FORMAT_PCM) { + switch (fmt) { + case WAVE_FORMAT_ALAW: + bits = AFMT_A_LAW; + break; + case WAVE_FORMAT_MULAW: + bits = AFMT_MU_LAW; + break; + case WAVE_FORMAT_IMA_ADPCM: + bits = AFMT_IMA_ADPCM; + break; + default: + return; + } + } + + file_bits = bits; + + if (bits == 32) { + bits = AFMT_S32_LE; + } else if (bits == 24) { + bits = AFMT_S32_LE; + } + + if (!setupDevice(audiofd, channels, bits, speed)) { + return; + } + + if (file_bits != 24) { + dumpData (audiofd, soundfd, n); + } else { + dumpData24 (audiofd, soundfd, n); + } + } +} +#endif /* AUDIO_OSS */ + +void FQTermSystemSound::play() { + +#ifdef AUDIO_OSS + int audio_fd = -1; + if ((audio_fd = open(FQ_AUDIO_DEV, O_WRONLY, 0)) == -1) { + FQ_TRACE("sound", 0) << "Error opening device: " << FQ_AUDIO_DEV; + return; + } + + int sound_fd = -1; + QFile soundFile(soundFile_); + + if (soundFile.open(QFile::ReadOnly)) { + sound_fd = soundFile.handle(); + } else { + FQ_TRACE("sound", 0) << "Error opening file: " << soundFile_; + close(audio_fd); + return; + } + + int l; + unsigned char sound_buf[1024]; + + if ((l = read(sound_fd, sound_buf, sizeof(sound_buf))) == -1) { + FQ_TRACE("sound", 0) << "Error reading file into buffer." << soundFile_; + soundFile.close(); + close(audio_fd); + return; + } + + if (l == 0) { + FQ_TRACE("sound", 0) << "Empty file: " << soundFile_; + soundFile.close(); + close(audio_fd); + return; + } + + lseek(sound_fd, 0, SEEK_SET); /* Start from the beginning */ + + if (l > 16 && + memcmp(&sound_buf[0], "RIFF", 4) == 0 && memcmp(&sound_buf[8], "WAVE", 4) == 0) { + + playWave(audio_fd, sound_fd, sound_buf, l); + } else { + FQ_TRACE("sound", 0) << "We play WAVE files only: " << soundFile_; + } + + soundFile.close(); + close(audio_fd); + +#undef OUTSAMPLE +#undef GETNIBBLE +#endif /* AUDIO_OSS */ + +/* 2008.07.06, ecore.cn@gmail.com, alsa sound for FQTerm ... */ +#ifdef AUDIO_ALSA + FILE *fp; + FQWFH wfh; + FQWMH wmh; + FQWDH wdh; + int endian, sz, len, count, ret; + unsigned int val; + snd_pcm_t *handle; + snd_pcm_hw_params_t *hwparams; + snd_pcm_sw_params_t *swparams; + snd_pcm_format_t format; + snd_pcm_uframes_t csz, vsz; + void *data; + +#define WAVE_UINT16(_x) (endian? ( \ + (((_x) & 0x00FF) << 8) | \ + (((_x) & 0xFF00) >> 8)): \ + (_x)) + +#define WAVE_UINT32(_x) (endian? ( \ + (((_x) & 0x000000FF) << 24) | \ + (((_x) & 0x0000FF00) << 8) | \ + (((_x) & 0x00FF0000) >> 8) | \ + (((_x) & 0xFF000000) >> 24)): \ + (_x)) + + do { + if ((fp = fopen(this->soundFile_.toLocal8Bit(), "r")) == NULL) { + continue; + } + + if (fread(&wfh, sizeof(FQWFH), 1, fp) != 1) { + continue; + } + + switch (wfh.rid) { + case 0x52494646: + endian = 1; /* Big-Endian */ + break; + case 0x46464952: + endian = 0; /* Small-Endian */ + break; + default: + continue; + } + + if (WAVE_UINT32(wfh.wid) != 0x45564157) { /* "WAVE" */ + continue; + } + + if (fread(&wmh, sizeof(FQWMH), 1, fp) != 1) { + continue; + } + + if (WAVE_UINT32(wmh.fid) != 0x20746d66) { /* "FMT " */ + continue; + } + + if (WAVE_UINT32(wmh.fsz) != 16 || WAVE_UINT16(wmh.aid) != 1) { /* PCM */ + continue; + } + + if (fread(&wdh, sizeof(FQWDH), 1, fp) != 1) { + continue; + } + + if (WAVE_UINT32(wdh.did) != 0x61746164) { /* "DATA" */ + continue; + } + + if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) { + continue; + } + + snd_pcm_hw_params_alloca(&hwparams); + snd_pcm_sw_params_alloca(&swparams); + + if (snd_pcm_hw_params_any(handle, hwparams) < 0) { + continue; + } + + if (snd_pcm_hw_params_set_access(handle, hwparams, + SND_PCM_ACCESS_RW_INTERLEAVED) < 0) { + continue; + } + + switch(WAVE_UINT16(wmh.abps)) { + case 8: + format = SND_PCM_FORMAT_U8; + break; + case 16: + format = SND_PCM_FORMAT_S16_LE; + break; + case 24: + switch (WAVE_UINT16(wmh.aba) / WAVE_UINT16(wmh.ach)) { + case 3: + format = SND_PCM_FORMAT_S24_3LE; + break; + case 4: + format = SND_PCM_FORMAT_S24_LE; + break; + default: + continue; + } + + break; + case 32: + format = SND_PCM_FORMAT_S32_LE; + break; + default: + continue; + } + + if (snd_pcm_hw_params_set_format(handle, hwparams, format) < 0) { + continue; + } + + if (snd_pcm_hw_params_set_channels(handle, hwparams, + WAVE_UINT16(wmh.ach)) < 0) { + continue; + } + + val = WAVE_UINT32(wmh.asr); + + if (snd_pcm_hw_params_set_rate_near(handle, hwparams, &val, NULL) < 0) { + continue; + } + + if (snd_pcm_hw_params(handle, hwparams) < 0) { + continue; + } + + snd_pcm_hw_params_get_period_size(hwparams, &csz, NULL); + snd_pcm_hw_params_get_buffer_size(hwparams, &vsz); + + if (csz == vsz) { + continue; + } + + snd_pcm_sw_params_current(handle, swparams); + + if (snd_pcm_sw_params_set_avail_min(handle, swparams, csz) < 0) { + continue; + } + + if (snd_pcm_sw_params_set_start_threshold(handle, swparams, vsz) < 0) { + continue; + } + + if (snd_pcm_sw_params_set_stop_threshold(handle, swparams, vsz) < 0) { + continue; + } + + if (snd_pcm_sw_params(handle, swparams) < 0) { + continue; + } + + sz = csz * snd_pcm_format_physical_width(format) + * WAVE_UINT16(wmh.ach) / 8; + + if ((data = malloc(sz)) == NULL) { + continue; + } + + len = WAVE_UINT32(wdh.dsz); + + while (len > 0) { + count = (len < sz)? len: sz; + + ret = fread(data, 1, count, fp); + + len -= ret; + + if (ret != count) { + continue; + } + + count = ret * csz / sz; + + ret = snd_pcm_writei(handle, data, count); + + if (ret == -EAGAIN || (ret >= 0 && ret < count)) { + snd_pcm_wait(handle, 200); + } + } + + free(data); + + snd_pcm_drain(handle); + snd_pcm_close(handle); + + fclose(fp); + } + while (0); + +#undef WAVE_UINT16 +#undef WAVE_UINT32 +#endif /* AUDIO_ALSA */ +} + +} // namespace FQTerm + +#include "fqterm_sound.moc" diff --git a/src/common/fqterm_sound.h b/src/common/fqterm_sound.h new file mode 100644 index 0000000..ab18645 --- /dev/null +++ b/src/common/fqterm_sound.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_SOUND_H +#define FQTERM_SOUND_H + +#include <QObject> +#include <QString> +#include <QThread> + +#include "fqterm.h" + +namespace FQTerm { +// By using QThread, we avoid blocking the main app. +// FIXME: However, whichever play method we use (ext|int), +// there are some WAVE files we can't play... + +class FQTermSound: public QThread { + Q_OBJECT; + + public: + FQTermSound(const QString &filename, QObject *parent = 0, + const char *name = 0); + + ~FQTermSound(); + + public slots: + void deleteInstance(); + + protected: + QString soundFile_; + virtual void play() = 0; + void run(); +}; + +class FQTermSystemSound: public FQTermSound { + public: + FQTermSystemSound(const QString &filename, QObject *parent = 0, + const char *name = 0) + : FQTermSound(filename, parent, name) { + } + + protected: + void play(); +}; + +class FQTermExternalSound: public FQTermSound { + public: + FQTermExternalSound(const QString &playername, const QString &filename, + QObject *parent = 0, const char *name = 0) + : FQTermSound(filename, parent, name), playerName_(playername) { + } + + protected: + QString playerName_; + void play(); + void setPlayer(const QString &playername); +}; + +} // namespace FQTerm + +#endif // FQTERM_SOUND_H diff --git a/src/common/fqterm_trace.cpp b/src/common/fqterm_trace.cpp new file mode 100644 index 0000000..867b7ad --- /dev/null +++ b/src/common/fqterm_trace.cpp @@ -0,0 +1,328 @@ +/*************************************************************************** + * 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 <string> + +#ifdef WIN32 +#include <hash_set> +#else +#include <set> +#endif + +#include "fqterm_trace.h" + +namespace FQTerm { + +int *getDefaultMaxTraceLevel() { + static int max_trace_level = 10; + return &max_trace_level; +} + +int getMaxTraceLevel() { + return *getDefaultMaxTraceLevel(); +} + +void setMaxTraceLevel(int max_trace_level) { + *getDefaultMaxTraceLevel() = max_trace_level; + FQ_TRACE("info", 0) << "The upper bound of maximum trace level is " + << FQTERM_MAX_TRACE_LEVEL; + FQ_TRACE("info", 0) << "The maximum trace level is set to " + << max_trace_level; +} + +#ifdef WIN32 +typedef stdext::hash_set<std::string> CategorySet; +#else +typedef std::set<std::string> CategorySet; +#endif + +CategorySet *getAllowedCategories() { + static CategorySet *allowed_categories + = new CategorySet; + return allowed_categories; +} + +int isAllowedCategory(const char *category, int trace_level) { + if (trace_level <= 0) return true; + + const CategorySet &categories = *getAllowedCategories(); + if (categories.empty() + || categories.find(category) != categories.end()) { + return true; + } + return false; +} + +void addAllowedCategory(const char *category) { + CategorySet &categories = *getAllowedCategories(); + + categories.insert(category); + + FQ_TRACE("info", 0) << "Allow category: " << category; +} + +// Event name from event type id (updated to Qt4.3.0). +static const char *kEventName[] = { + "QEvent::None", // 0 + "QEvent::Timer", // 1 + "QEvent::MouseButtonPress", // 2 + "QEvent::MouseButtonRelease", // 3 + "QEvent::MouseButtonDblClick", // 4 + "QEvent::MouseMove", // 5 + "QEvent::KeyPress", // 6 + "QEvent::KeyRelease", // 7 + "QEvent::FocusIn", // 8 + "QEvent::FocusOut", // 9 + "QEvent::Enter", // 10 + "QEvent::Leave", // 11 + "QEvent::Paint", // 12 + "QEvent::Move", // 13 + "QEvent::Resize", // 14 + "None", // 15 + "None", // 16 + "QEvent::Show", // 17 + "QEvent::Hide", // 18 + "QEvent::Close", // 19 + "None", // 20 + "QEvent::ParentChange", // 21 + "None", // 22 + "None", // 23 + "QEvent::WindowActivate", // 24 + "QEvent::WindowDeactivate", // 25 + "QEvent::ShowToParent", // 26 + "QEvent::HideToParent", // 27 + "None", // 28 + "None", // 29 + "None", // 30 + "QEvent::Wheel", // 31 + "None", // 32 + "QEvent::WindowTitleChange", // 33 + "QEvent::WindowIconChange", // 34 + "QEvent::ApplicationWindowIconChange", // 35 + "QEvent::ApplicationFontChange", // 36 + "QEvent::ApplicationLayoutDirectionChange", // 37 + "QEvent::ApplicationPaletteChange", // 38 + "QEvent::PaletteChange", // 39 + "QEvent::Clipboard", // 40 + "None", // 41 + "None", // 42 + "QEvent::MetaCall", // 43 + "None", // 44 + "None", // 45 + "None", // 46 + "None", // 47 + "None", // 48 + "None", // 49 + "QEvent::SockAct", // 50 + "QEvent::ShortcutOverride", // 51 + "QEvent::DeferredDelete", // 52 + "None", // 53 + "None", // 54 + "None", // 55 + "None", // 56 + "None", // 57 + "None", // 58 + "None", // 59 + "QEvent::DragEnter", // 60 + "QEvent::DragMove", // 61 + "QEvent::DragLeave", // 62 + "QEvent::Drop", // 63 + "None", // 64 + "None", // 65 + "None", // 66 + "None", // 67 + "QEvent::ChildAdded", // 68 + "QEvent::ChildPolished", // 69 + "None", // 70 + "QEvent::ChildRemoved", // 71 + "None", // 72 + "None", // 73 + "QEvent::PolishRequest", // 74 + "QEvent::Polish", // 75 + "QEvent::LayoutRequest", // 76 + "QEvent::UpdateRequest", // 77 + "QEvent::UpdateLater", // 78 + "None", // 79 + "None", // 80 + "None", // 81 + "QEvent::ContextMenu", // 82 + "QEvent::InputMethod", // 83 + "None", // 84 + "None", // 85 + "QEvent::AccessibilityPrepare", // 86 + "QEvent::TabletMove", // 87 + "QEvent::LocaleChange", // 88 + "QEvent::LanguageChange", // 89 + "QEvent::LayoutDirectionChange", // 90 + "None", // 91 + "QEvent::TabletPress", // 92 + "QEvent::TabletRelease", // 93 + "None", // 94 + "None", // 95 + "QEvent::IconDrag", // 96 + "QEvent::FontChange", // 97 + "QEvent::EnabledChange", // 98 + "QEvent::ActivationChange", // 99 + "QEvent::StyleChange", // 100 + "QEvent::IconTextChange", // 101 + "QEvent::ModifiedChange", // 102 + "QEvent::WindowBlocked", // 103 + "QEvent::WindowUnblocked", // 104 + "QEvent::WindowStateChange", // 105 + "None", // 106 + "None", // 107 + "None", // 108 + "QEvent::MouseTrackingChange", // 109 + "QEvent::ToolTip", // 110 + "QEvent::WhatsThis", // 111 + "QEvent::StatusTip", // 112 + "QEvent::ActionChanged", // 113 + "QEvent::ActionAdded", // 114 + "QEvent::ActionRemoved", // 115 + "QEvent::FileOpen", // 116 + "QEvent::Shortcut", // 117 + "QEvent::WhatsThisClicked", // 118 + "QEvent::AccessibilityHelp", // 119 + "QEvent::ToolBarChange", // 120 + "QEvent::ApplicationActivate", // 121 + "QEvent::ApplicationDeactivate", // 122 + "QEvent::QueryWhatsThis", // 123 + "QEvent::EnterWhatsThisMode", // 124 + "QEvent::LeaveWhatsThisMode", // 125 + "QEvent::ZOrderChange", // 126 + "QEvent::HoverEnter", // 127 + "QEvent::HoverLeave", // 128 + "QEvent::HoverMove", // 129 + "QEvent::AccessibilityDescription", // 130 + "QEvent::ParentAboutToChange", // 131 + "QEvent::WinEventAct", // 132 + "None", // 133 + "None", // 134 + "None", // 135 + "None", // 136 + "None", // 137 + "None", // 138 + "None", // 139 + "None", // 140 + "None", // 141 + "None", // 142 + "None", // 143 + "None", // 144 + "None", // 145 + "None", // 146 + "None", // 147 + "None", // 148 + "None", // 149 + "QEvent::EnterEditFocus", // 150 + "QEvent::LeaveEditFocus", // 151 + "None", // 152 + "QEvent::MenubarUpdated", // 153 + "None", // 154 + "QEvent::GraphicsSceneMouseMove", // 155 + "QEvent::GraphicsSceneMousePress", // 156 + "QEvent::GraphicsSceneMouseRelease", // 157 + "QEvent::GraphicsSceneMouseDoubleClick", // 158 + "QEvent::GraphicsSceneContextMenu", // 159 + "QEvent::GraphicsSceneHoverEnter", // 160 + "QEvent::GraphicsSceneHoverMove", // 161 + "QEvent::GraphicsSceneHoverLeave", // 162 + "QEvent::GraphicsSceneHelp", // 163 + "QEvent::GraphicsSceneDragEnter", // 164 + "QEvent::GraphicsSceneDragMove", // 165 + "QEvent::GraphicsSceneDragLeave", // 166 + "QEvent::GraphicsSceneDrop", // 167 + "QEvent::GraphicsSceneWheel", // 168 + "QEvent::KeyboardLayoutChange", // 169 + "QEvent::DynamicPropertyChange", // 170 + "QEvent::TabletEnterProximity", // 171 + "QEvent::TabletLeaveProximity", // 172 + // "QEvent::User", // 1000 + // "QEvent::MaxUser", // 65535 +}; + +const char *getEventName(unsigned int type) { + if (type > 1000) { + return "User defined event"; + } + + if (type > 172) { + return "None"; + } + + return kEventName[type]; +} + +} // namespace FQTerm + +#ifdef WIN32 +/* + * Number of micro-seconds between the beginning of the Windows epoch + * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970). + * + * This assumes all Win32 compilers have 64-bit support. + */ + +#include <Windows.h> + +#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__) + #define DELTA_EPOCH_IN_USEC 11644473600000000Ui64 +#else + #define DELTA_EPOCH_IN_USEC 11644473600000000ULL +#endif + +static unsigned long long filetime_to_unix_epoch (const FILETIME *ft) +{ + unsigned long long res = (unsigned long long) ft->dwHighDateTime << 32; + + res |= ft->dwLowDateTime; + res /= 10; /* from 100 nano-sec periods to usec */ + res -= DELTA_EPOCH_IN_USEC; /* from Win epoch to Unix epoch */ + return (res); +} + +int gettimeofday (struct timeval *tv, int unused) +{ + FILETIME ft; + unsigned long long tim; + + GetSystemTimeAsFileTime (&ft); + tim = filetime_to_unix_epoch (&ft); + tv->tv_sec = (long) (tim / 1000000L); + tv->tv_usec = (long) (tim % 1000000L); + return (0); +} +#else + +#include <sys/time.h> +#include <time.h> + +#endif + +namespace FQTerm { + +long long getTraceTime() { + struct timeval t; + gettimeofday(&t, 0); + long long sec = t.tv_sec; + long long usec = t.tv_usec; + return sec * 1000 + usec/1000; +} + +} // namespace FQTerm diff --git a/src/common/fqterm_trace.h b/src/common/fqterm_trace.h new file mode 100644 index 0000000..287a8a8 --- /dev/null +++ b/src/common/fqterm_trace.h @@ -0,0 +1,331 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ + +#ifndef FQTERM_TRACE_H +#define FQTERM_TRACE_H + +#include <cassert> +#ifndef WIN32 +#include <unistd.h> +#endif // WIN32 + +#include <QtDebug> +#include <QFileInfo> + +namespace FQTerm { + +// define NO_FQTERM_TRACE to avoid all trace output. +// #define NO_FQTERM_TRACE + +// define NO_FQTERM_TRACE_FILE_LINE_NUM to avoid file line number in trace +// output. + +// define NO_FQTERM_TRACE_FUNCTION_NAME to avoid function name in trace output. +// define integer FQTERM_MAX_TRACE_LEVEL to determine the maximize outputed +// trace level. +//#define NO_FQTERM_TRACE +#if defined(NDEBUG) +#define FQTERM_MAX_TRACE_LEVEL 1 +#endif + +#ifndef FQTERM_MAX_TRACE_LEVEL +#define FQTERM_MAX_TRACE_LEVEL 20 +#endif // FQTERM_MAX_TRACE_LEVEL + +int getMaxTraceLevel(); + +void setMaxTraceLevel(int max_trace_level); + +long long getTraceTime(); + +int isAllowedCategory(const char *category, int trace_level); + +void addAllowedCategory(const char *category); + +static void soft_break() { +#if defined(WIN32) + __asm int 03h; +#else + pause(); +#endif +} + +template<int trace_level> +class FQTermTrace { + public: + FQTermTrace(const char *category, const char *file_name, int line_num, const char *func_name) + : category_(category), + is_dummy_(!isAllowedCategory(category, trace_level)), + trace_output_((trace_level <= FQTERM_MAX_TRACE_LEVEL + && trace_level <= getMaxTraceLevel()) + ? new QDebug(qDebug().nospace()) + : NULL), + dump_string_(false) { + + if (is_dummy_) return; + +#ifdef NO_FQTERM_TRACE_FILE_LINE_NUM +#ifdef NO_FQTERM_TRACE_FUNCTION_NAME + return; +#endif // NO_FQTERM_TRACE_FUNCTION_NAME +#endif // NO_FQTERM_TRACE_FILE_LINE_NUM + + (*this) << "[" << category_ << " " << trace_level << " "; + +#ifndef NO_FQTERM_TRACE_FILE_LINE_NUM + (*this) << QFileInfo(file_name).fileName().toAscii().constData() + << ": " << line_num; +#endif // NO_FQTERM_TRACE_FILE_LINE_NUM + +#ifndef NO_FQTERM_TRACE_FUNCTION_NAME +#ifndef NO_FQTERM_TRACE_FILE_LINE_NUM + (*this) << ", "; +#endif // NO_FQTERM_TRACE_FILE_LINE_NUM + (*this) << func_name; +#endif // NO_FQTERM_TRACE_FUNCTION_NAME + + (*this) << "] "; + } + + ~FQTermTrace() { + if (is_dummy_) return; + + if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) { + delete trace_output_; + + if (trace_level < 0) { + soft_break(); + assert(false); + qFatal("Fatal error occured!\n"); + } + } + } + + template<class T> + FQTermTrace &operator << (const T &t) { + if (is_dummy_) return *this; + + if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) { + *trace_output_ << t; + } + return *this; + } + + FQTermTrace &operator << (const std::string &t) { + return output_raw_string(t); + } + + FQTermTrace &operator << (const char *t) { + return output_raw_string(t); + } + + FQTermTrace &operator << (void (*setter)(FQTermTrace<trace_level> &)) { + (*setter)(*this); + return *this; + } + + private: + FQTermTrace &output_raw_string(const std::string &t) { + if (is_dummy_) return *this; + + if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) { + if (!dump_string_) { + for (std::string::size_type i = 0; i < t.size(); ++i) { + *trace_output_ << t[i]; + } + } else { + for (std::string::size_type i = 0; i < t.size(); ++i) { + unsigned char a = t[i]; + unsigned char b = a / 0x10; + unsigned char c = a % 0x10; + char h = (char) (b < 10 ? '0' + b : 'A' + b - 10); + char l = (char) (c < 10 ? '0' + c : 'A' + c - 10); + + *trace_output_ << h << l << ' '; + } + } + } + return *this; + } + + private: + const char *category_; + bool is_dummy_; + QDebug *trace_output_; + + public: + bool dump_string_; // whether we print string in hex mode. + +}; + +template<int trace_level> +class FQTermDummyTrace { + public: + template<class T> + FQTermDummyTrace &operator << (const T &) { + return *this; + } + + FQTermDummyTrace &operator << (void (*setter)(FQTermTrace<trace_level> &)) { + return *this; + } +}; + +template<int trace_level> +void dumpHexString(FQTermTrace<trace_level> &tracer) { + tracer.dump_string_ = true; +} + +template<int trace_level> +void dumpNormalString(FQTermTrace<trace_level> &tracer) { + tracer.dump_string_ = false; +} + +template<int trace_level> +class FQTermScopeTrace { + public: + FQTermScopeTrace(const char *category, const char *file_name, int line_num, + const char *func_name, const char *scope_name) + : category_(category), + is_dummy_(!isAllowedCategory(category, trace_level)), + file_name_(file_name), + line_num_(line_num), + func_name_(func_name), + scope_name_(scope_name) { + if (is_dummy_) return; + FQTermTrace<trace_level>(category_, file_name_, line_num_, func_name_) + << "Entering " << scope_name_; + } + + ~FQTermScopeTrace() { + if (is_dummy_) return; + FQTermTrace<trace_level>(category_, file_name_, line_num_, func_name_) + << "Leaving " << scope_name_; + } + + private: + const char *category_; + bool is_dummy_; + + const char *file_name_; + const int line_num_; + const char *func_name_; + const char *scope_name_; +}; + +template<int trace_level> +class FQTermTimerTrace { + public: + FQTermTimerTrace(const char *category, const char *file_name, int line_num, + const char *func_name, const char *msg) + : category_(category), + is_dummy_(!isAllowedCategory(category, trace_level)), + file_name_(file_name), + line_num_(line_num), + func_name_(func_name), + msg_(msg), + start_time(is_dummy_? 0: getTraceTime()) { + } + + ~FQTermTimerTrace() { + if (is_dummy_) return; + + long long total_time = getTraceTime() - start_time; + + long long num_sec = total_time / 1000; + long long num_ms = total_time % 1000; + + FQTermTrace<trace_level>(category_, file_name_, line_num_, func_name_) + << msg_ << num_sec << "s" << num_ms << "ms"; + } + + private: + const char *category_; + bool is_dummy_; + + const char *file_name_; + const int line_num_; + const char *func_name_; + const char *msg_; + + long long start_time; // in millisecond. +}; + +// Some macros work in both debug & release version. +#define FQ_FATAL(file, line, func) \ + do {FQTerm::soft_break(); qFatal("%s", (QString(file) + ": %1 " + QString(func)).arg(line).toUtf8().constData());} while(false) + +#define FQ_VERIFY(expr) do { \ + if(!(expr)) { \ + FQ_FATAL(__FILE__, __LINE__, __FUNCTION__); \ + } \ + } while(false) + + + +#ifdef NO_FQTERM_TRACE + +#define FQ_TRACE(category, trace_level) FQTermDummyTrace<trace_level>() +#define FQ_SCOPE_TRACE(category, trace_level, scope_name) do {} while (false) +#define FQ_FUNC_TRACE(category, trace_level) do {} while(false) + +#define FQ_ASSERT(expr) do {} while(false) + +#define FQ_SCOPE_TIMER(category, trace_level, msg) do {} while(false) +#define FQ_FUNC_TIMER(category, trace_level) do {} while(false) + + +#else // NO_FQTERM_TRACE + +#define FQ_TRACE(category, trace_level) \ + FQTermTrace<trace_level>(category, __FILE__, __LINE__, __FUNCTION__) + +#define FQ_SCOPE_TRACE_PRIVATE(file, line, func, category, trace_level, scope_name) \ + FQTermScopeTrace<trace_level> file##line##func(category, file, line, func, scope_name); + +#define FQ_SCOPE_TRACE(category, trace_level, scope_name) \ + FQ_SCOPE_TRACE_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, scope_name) + +#define FQ_FUNC_TRACE(category, trace_level) \ + FQ_SCOPE_TRACE_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, "function") + + +#define FQ_ASSERT(expr) \ + do {if(!(expr)) {FQ_TRACE("assert", -1) << "assertion failed." << #expr;}} while(false) + + +#define FQ_SCOPE_TIMER_PRIVATE(file, line, func, category, trace_level, msg) \ + FQTermTimerTrace<trace_level> file##line##func(category, file, line, func, msg); + +#define FQ_SCOPE_TIMER(category, trace_level, msg) \ + FQ_SCOPE_TIMER_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, msg) + +#define FQ_FUNC_TIMER(category, trace_level) \ + FQ_SCOPE_TIMER_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, "The function runs for ") + + +#endif // NO_FQTERM_TRACE + + +const char *getEventName(unsigned int type); + +} // namespace FQTerm + +#endif // FQTERM_TRACE_H |