附qterm-0.4.0源代码和补丁:
源代码:
http://www.newsmth.net/att.php?p.69.206347.6850.bz2
补丁:
http://www.newsmth.net/att.php?s.69.206347.2253.patch
使用方法:
下载qterm-0.4.0源代码。解压。下载补丁qterm-0.4.0-copy_colorful_article.patch,放在源代码同一个目录下。
tar jxvf qterm-
0.4
.
0
.
tar
.
bz2
cd
qterm-
0.4
.
0
/
patch
-p1
<
../
qterm-
0.4
.
0
-copy_colorful_article
.
patch
./
configure
make
make install
增加的功能:
1.选择主菜单中的Edit->Copy with color,然后点击右键菜单中的copy article或者点击工具栏中的copy article按钮(右起第7个),会彩色存盘。
2.修正了qterm提供的python模块"qterm"中的getAttrText方法的一个bug,原来这个方法返回的彩色字符中的控制字符少了一个"[",现在正常了。
3.在qterm提供的python模块"qterm"中的copyArticle方法中增加了一个bool类型的参数colorful可以指定是否要彩色存盘。如果为True则彩色存盘,否则则为普通存盘。该接口是向下兼容的,如果没有指定colorful的值,默认就是False.测试代码如下:
import
qterm
import
sys, time

f
=
open(
"
/home/study/prog/python/qterm/test.txt
"
,
"
w
"
)
lp
=
long(sys.argv[0])
f.write(qterm.copyArticle(lp, True))
f.close()
保存为.py文件,然后在qterm主菜单中选择script->run,当前文章就会被彩色保
存到test.txt。
原理:
QTermTextLine类中有两个方法getText()和getAttrText()分别用来获得普通文本和彩色文本。QTermWindow类中有个属性叫m_bCopyColor,可以根据它的值来决定是普通复制还是彩色复制,即调用getText()还是getAttrText()。
class QTermTextLine类中的getAttrText声明中,默认控制字符是"/x1b/x1b"而不是"/x1b/x1b/x5b",即少了一个"[".
QCString getAttrText( int index = -1, int len = -1, const QCString& escape="/x1b/x1b" );
如果直接调用默认参数的getAttrText()就会少一个"["
由于不同的BBS的控制字符可能不同,所以最保险的办法就是从配置文件里读控制字符。
此外,我把原代码的改动尽量地减少到最低限度。代码中原来的函数接口都不变(qterm提供的python接口是个例外,但是也是与原来的接口兼容的。)只在代码中根据pWin->m_bCopyColor的值来决定是调用getText还是getAttrText。
若有其它bug,欢迎广大网友fix它们或者和我联系。
过程如下:
一开始我想写一个python脚本来实现彩色存盘的功能。好不容易在qterm的源代码中找到qterm模块的文档和测试程序,发现qterm只提供了copyArticle功能。虽然有getAttrText方法,但实现起来会比较麻烦。当时不知道有embeding python这回事,于是满世界找qterm.py,希望能找到copyArticle的python代码,加以参考。结果没找到。后来在诸位大牛们的指点下,发现qterm提供的python模块是embeding的。
实现的代码在qtermpython.cpp中。
//
copy current artcle for back compatible use only
//
for new coder please use getArticle
static
PyObject
*
qterm_copyArticle(PyObject
*
, PyObject
*
args)
{
long lp;
if (!PyArg_ParseTuple(args, "l", &lp))
return NULL;

QTermWindow *pWin=(QTermWindow*)lp;

QStringList strList;
QCString cstrArticle;
while(1)
{
// check it there is duplicated string
// it starts from the end in the range of one screen height
// so this is a non-greedy match QString strTemp = pWin->stripWhitespace(
pWin->m_pBuffer->screen(0)->getText());
int i=0;
int start=0;
for(QStringList::Iterator it=strList.fromLast();
it!=strList.begin(), i < pWin->m_pBuffer->line()-1; // not exce eeding the last screen
--it, i++)
{
if(*it!=strTemp)
continue;
QStringList::Iterator it2 = it;
bool dup=true;
// match more to see if its duplicated
for(int j=0; j<=i; j++, it2++)
{
QString str1 = pWin->stripWhitespace(
pWin->m_pBuffer->screen(j)->getText());
if(*it2!=str1)
{
dup = false;
break;
}
}
if(dup)
{
// set the start point
start = i+1;
break;
}
}
// add new lines
for(i=start;i<pWin->m_pBuffer->line()-1;i++)
strList+=pWin->stripWhitespace(
pWin->m_pBuffer->screen(i)->getText());

// the end of article
if( pWin->m_pBuffer->screen(
pWin->m_pBuffer->line()-1)->getText().find("%") == -1 )
break;
// continue
pWin->m_pTelnet->write(" ", 1);

if(!pWin->m_wcWaiting.wait(10000)) // timeout
break;
}
#if defined(_OS_WIN32_) || defined(Q_OS_WIN32)
cstrArticle = strList.join(" ");
#else
cstrArticle = strList.join(" ");
#endif

PyObject *py_text = PyString_FromString(cstrArticle);

Py_INCREF(py_text);
return py_text;
}
对比qterm_getText和qterm_getAttrText发现关键在于调用的是pWin->m_pBuffer->screen(i)对象的getText还是getAttrText,前者没有色彩而后者有。而且也没有必要把所有的getText都改成getAttrText。参考一下注释,只有一处地方真正下载,那就是add new line处。改了一下,测试效果良好。
于是进一步考虑添加菜单功能。毕竟用脚本不方便。
从Copy Article入手,这个功能的菜单项就是Copy Article,grep一下"Copy Article",发现在qtermframe.cpp和qtermwindow.cpp中都有这个命令项的设置,看到了QT中熟悉的SLOT宏。于是找到与它相关联的函数是QTermWindow::copyArticle()和
QTermFrame::copyArticle()。QTermFrame::copyArticle()是调用QTermWindow::copyArticle()的。而QTermWindow::copyArticle()的代码如下:
void
QTermWindow::copyArticle( )
{
if(!m_bConnected)
return;

m_pDAThread = new QTermDAThread(this);
m_pDAThread->start();

}
可见是新开一个线程去下载文章。
于是寻找QTermDAThread类的代码。
QTermDAThread类有个方法叫run(),这令人联想起Java的线程类。所以关键在这个
函数:
void
QTermDAThread::run()
{
QStringList strList;
while(1)
{
// check it there is duplicated string
// it starts from the end in the range of one screen height
// so this is a non-greedy match
QString strTemp = pWin->stripWhitespace(pWin->m_pBuffer
->screen(0)->getText());
int i=0;
int start=0;
for(QStringList::Iterator it=strList.fromLast();
it!=strList.begin(), i < pWin->m_pBuffer->line(
)-1; // not exceeeding the last screen
--it, i++)
{
if(*it!=strTemp)
continue;
QStringList::Iterator it2 = it;
bool dup=true;
// match more to see if its duplicated
for(int j=0; j<=i; j++, it2++)
{
QString str1 = pWin->stripWhitespace(
pWin->m
_pBuffer->screen(j)->getText());
if(*it2!=str1)
{
dup = false;
break;
}
}
if(dup)
{
// set the start point
start = i+1;
break;
}
}
// add new lines
for(i=start;i<pWin->m_pBuffer->line()-1;i++)
strList+=pWin->stripWhitespace(
pWin->m_pBuffer->screen(i)->getText());


// the end of article
if( pWin->m_pBuffer->screen(
pWin->m_pBuffer->line()-1)->getText().find("%") == -1 )
break;
// continue
pWin->m_pTelnet->write(" ", 1);

if(!pWin->m_wcWaiting.wait(10000)) // timeout
{
postEvent(pWin, new QCustomEvent(DAE_TIMEOUT));
break;
}
}
#if defined(_OS_WIN32_) || defined(Q_OS_WIN32)
cstrArticle = strList.join(" ");
#else
cstrArticle = strList.join(" ");
#endif
postEvent(pWin, new QCustomEvent(DAE_FINISH));
}
这个函数与python 接口的copyArticle如出一辙。于是只要作类似的修改就行。
为了让QTermDAThread类既能下载普通文件,又能下载彩色文件。我在QTermDAThr
ead类中的run方法中,在add new lines时根据pWin->m_bCopyColor的值来决
定是调用getText还是getAttrText。
这就是整个修改过程,不需要了解Qterm的架构,不需要了解telnet协议的细节,
只要抓住重点,依样画葫芦就OK了。这也得意于Qterm良好的架构和清晰的源代码风
格。
改动的代码量其实不大,就二十多行代码:
diff
-
uNr qterm
-
0.4
.
0
/
qterm
/
docs
/
script qterm
-
0.4
.
0
-
copy_colorful_article
/
qterm
/
docs
/
script
---
qterm
-
0.4
.
0
/
qterm
/
docs
/
script
2006
-
07
-
10
15
:
36
:
10.000000000
+
0800
+++
qterm
-
0.4
.
0
-
copy_colorful_article
/
qterm
/
docs
/
script
2008
-
01
-
07
19
:
57
:
57.000000000
+
0800
@@
-
9
,
8
+
9
,
8
@@
download the current article
in
given timeout seconds,
return
success
=
0
when timeout, otherwise
1
-
string
copyArticle(
long
lp) (obsolete)
-
download the current article
+
string
copyArticle(
long
lp,
bool
colorful
=
false
) (obsolete)
+
download the current article, you can use it without setting colorful, and by
default
it
is
false
(
in
order to back compatible ),
if
colorful
is
true
,the article
is
colorful.
else
,the article
is
not colorful
string
getText(
long
lp,
int
line)
get
text at line
diff
-
uNr qterm
-
0.4
.
0
/
qterm
/
qtermpython.cpp qterm
-
0.4
.
0
-
copy_colorful_article
/
qterm
/
qtermpython.cpp
---
qterm
-
0.4
.
0
/
qterm
/
qtermpython.cpp
2006
-
07
-
10
15
:
36
:
13.000000000
+
0800
+++
qterm
-
0.4
.
0
-
copy_colorful_article
/
qterm
/
qtermpython.cpp
2008
-
01
-
07
19
:
56
:
50.000000000
+
0800
@@
-
86
,
13
+
86
,
16
@@
//
copy current artcle for back compatible use only
//
for new coder please use getArticle
+
//
you can use it without setting colorful, and by default it is false(in order to back compatible ),if colorful is true ,the article is colorful.else ,the article is not colorful
static
PyObject
*
qterm_copyArticle(PyObject
*
, PyObject
*
args)
{
long lp;
- if (!PyArg_ParseTuple(args, "l", &lp))
+ bool colorful = false;
+ if (!PyArg_ParseTuple(args, "l|b", &lp, &colorful))
return NULL;
QTermWindow *pWin=(QTermWindow*)lp;
+ QCString escape = pWin->getParsedEscape();
QStringList strList;
QCString cstrArticle;
@@ -133,8 +136,12 @@
}
//
add new lines
for
(i
=
start;i
<
pWin
->
m_pBuffer
->
line()
-
1
;i
++
)
-
strList
+=
pWin
->
stripWhitespace(
-
pWin
->
m_pBuffer
->
screen(i)
->
getText());
+
if
(
!
colorful)
+
strList
+=
pWin
->
stripWhitespace(
+
pWin
->
m_pBuffer
->
screen(i)
->
getText());
+
else
+
strList
+=
pWin
->
stripWhitespace(
+
pWin
->
m_pBuffer
->
screen(i)
->
getAttrText(
-
1
,
-
1
, escape));
//
the end of article
if
( pWin
->
m_pBuffer
->
screen(
@@
-
388
,
7
+
395
,
7
@@
if
(
!
PyArg_ParseTuple(args,
"
li
"
,
&
lp,
&
line))
return
NULL;
-
QCString cstr
=
((QTermWindow
*
)lp)
->
m_pBuffer
->
screen(line)
->
getAttrText();
+
QCString cstr
=
((QTermWindow
*
)lp)
->
m_pBuffer
->
screen(line)
->
getAttrText(
-
1
,
-
1
, ((QTermWindow
*
)lp)
->
getParsedEscape());
PyObject
*
py_text
=
PyString_FromString(cstr);
diff
-
uNr qterm
-
0.4
.
0
/
qterm
/
qtermwindow.cpp qterm
-
0.4
.
0
-
copy_colorful_article
/
qterm
/
qtermwindow.cpp
---
qterm
-
0.4
.
0
/
qterm
/
qtermwindow.cpp
2006
-
07
-
10
15
:
36
:
13.000000000
+
0800
+++
qterm
-
0.4
.
0
-
copy_colorful_article
/
qterm
/
qtermwindow.cpp
2008
-
01
-
07
19
:
56
:
38.000000000
+
0800
@@
-
91
,
6
+
91
,
7
@@
void
QTermDAThread::run()
{
QStringList strList;
+ QCString escape = pWin->getParsedEscape();
while(1)
{
// check it there is duplicated string
@@ -127,8 +128,12 @@
}
// add new lines
for(i=start;i<pWin->m_pBuffer->line()-1;i++)
- strList+=pWin->stripWhitespace(
- pWin->m_pBuffer->screen(i)->getText());
+ if(!pWin->m_bCopyColor)
+ strList+=pWin->stripWhitespace(
+ pWin->m_pBuffer->screen(i)->getText());
+ else
+ strList+=pWin->stripWhitespace(
+ pWin->m_pBuffer->screen(i)->getAttrText(-1, -1, escape));
// the end of article
if( pWin->m_pBuffer->screen(
@@ -2217,4 +2222,8 @@
{
pHttp->deleteLater();
}
+QCString QTermWindow::getParsedEscape()
+{
+ return parseString((const char *)m_param.m_strEscape);
+}
#include <qtermwindow.moc>
diff -uNr qterm-0.4.0/qterm/qtermwindow.h qterm-0.4.0-copy_colorful_article/qterm/qtermwindow.h
--- qterm-0.4.0/qterm/qtermwindow.h 2006-07-10 15:36:12.000000000 +0800
+++ qterm-0.4.0-copy_colorful_article/qterm/qtermwindow.h 2008-01-07 19:56:34.000000000 +0800
@@ -85,6 +85,7 @@
void externInput(const QCString&);
QCString stripWhitespace(const QCString& cstr);
void getHttpHelper(const QString&, bool);
+ QCString getParsedEscape();
protected slots:
// from QTermTelnet
diff -uNr qterm-0.4.0/qterm/script/copyColorfulArticle.py qterm-0.4.0-copy_colorful_article/qterm/script/copyColorfulArticle.py
--- qterm-0.4.0/qterm/script/copyColorfulArticle.py 1970-01-01 08:00:00.000000000 +0800
+++ qterm-0.4.0-copy_colorful_article/qterm/script/copyColorfulArticle.py 2008-01-07 19:58:44.000000000 +0800
@@ -0,0 +1,7 @@
+import qterm
+import sys, time
+
+f=open("/home/study/prog/python/qterm/test.txt","w")
+lp=long(sys.argv[0])
+f.write(qterm.copyArticle(lp, True))
+f.close()
最后,感谢adoal,BSD,macaulish,pluskid等网友的指点!
源代码:
http://www.newsmth.net/att.php?p.69.206347.6850.bz2
补丁:
http://www.newsmth.net/att.php?s.69.206347.2253.patch
使用方法:
下载qterm-0.4.0源代码。解压。下载补丁qterm-0.4.0-copy_colorful_article.patch,放在源代码同一个目录下。






增加的功能:
1.选择主菜单中的Edit->Copy with color,然后点击右键菜单中的copy article或者点击工具栏中的copy article按钮(右起第7个),会彩色存盘。
2.修正了qterm提供的python模块"qterm"中的getAttrText方法的一个bug,原来这个方法返回的彩色字符中的控制字符少了一个"[",现在正常了。
3.在qterm提供的python模块"qterm"中的copyArticle方法中增加了一个bool类型的参数colorful可以指定是否要彩色存盘。如果为True则彩色存盘,否则则为普通存盘。该接口是向下兼容的,如果没有指定colorful的值,默认就是False.测试代码如下:







保存为.py文件,然后在qterm主菜单中选择script->run,当前文章就会被彩色保
存到test.txt。
原理:
QTermTextLine类中有两个方法getText()和getAttrText()分别用来获得普通文本和彩色文本。QTermWindow类中有个属性叫m_bCopyColor,可以根据它的值来决定是普通复制还是彩色复制,即调用getText()还是getAttrText()。
class QTermTextLine类中的getAttrText声明中,默认控制字符是"/x1b/x1b"而不是"/x1b/x1b/x5b",即少了一个"[".
QCString getAttrText( int index = -1, int len = -1, const QCString& escape="/x1b/x1b" );
如果直接调用默认参数的getAttrText()就会少一个"["
由于不同的BBS的控制字符可能不同,所以最保险的办法就是从配置文件里读控制字符。
此外,我把原代码的改动尽量地减少到最低限度。代码中原来的函数接口都不变(qterm提供的python接口是个例外,但是也是与原来的接口兼容的。)只在代码中根据pWin->m_bCopyColor的值来决定是调用getText还是getAttrText。
若有其它bug,欢迎广大网友fix它们或者和我联系。
过程如下:
一开始我想写一个python脚本来实现彩色存盘的功能。好不容易在qterm的源代码中找到qterm模块的文档和测试程序,发现qterm只提供了copyArticle功能。虽然有getAttrText方法,但实现起来会比较麻烦。当时不知道有embeding python这回事,于是满世界找qterm.py,希望能找到copyArticle的python代码,加以参考。结果没找到。后来在诸位大牛们的指点下,发现qterm提供的python模块是embeding的。
实现的代码在qtermpython.cpp中。








































































对比qterm_getText和qterm_getAttrText发现关键在于调用的是pWin->m_pBuffer->screen(i)对象的getText还是getAttrText,前者没有色彩而后者有。而且也没有必要把所有的getText都改成getAttrText。参考一下注释,只有一处地方真正下载,那就是add new line处。改了一下,测试效果良好。
于是进一步考虑添加菜单功能。毕竟用脚本不方便。
从Copy Article入手,这个功能的菜单项就是Copy Article,grep一下"Copy Article",发现在qtermframe.cpp和qtermwindow.cpp中都有这个命令项的设置,看到了QT中熟悉的SLOT宏。于是找到与它相关联的函数是QTermWindow::copyArticle()和
QTermFrame::copyArticle()。QTermFrame::copyArticle()是调用QTermWindow::copyArticle()的。而QTermWindow::copyArticle()的代码如下:









可见是新开一个线程去下载文章。
于是寻找QTermDAThread类的代码。
QTermDAThread类有个方法叫run(),这令人联想起Java的线程类。所以关键在这个
函数:


































































这个函数与python 接口的copyArticle如出一辙。于是只要作类似的修改就行。
为了让QTermDAThread类既能下载普通文件,又能下载彩色文件。我在QTermDAThr
ead类中的run方法中,在add new lines时根据pWin->m_bCopyColor的值来决
定是调用getText还是getAttrText。
这就是整个修改过程,不需要了解Qterm的架构,不需要了解telnet协议的细节,
只要抓住重点,依样画葫芦就OK了。这也得意于Qterm良好的架构和清晰的源代码风
格。
改动的代码量其实不大,就二十多行代码:





















































































































最后,感谢adoal,BSD,macaulish,pluskid等网友的指点!