# # Machekku Smart Reply and Forward # # Version: 0.5 # Date: 2005-05-17 # # http://machekku.uaznia.net/jabber/psi/patches/ # # psics.pri | 12 # src/common.cpp | 63 + # src/common.h | 31 # src/eventdlg.cpp | 170 ++++- # src/eventdlg.h | 23 # src/options/opt_messages-ui.ui | 895 ++++++++++++++++++++++++++++ # src/options/opt_messages-ui.ui.h | 18 # src/options/opt_messages.cpp | 540 ++++++++++++++++ # src/options/opt_messages.h | 68 ++ # src/options/options.pri | 3 # src/options/optionsdlg.cpp | 2 # src/psi_profiles.cpp | 152 ++++ # src/psiaccount.cpp | 222 ++++++ # src/psiaccount.h | 10 # src/psicon.cpp | 4 # src/tools/multilineinput/multilineinput.cpp | 162 +++++ # src/tools/multilineinput/multilineinput.h | 36 + # src/tools/multilineinput/multilineinput.pri | 4 # src/tools/templates/templates.cpp | 277 ++++++++ # src/tools/templates/templates.h | 86 ++ # src/tools/templates/templates.pri | 4 # 21 files changed, 2735 insertions(+), 47 deletions(-) # diff -X exclude -Naru psi_cvs-2005.05.17/psi/psics.pri psi/psi/psics.pri --- psi_cvs-2005.05.17/psi/psics.pri Tue Apr 12 17:51:40 2005 +++ psi/psi/psics.pri Tue May 17 20:51:18 2005 @@ -85,6 +85,18 @@ ADVWIDGET_CPP = $$PSICS_CPP/advwidget INCLUDEPATH += $$ADVWIDGET_CPP include($$ADVWIDGET_CPP/advwidget.pri) + + # multiline text input + CONFIG += multilineinput + MULTILINEINPUT_CPP = $$PSICS_CPP/multilineinput + INCLUDEPATH += $$MULTILINEINPUT_CPP + include($$MULTILINEINPUT_CPP/multilineinput.pri) + + # templates utils + CONFIG += templates + TEMPLATES_CPP = $$PSICS_CPP/templates + INCLUDEPATH += $$TEMPLATES_CPP + include($$TEMPLATES_CPP/templates.pri) use_crash { # crash diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/common.cpp psi/psi/src/common.cpp --- psi_cvs-2005.05.17/psi/src/common.cpp Sun May 15 22:26:44 2005 +++ psi/psi/src/common.cpp Tue May 17 20:54:18 2005 @@ -146,11 +146,68 @@ return txt; } -QString qstrquote(const QString &toquote, int width, bool quoteEmpty) +/*! + Quotes \a toquote string, + by dividing it into lines with max witdh \a width, + each line starting with '>' quote character. + + If \a quoteEmpty is false, empty lines are not prepended with '>'. + + If \a stripEmptyLines is true, empty lines from beginning and end + of the quoted text are removed. + + If \a removeSignature is true, all text after signature delimiter ("-- \n") + is removed from output, including the delimiter. +*/ + +QString qstrquote(const QString &toquote, int width, bool quoteEmpty, bool stripEmptyLines /* = FALSE */, bool removeSignature /* = FALSE */) { - int ql = 0, col = 0, atstart = 1, ls=0; + const QString quotedEmpty = ">\n\n\n"; + + int ql = 0, col = 0, atstart = 1, ls=0; + + QString quoted = toquote; + + if ( removeSignature ) { + int sig = -1; + if ( (sig = quoted.find("\n-- \n")) != -1 ) + quoted.truncate(sig+1); // +1 -> don't trunc '\n' + else if (toquote.startsWith("-- \n")) // message was just a signature + return quotedEmpty; // two empty lines at the end... + } + + if ( stripEmptyLines ) { + int len = quoted.length(); + + // check for empty lines at the beginning + int last = 0; + while ( last < len && quoted[last] == '\n' ) + ++last; + + if ( last == len ) { + // message contained only empty lines + return quotedEmpty; + } + + // now, quoted[last] is the first not '\n' character + if ( last > 0 ) { + quoted.remove(0, last); // last = length of removed part + len -= last; + } + + // check for empty lines at the end + int first = len - 1; + while ( first > 0 && quoted[first] == '\n') + --first; + + // now, quoted[first] is the last not-'\n' character + if ( first < len - 1) { + quoted.truncate(first + 1); + } + } + + quoted = "> " + quoted; // quote first line - QString quoted = "> "+toquote; // quote first line QString rxs = quoteEmpty ? "\n" : "\n(?!\\s*\n)"; QRegExp rx(rxs); // quote following lines quoted.replace(rx, "\n> "); diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/common.h psi/psi/src/common.h --- psi_cvs-2005.05.17/psi/src/common.h Wed May 4 18:18:20 2005 +++ psi/psi/src/common.h Tue May 17 20:54:18 2005 @@ -35,6 +35,7 @@ //#include"xmpp_types.h" #include"varlist.h" #include"psiiconset.h" +#include"templates.h" #define PROXY_NONE 0 #define PROXY_HTTPS 1 @@ -200,6 +201,33 @@ int dtPort; QString dtExternal; + // machekku: smart forward and reply + + Template quoteHeaderQuote; + Template quoteHeaderReply; + Template quoteHeaderForward; + + bool useQuoteHeaderQuote; + bool useQuoteHeaderReply; + bool useQuoteHeaderForward; + + Template messageSignature; + bool useMessageSignature; + bool autoMessageSignatureDelimiter; + + bool hideQuoteBtn; + bool defaultReplyWithoutQuoting; + bool hideChatBtn; + bool replyInAuthReq; + + bool cursorAtTopInEventDlg; + int wrapAtColumn; + bool quoteEmptyLines; + bool stripEmptyLines; + bool removeSignature; + + QValueVector fortunes; + // Last used path remembering QString lastPath; QString lastSavePath; @@ -228,7 +256,7 @@ QString status2txt(int status); QString eatptag(QString txt); -QString qstrquote(const QString &, int width=60, bool quoteEmpty=FALSE); +QString qstrquote(const QString &, int width=60, bool quoteEmpty=FALSE, bool stripEmptyLines=FALSE, bool removeSignature=FALSE); QString plain2rich(const QString &); QString rich2plain(const QString &); QString clipStatus(const QString &str, int width, int height); @@ -323,5 +351,6 @@ typedef QValueList JidList; typedef QValueListIterator JidListIt; +enum ComposeType { ctNew, ctReply, ctQuote, ctForward }; #endif diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/eventdlg.cpp psi/psi/src/eventdlg.cpp --- psi_cvs-2005.05.17/psi/src/eventdlg.cpp Sun May 15 22:26:44 2005 +++ psi/psi/src/eventdlg.cpp Tue May 17 21:36:30 2005 @@ -49,6 +49,17 @@ #include"iconselect.h" #include"iconwidget.h" +/*! + \enum ComposeType + + This enum represents different types of Compose action: + + \value ctNew - a new message + \value ctReply - a reply to a message (without quoting) + \value ctQuote - a reply to a message (with quoting) + \value ctForward - a forwarding of a message +*/ + static QString findJid(const QString &s, int x, int *p1, int *p2) { // scan backward for the beginning of a Jid @@ -90,6 +101,29 @@ } //---------------------------------------------------------------------------- +// HLineEdit - helper class to enable hotkeys while lineedit is focused +//---------------------------------------------------------------------------- + +/*! + \class HLineEdit + + HLineEdit is a specialised QLineEdit which prevents text box + from catching some hotkeys. +*/ + +HLineEdit::HLineEdit(EventDlg *parent, const char *name) + : QLineEdit(parent, name) {} + + +void HLineEdit::keyPressEvent(QKeyEvent *e) +{ + if((e->key() == Key_H || e->key() == Key_I ) && (e->state() & ControlButton)) + e->ignore(); + else + QLineEdit::keyPressEvent(e); +} + +//---------------------------------------------------------------------------- // ELineEdit - a line edit that handles advanced Jid entry //---------------------------------------------------------------------------- // hack hack hack hack @@ -124,7 +158,7 @@ }; ELineEdit::ELineEdit(EventDlg *parent, const char *name) -:QLineEdit(parent, name) +:HLineEdit(parent, name) { setAcceptDrops(TRUE); } @@ -173,7 +207,8 @@ void ELineEdit::keyPressEvent(QKeyEvent *e) { - QLineEdit::keyPressEvent(e); + HLineEdit::keyPressEvent(e); + if(e->ascii() >= 32 && e->ascii() < 127) tryComplete(); } @@ -443,14 +478,14 @@ QLabel *lb_ident, *lb_time; IconLabel *lb_status; ELineEdit *le_to; - QLineEdit *le_from, *le_subj; + HLineEdit *le_from, *le_subj; QLCDNumber *lcd_count; IconToolButton *tb_url, *tb_info, *tb_history, *tb_pgp, *tb_icon; IconLabel *lb_pgp; bool enc; int transid; IconButton *pb_next; - IconButton *pb_close, *pb_quote, *pb_deny, *pb_send, *pb_reply, *pb_chat, *pb_auth; + IconButton *pb_close, *pb_forward, *pb_quote, *pb_deny, *pb_send, *pb_reply, *pb_auth, *pb_chat; ChatView *mle; AttachView *attachView; QTimer *whois; @@ -466,6 +501,10 @@ Message m; QStringList sendLeft; + QDateTime messageTime; + + bool mayShowReplyingBtns; + public slots: void addEmoticon(const Icon *icon) { if ( !dlg->isActiveWindow() ) @@ -503,6 +542,7 @@ { d = new Private(this); d->composing = true; + d->mayShowReplyingBtns = false; d->psi = psi; d->pa = 0; d->psi->dialogRegister(this); @@ -569,6 +609,7 @@ { d = new Private(this); d->composing = false; + d->mayShowReplyingBtns = false; d->psi = pa->psi(); d->pa = pa; d->jid = j; @@ -672,7 +713,7 @@ l = new QLabel(tr("From:"), this); hb2->addWidget(l); hb2->addWidget(d->lb_status); - d->le_from = new QLineEdit(this); + d->le_from = new HLineEdit(this); d->le_from->setReadOnly(true); hb2->addWidget(d->le_from); } @@ -690,7 +731,7 @@ d->tb_icon->setEnabled(false); // message length counter - d->le_subj = new QLineEdit(this); + d->le_subj = new HLineEdit(this); d->lcd_count = new QLCDNumber(this); QToolTip::add(d->lcd_count, tr("Message length")); d->lcd_count->setFixedWidth(50); @@ -785,6 +826,7 @@ connect(d->pb_close, SIGNAL(clicked()), SLOT(close())); d->pb_close->setMinimumWidth(80); hb4->addWidget(d->pb_close); + hb4->addSpacing(16); hb4->addStretch(1); d->pb_next = new IconButton(this); connect(d->pb_next, SIGNAL(clicked()), SLOT(doReadNext())); @@ -793,6 +835,18 @@ d->pb_next->setMinimumWidth(96); d->pb_next->setEnabled(false); hb4->addWidget(d->pb_next); + d->pb_forward = new IconButton(this); + d->pb_forward->setText(tr("&Forward")); + connect(d->pb_forward, SIGNAL(clicked()), SLOT(doForward())); + d->pb_forward->hide(); + d->pb_forward->setMinimumWidth(96); + hb4->addWidget(d->pb_forward); + d->pb_chat = new IconButton(this); + d->pb_chat->setText(tr("&Chat")); + connect(d->pb_chat, SIGNAL(clicked()), SLOT(doChat())); + d->pb_chat->hide(); + d->pb_chat->setMinimumWidth(96); + hb4->addWidget(d->pb_chat); d->pb_quote = new IconButton(this); d->pb_quote->setText(tr("&Quote")); connect(d->pb_quote, SIGNAL(clicked()), SLOT(doQuote())); @@ -818,12 +872,6 @@ d->pb_send->hide(); d->pb_send->setMinimumWidth(96); hb4->addWidget(d->pb_send); - d->pb_chat = new IconButton(this); - d->pb_chat->setText(tr("&Chat")); - connect(d->pb_chat, SIGNAL(clicked()), SLOT(doChat())); - d->pb_chat->hide(); - d->pb_chat->setMinimumWidth(96); - hb4->addWidget(d->pb_chat); d->pb_reply = new IconButton(this); d->pb_reply->setText(tr("&Reply")); connect(d->pb_reply, SIGNAL(clicked()), SLOT(doReply())); @@ -873,10 +921,10 @@ return d->mle->text(); } -void EventDlg::setText(const QString &s) +void EventDlg::setText(const QString &s, bool moveCursorToTop) { d->mle->setText(s); - d->mle->moveCursor(QTextEdit::MoveEnd, false); + d->mle->moveCursor((moveCursorToTop)? QTextEdit::MoveHome : QTextEdit::MoveEnd, false); } void EventDlg::setSubject(const QString &s) @@ -894,6 +942,15 @@ d->urlOnShow = true; } +/*! + Adds attachement with URL \a url and description \a desc to the message. +*/ + +void EventDlg::addAttachement(const QString &url, const QString &desc) // machekku +{ + d->attachView->urlAdd(url, desc); +} + PsiAccount *EventDlg::psiAccount() { return d->pa; @@ -1210,6 +1267,9 @@ setIcon(d->anim->impix()); } #endif + + // update replying buttons + updateReplyingButtons(); } QSize EventDlg::defaultSize() @@ -1243,6 +1303,14 @@ #endif else if(d->composing && e->key() == Key_Return && ((e->state() & ControlButton) || (e->state() & AltButton)) ) doSend(); + else if(!d->composing && e->key() == Key_R && (e->state() & ControlButton)) { + if(option.defaultReplyWithoutQuoting) + doReply(); + else + doQuote(); + } + else if(!d->composing && e->key() == Key_L && (e->state() & ControlButton)) + doForward(); else if(e->key() == Key_H && (e->state() & ControlButton)) doHistory(); else if(e->key() == Key_I && (e->state() & ControlButton)) @@ -1344,7 +1412,7 @@ if(list.isEmpty()) return; Jid j(list[0]); - aReply(j, "", d->le_subj->text(), d->thread); + aCompose(j, "", d->le_subj->text(), d->thread, ctReply, j, d->pa->jid(), d->messageTime, d->attachView->urlList()); } void EventDlg::doQuote() @@ -1360,7 +1428,32 @@ else body = rich2plain(d->mle->text()); - aReply(j, body, d->le_subj->text(), d->thread); + aCompose(j, body, d->le_subj->text(), d->thread, ctQuote, j, d->pa->jid(), d->messageTime, d->attachView->urlList()); +} + +/*! + Forwards the message. + Forwarded message will contain selected part of the text + or all text if there was no selection. + + All attachemenets are forwarded, too. +*/ + +void EventDlg::doForward() +{ + QStringList list = stringToList(d->le_from->text()); + Jid jFrom; + if(!list.isEmpty()) + jFrom = Jid(list[0]); + + QString body; + if(d->mle->hasSelectedText()) + body = rich2plain(d->mle->selectedText()); + else + body = rich2plain(d->mle->text()); + + Jid jTo; + aCompose(jTo, body, d->le_subj->text(), d->thread, ctForward, jFrom, d->pa->jid(), d->messageTime, d->attachView->urlList()); } void EventDlg::doDeny() @@ -1484,6 +1577,31 @@ str = QString("") + str + ""; d->lb_time->setText(str); + + d->messageTime = t; +} + +void EventDlg::updateReplyingButtons() +{ + const bool showChat = !option.hideChatBtn; + const bool showReply = !option.hideQuoteBtn || option.defaultReplyWithoutQuoting; // (two buttons) or (one button which is 'reply') + const bool showQuote = !option.hideQuoteBtn || !option.defaultReplyWithoutQuoting; // (two buttons) or (one button which is 'quote') + + d->pb_quote->setText( ( option.hideQuoteBtn && !option.defaultReplyWithoutQuoting ) ? tr("&Reply") : tr("&Quote") ); + + if ( d->mayShowReplyingBtns ) { + (showChat )? d->pb_chat ->show() : d->pb_chat ->hide(); + (showReply)? d->pb_reply->show() : d->pb_reply->hide(); + (showQuote)? d->pb_quote->show() : d->pb_quote->hide(); + d->pb_forward->show(); + } + else { + d->pb_chat->hide(); + d->pb_forward->hide(); + d->pb_reply->hide(); + d->pb_quote->hide(); + } + } void EventDlg::updateEvent(PsiEvent *e) @@ -1510,9 +1628,7 @@ d->pb_auth->hide(); d->pb_deny->hide(); - d->pb_chat->show(); - d->pb_reply->show(); - d->pb_quote->show(); + d->mayShowReplyingBtns = true; QString txt = plain2rich(m.body()); @@ -1551,9 +1667,7 @@ d->mle->setTextFormat(RichText); d->mle->setText("" + body + ""); - d->pb_chat->show(); - d->pb_reply->hide(); - d->pb_quote->hide(); + d->mayShowReplyingBtns = option.replyInAuthReq; d->pb_auth->setEnabled(true); d->pb_auth->show(); @@ -1567,9 +1681,8 @@ d->pb_auth->hide(); d->pb_deny->hide(); - d->pb_chat->show(); - d->pb_reply->show(); - d->pb_quote->show(); + + d->mayShowReplyingBtns = true; } else if(type == "unsubscribed") { QString body(tr("[System Message]
Your authorization has been removed!")); @@ -1579,11 +1692,12 @@ d->pb_auth->hide(); d->pb_deny->hide(); - d->pb_chat->show(); - d->pb_reply->show(); - d->pb_quote->show(); + + d->mayShowReplyingBtns = true; } } + + updateReplyingButtons(); if(d->lb_pgp) d->lb_pgp->setIcon( IconsetFactory::iconPtr(d->enc ? "psi/cryptoYes" : "psi/cryptoNo") ); diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/eventdlg.h psi/psi/src/eventdlg.h --- psi_cvs-2005.05.17/psi/src/eventdlg.h Sun May 15 22:26:44 2005 +++ psi/psi/src/eventdlg.h Tue May 17 21:35:24 2005 @@ -30,6 +30,7 @@ #include"im.h" #include"userlist.h" #include"ui_addurl.h" +#include"common.h" using namespace XMPP; @@ -41,7 +42,18 @@ class Icon; class EventDlg; -class ELineEdit : public QLineEdit + +// helper class to enable hotkeys while lineedit is focused +class HLineEdit : public QLineEdit +{ + Q_OBJECT +public: + HLineEdit(EventDlg *parent, const char *name=0); +protected: + void keyPressEvent(QKeyEvent *); +}; + +class ELineEdit : public HLineEdit { Q_OBJECT public: @@ -112,18 +124,20 @@ ~EventDlg(); QString text() const; - void setText(const QString &); + void setText(const QString &, bool moveCursorToTop = false); void setSubject(const QString &); void setThread(const QString &); void setUrlOnShow(); + void addAttachement(const QString &url, const QString &desc); + PsiAccount *psiAccount(); static QSize defaultSize(); signals: void aChat(const Jid& jid); - void aReply(const Jid &jid, const QString &body, const QString &subject, const QString &thread); + void aCompose(const Jid &jid, const QString &body, const QString &subject, const QString &thread, ComposeType ct, const Jid &originalJid_Sender, const Jid &originalJid_Me, const QDateTime &originalMessageTime, const UrlList &originalMessageAttachements); void aReadNext(const Jid &); void aDeny(const Jid &); void aAuth(const Jid &); @@ -154,6 +168,7 @@ void doReadNext(); void doChat(); void doReply(); + void doForward(); void doQuote(); void doDeny(); void doAuth(); @@ -165,6 +180,8 @@ void updatePGP(); void encryptedMessageSent(int, bool); void trySendEncryptedNext(); + + void updateReplyingButtons(); public: class Private; diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/opt_messages-ui.ui psi/psi/src/options/opt_messages-ui.ui --- psi_cvs-2005.05.17/psi/src/options/opt_messages-ui.ui Thu Jan 1 01:00:00 1970 +++ psi/psi/src/options/opt_messages-ui.ui Tue May 17 20:54:18 2005 @@ -0,0 +1,895 @@ + +OptMessagesUI + + + OptMessagesUI + + + + 0 + 0 + 300 + 403 + + + + OptMessagesUI + + + + unnamed + + + 0 + + + + tabWidget3 + + + + TabPage + + + Signature + + + + unnamed + + + + ck_signature + + + Add a signature when sending a message + + + + + gb_signature + + + + 5 + 4 + 0 + 0 + + + + &Signature + + + + unnamed + + + + layout18 + + + + unnamed + + + + te_signature + + + + 7 + 7 + 0 + 0 + + + + + 32767 + 90 + + + + NoWrap + + + + + pb_insSignature + + + true + + + Special symbols + + + + + spacer9_4 + + + Horizontal + + + Expanding + + + + 182 + 20 + + + + + + + + ck_signatureAutoDelimiter + + + Automatically add signature &delimiter + + + Alt+D + + + + + + + groupBox10 + + + + 5 + 4 + 0 + 0 + + + + &Fortunes + + + + unnamed + + + 2 + + + + layout29 + + + + unnamed + + + + lb_fortunes + + + + 7 + 7 + 0 + 0 + + + + + 32767 + 62 + + + + + + pb_fortuneNew + + + New + + + + + Spacer6 + + + Vertical + + + Maximum + + + + 16 + 0 + + + + + + pb_fortuneDelete + + + Delete + + + + + + + TextLabel2_2 + + + Content: + + + + + te_fortune + + + + 7 + 7 + 0 + 0 + + + + + 32767 + 62 + + + + + + + + spacer88 + + + Vertical + + + Minimum + + + + 20 + 0 + + + + + + + + TabPage + + + Quote && Reply + + + + unnamed + + + + ck_headerQuote + + + Add a header when quoting a message + + + + + gb_headerQuote + + + + 5 + 4 + 0 + 0 + + + + &Quote header + + + + unnamed + + + + layout8 + + + + unnamed + + + + pb_insQuote + + + Special symbols + + + + + spacer9_2 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + te_headerQuote + + + + 7 + 7 + 0 + 0 + + + + + 32767 + 90 + + + + + + + + + + ck_headerReply + + + Add a header when replying a message + + + + + gb_headerReply + + + + 5 + 4 + 0 + 0 + + + + &Reply header + + + + unnamed + + + + layout9 + + + + unnamed + + + + te_headerReply + + + + 7 + 7 + 0 + 0 + + + + + 32767 + 90 + + + + NoWrap + + + + + pb_insReply + + + Special symbols + + + + + spacer9_3 + + + Horizontal + + + Expanding + + + + 40 + 20 + + + + + + + + + + spacer10 + + + Vertical + + + Minimum + + + + 20 + 0 + + + + + + + + TabPage + + + Forward + + + + unnamed + + + + ck_headerForward + + + Add a header when forwarding a message + + + + + gb_headerForward + + + + 5 + 4 + 0 + 0 + + + + &Forward header + + + + unnamed + + + + layout7 + + + + unnamed + + + + spacer9 + + + Horizontal + + + Expanding + + + + 160 + 20 + + + + + + te_headerForward + + + + 7 + 7 + 0 + 0 + + + + + 0 + 10 + + + + + 32767 + 90 + + + + false + + + + + pb_insForward + + + Special symbols + + + + + + + + + spacer86 + + + Vertical + + + Minimum + + + + 20 + 0 + + + + + + + + TabPage + + + Misc + + + + unnamed + + + + groupBox6 + + + + 5 + 4 + 0 + 0 + + + + &Quoting options + + + + unnamed + + + + ck_quoteEmptyLines + + + &Quote empty lines + + + Alt+Q + + + + + ck_stripEmptyLines + + + &Strip empty lines + + + Alt+S + + + + + ck_removeSignature + + + &Remove signature from quoted text + + + Alt+R + + + + + layout21 + + + + unnamed + + + + textLabel3 + + + &Wrap at column: + + + sb_wrapAtColumn + + + + + sb_wrapAtColumn + + + + + spacer19 + + + Horizontal + + + Expanding + + + + 44 + 20 + + + + + + + + + + groupBox7 + + + + 5 + 4 + 0 + 0 + + + + Q&uote or reply + + + + unnamed + + + + ck_hideQuoteBtn + + + Hide '&Quote' button + + + Alt+Q + + + + + ck_defaultReplyWithoutQuoting + + + &Reply without quoting by default + + + Alt+R + + + + + + + groupBox9 + + + + 5 + 4 + 0 + 0 + + + + &Other + + + + unnamed + + + + ck_hideChatBtn + + + Hide 'Start &Chat' button + + + Alt+C + + + + + ck_showReplyInAuthRequests + + + Show replying buttons for authorization requests + + + + + + + + ck_cursorAtTop + + + &Move cursor to the top of edit field + + + Alt+M + + + + + + + spacer85 + + + Vertical + + + Minimum + + + + 20 + 0 + + + + + + + + + + + FortunesListBox +
opt_messages.h
+ + -1 + -1 + + 0 + + 5 + 5 + 0 + 0 + + image0 +
+
+ + + 789cd3d7528808f055d0d2e72a2e492cc94c5648ce482c52d04a29cdcdad8c8eb5ade65232540043251d2e253d856405650b03100473956aadb9003aff0fa0 + + + + + ck_headerForward + toggled(bool) + gb_headerForward + setEnabled(bool) + + + ck_headerQuote + toggled(bool) + gb_headerQuote + setEnabled(bool) + + + ck_headerReply + toggled(bool) + gb_headerReply + setEnabled(bool) + + + ck_signature + toggled(bool) + gb_signature + setEnabled(bool) + + + + tabWidget3 + ck_headerForward + pb_insForward + te_headerForward + ck_headerQuote + pb_insQuote + te_headerQuote + ck_headerReply + pb_insReply + te_headerReply + ck_signature + pb_insSignature + te_signature + ck_signatureAutoDelimiter + + + opt_messages-ui.ui.h + + + destroy() + + + + fortuneslistbox.h + +
diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/opt_messages-ui.ui.h psi/psi/src/options/opt_messages-ui.ui.h --- psi_cvs-2005.05.17/psi/src/options/opt_messages-ui.ui.h Thu Jan 1 01:00:00 1970 +++ psi/psi/src/options/opt_messages-ui.ui.h Tue May 17 20:54:18 2005 @@ -0,0 +1,18 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +#include + +void OptMessagesUI::destroy() +{ + delete pb_insForward->popup(); + delete pb_insQuote->popup(); + delete pb_insReply->popup(); + delete pb_insSignature->popup(); +} diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/opt_messages.cpp psi/psi/src/options/opt_messages.cpp --- psi_cvs-2005.05.17/psi/src/options/opt_messages.cpp Thu Jan 1 01:00:00 1970 +++ psi/psi/src/options/opt_messages.cpp Tue May 17 20:54:18 2005 @@ -0,0 +1,540 @@ +/* + * opt_messages.cpp - options tab for messages options + * Copyright (C) 2005 Maciej Niedzielski + * + * 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "opt_messages.h" +#include "opt_messages-ui.h" + +#include "common.h" +#include "templates.h" +#include "multilineinput.h" + +#include +#include +#include +#include +#include +#include +#include + +//---------------------------------------------------------------------------- +// ListBoxFortune +//---------------------------------------------------------------------------- + +/*! + \class ListBoxFortune + + ListBoxFortune is a QListBoxText descendent class used to display + multiline fortune text in a single line. + + Use setFortune()/getFortune() methods instead of setText()/getText(). +*/ + +class ListBoxFortune : public QListBoxText +{ +public: + + /*! + Constructs a new fortune list item with \a aFortune fortune. + */ + + ListBoxFortune(const QString &aFortune) + : QListBoxText(singleLine(aFortune)), fortune(aFortune) { + } + + /*! + Changes fortune contained in this list item. + This method will also change item's text (used to draw this item) + with a single-line representation of the fortune, provided by + singleLine() method. + */ + + void setFortune(const QString &f) { + fortune = f; + setText(singleLine(f)); + } + + /*! + Retrieves multi-line fortune stored in this item. + */ + + QString getFortune() { + return fortune; + } + +protected: + + /*! + Prepares fortune \a f to be displayed as a single-line list item + by replacing new line character with "\\" string + and tab character with a space. + */ + + QString singleLine(const QString &f) { + QString sl = f; + sl.replace(QRegExp("\\n"), "\\"); + sl.replace(QRegExp("\\t"), " "); + return sl; + } + +private: + QString fortune; +}; + +//---------------------------------------------------------------------------- +// FortunesListBox +//---------------------------------------------------------------------------- + +/*! + \class FortunesListBox opt_messages.h + \brief A list box class designed to represent fortunes. + + FortunesListBox class is a QListBox derived class, + designed to manage a list of ListBoxFortune items. + + With this class you may display multi-line fortunes + using single-line items (new line characters are replaced by "\". +*/ + +/*! + Constructs a new fortunes list box with parent \a parent, name \a name + and flags \a f. +*/ + +FortunesListBox::FortunesListBox(QWidget* parent, const char* name, WFlags f) +: QListBox(parent, name, f) { +} + +/*! + Inserts \a fortune as a new fortune. +*/ + +void FortunesListBox::insertFortune(const QString &fortune) { + insertItem(new ListBoxFortune(fortune)); +} + +/*! + Changes fortune with is \a id. +*/ + +void FortunesListBox::updateFortune(const QString &fortune, int id) { + ((ListBoxFortune*)item(id))->setFortune(fortune); + updateItem(id); +} + +/*! + Retrieves fortune from item with id \a id. +*/ + +QString FortunesListBox::getFortune(int id) { + return ((ListBoxFortune*)item(id))->getFortune(); +} + +//---------------------------------------------------------------------------- +// QuoteHeaderPopup +//---------------------------------------------------------------------------- + +/*! + \class QuoteHeaderPopup + + QuoteHeaderPopup is a class representing a popup menu with + template items which may be used in quote header template. +*/ + +class QuoteHeaderPopup : public TemplatePopup { + Q_OBJECT +public: + QuoteHeaderPopup(QTextEdit *edt, QWidget *parent = 0, const char *name = 0) + : TemplatePopup(edt, parent, name) + { + insertTemplateItem(tr("Sender's bare jid"), "Sender.jid.bare"); + insertTemplateItem(tr("Sender's full jid"), "Sender.jid.full"); + insertTemplateItem(tr("Sender's nick"), "Sender.nick"); + insertTemplateItem(tr("Sender's nick or jid"), "Sender.nick-jid"); + insertSeparator(); + insertTemplateItem(tr("Your bare jid"), "Me.jid.bare"); + insertTemplateItem(tr("Your full jid"), "Me.jid.full"); + insertTemplateItem(tr("Your nick"), "Me.nick"); + insertTemplateItem(tr("Your nick or jid"), "Me.nick-jid"); + insertSeparator(); + insertTemplateItem(tr("Message date and time"), "Message.DateTime"); + insertTemplateItem(tr("Message subject"), "Message.subject"); + insertSeparator(); + insertTemplateItem(tr("\'<\' character"), ""); + } +}; + +//---------------------------------------------------------------------------- +// SignaturePopup +//---------------------------------------------------------------------------- + +/*! + \class SignaturePopup + + SignaturePopup is a class representing a popup menu with + template items which may be used in signature template. +*/ + +class SignaturePopup : public TemplatePopup { + Q_OBJECT +public: + SignaturePopup(QTextEdit *edt, QWidget *parent = 0, const char *name = 0) + : TemplatePopup(edt, parent, name) + { + insertTemplateItem(tr("Fortune"), "Fortune"); + insertSeparator(); + insertTemplateItem(tr("\'<\' character"), ""); + } +}; + +//---------------------------------------------------------------------------- +// OptionsTabMessages +//---------------------------------------------------------------------------- + +OptionsTabMessages::OptionsTabMessages(QObject *parent) +: OptionsTab(parent, "messages", "", tr("Messages"), tr("Advanced options for quoting and replying messages"), "psi/sendMessage") +{ + w = 0; + o = new Options; +} + +OptionsTabMessages::~OptionsTabMessages() +{ + delete o; +} + +QWidget *OptionsTabMessages::widget() +{ + if ( w ) + return 0; + + w = new OptMessagesUI(); + + OptMessagesUI *d = (OptMessagesUI *)w; + + // signature + QWhatsThis::add(d->ck_signature, + tr("Check this option if you want to include signature in messages that you send.")); + QWhatsThis::add(d->pb_insSignature, + tr("Press this button if you want to add special symbols to your signature.")); + QWhatsThis::add(d->te_signature, + tr("You may edit your signature here.")); + QWhatsThis::add(d->ck_signatureAutoDelimiter, + tr("Check this option if you want Psi to automatically prepend your signature with" + " a signature delimiter ('-- ').")); + + QWhatsThis::add(d->pb_fortuneNew, + tr("Press this button to create a new fortune.")); + QWhatsThis::add(d->pb_fortuneDelete, + tr("Press this button to delete a fortune.")); + QWhatsThis::add(d->lb_fortunes, + tr("Use this list to select a fortune" + " to view or edit in the box to the bottom.")); + QWhatsThis::add(d->te_fortune, + tr("Here you may edit the fortune selected in the list above.")); + + // quote & reply + QWhatsThis::add(d->ck_headerQuote, + tr("Check this option if you want to include a header when quoting a message.")); + QWhatsThis::add(d->pb_insQuote, + tr("Press this button if you want to add special symbols to your header.")); + QWhatsThis::add(d->te_headerQuote, + tr("You may edit your header here.")); + + QWhatsThis::add(d->ck_headerReply, + tr("Check this option if you want to include a header when replying a message.")); + QWhatsThis::add(d->pb_insReply, + tr("Press this button if you want to add special symbols to your header.")); + QWhatsThis::add(d->te_headerReply, + tr("You may edit your header here.")); + + // forward + QWhatsThis::add(d->ck_headerForward, + tr("Check this option if you want to include a header when forwarding a message.")); + QWhatsThis::add(d->pb_insForward, + tr("Press this button if you want to add special symbols to your header.")); + QWhatsThis::add(d->te_headerForward, + tr("You may edit your header here.")); + + // misc + QWhatsThis::add(d->ck_quoteEmptyLines, + tr("Uncheck this option if you don't want empty lines to be" + " prepended with '>' character when quoting.")); + QWhatsThis::add(d->ck_stripEmptyLines, + tr("Check this option if you want to remove empty lines at the beginning" + " and ending of a message when quoting it.")); + QWhatsThis::add(d->ck_removeSignature, + tr("Check this option if you don't want to include sender's signature" + " in the quoted text.")); + QWhatsThis::add(d->sb_wrapAtColumn, + tr("Here you may change the maximum length of a line in the quoted message.")); + + QWhatsThis::add(d->ck_hideQuoteBtn, + tr("Check this option if you want to have only 'Reply' button, instead of 'Quote'" + " and 'Reply'. In one-button mode, you may change 'Reply' button to work" + " as 'Quote' by changing your default way of replying.")); + QWhatsThis::add(d->ck_defaultReplyWithoutQuoting, + tr("This option is used to determine your default way of replying a message." + " Default way of replying if used by Ctrl+R hotkey." + " In addition, this action is invoked by 'Reply' button when 'Quote' button is hidden.")); + + QWhatsThis::add(d->ck_hideChatBtn, + tr("Check this option to hide 'Chat' button.")); + QWhatsThis::add(d->ck_showReplyInAuthRequests, + tr("Check this option if you want to have replying buttons in authorization request windows.")); + QWhatsThis::add(d->ck_cursorAtTop, + tr("Check this option if you want cursor to be at the top of the edit.")); + + + // don't worry: these menus are deleted in OptMessagesUI::destroy() + d->pb_insForward->setPopup(new QuoteHeaderPopup(d->te_headerForward)); + d->pb_insReply->setPopup(new QuoteHeaderPopup(d->te_headerReply)); + d->pb_insQuote->setPopup(new QuoteHeaderPopup(d->te_headerQuote)); + d->pb_insSignature->setPopup(new SignaturePopup(d->te_signature)); + + + // tags for header template + TemplateEditHighlighter::TagsVector headerTags; + + headerTags.push_back("Sender.jid.bare"); + headerTags.push_back("Sender.jid.full"); + headerTags.push_back("Sender.nick"); + headerTags.push_back("Sender.nick-jid"); + + headerTags.push_back("Me.jid.bare"); + headerTags.push_back("Me.jid.full"); + headerTags.push_back("Me.nick"); + headerTags.push_back("Me.nick-jid"); + + headerTags.push_back("Message.DateTime"); + headerTags.push_back("Message.subject"); + + headerTags.push_back(""); + + // tags for signature template + TemplateEditHighlighter::TagsVector signatureTags; + + signatureTags.push_back("Fortune"); + signatureTags.push_back(""); + + // syntax highlighters are deleted by edit boxes + new TemplateEditHighlighter(d->te_headerForward, headerTags); + new TemplateEditHighlighter(d->te_headerReply, headerTags); + new TemplateEditHighlighter(d->te_headerQuote, headerTags); + new TemplateEditHighlighter(d->te_signature, signatureTags); + + // fortunes editing + d->pb_fortuneNew->setEnabled(TRUE); + d->pb_fortuneDelete->setEnabled(FALSE); + d->te_fortune->setEnabled(FALSE); + + connect(d->pb_fortuneNew, SIGNAL(clicked()), SLOT(newFortune())); + connect(d->pb_fortuneDelete, SIGNAL(clicked()), SLOT(removeFortune())); + connect(d->lb_fortunes, SIGNAL(highlighted(int)), SLOT(selectFortune(int))); + connect(d->te_fortune, SIGNAL(textChanged()), SLOT(changeFortune())); + + return w; +} + +void OptionsTabMessages::applyOptions(Options *opt) +{ + if ( !w ) + return; + + OptMessagesUI *d = (OptMessagesUI *)w; + + opt->useQuoteHeaderForward = d->ck_headerForward->isChecked(); + opt->quoteHeaderForward = d->te_headerForward->text(); + opt->useQuoteHeaderQuote = d->ck_headerQuote->isChecked(); + opt->quoteHeaderQuote = d->te_headerQuote->text(); + opt->useQuoteHeaderReply = d->ck_headerReply->isChecked(); + opt->quoteHeaderReply = d->te_headerReply->text(); + + opt->useMessageSignature = d->ck_signature->isChecked(); + opt->messageSignature = d->te_signature->text(); + opt->autoMessageSignatureDelimiter = d->ck_signatureAutoDelimiter->isChecked(); + + opt->fortunes = o->fortunes; + + opt->wrapAtColumn = d->sb_wrapAtColumn->value(); + opt->quoteEmptyLines = d->ck_quoteEmptyLines->isChecked(); + opt->stripEmptyLines = d->ck_stripEmptyLines->isChecked(); + opt->removeSignature = d->ck_removeSignature->isChecked(); + + opt->hideQuoteBtn = d->ck_hideQuoteBtn->isChecked(); + opt->defaultReplyWithoutQuoting = d->ck_defaultReplyWithoutQuoting->isChecked(); + opt->hideChatBtn = d->ck_hideChatBtn->isChecked(); + opt->replyInAuthReq = d->ck_showReplyInAuthRequests->isChecked(); + + opt->cursorAtTopInEventDlg = d->ck_cursorAtTop->isChecked(); +} + +void OptionsTabMessages::restoreOptions(const Options *opt) +{ + if ( !w ) + return; + + OptMessagesUI *d = (OptMessagesUI *)w; + + d->ck_headerForward->setChecked( true ); + d->ck_headerForward->setChecked( opt->useQuoteHeaderForward ); + d->te_headerForward->setText( opt->quoteHeaderForward ); + d->ck_headerQuote->setChecked( true ); + d->ck_headerQuote->setChecked( opt->useQuoteHeaderQuote ); + d->te_headerQuote->setText( opt->quoteHeaderQuote ); + d->ck_headerReply->setChecked( true ); + d->ck_headerReply->setChecked( opt->useQuoteHeaderReply ); + d->te_headerReply->setText( opt->quoteHeaderReply ); + + d->ck_signature->setChecked( true ); + d->ck_signature->setChecked( opt->useMessageSignature ); + d->te_signature->setText( opt->messageSignature ); + d->ck_signatureAutoDelimiter->setChecked( opt->autoMessageSignatureDelimiter ); + + o->fortunes = opt->fortunes; + d->lb_fortunes->clear(); + for ( QValueVector::ConstIterator it = o->fortunes.begin(); it != o->fortunes.end(); ++it ) { + d->lb_fortunes->insertFortune(*it); + } + if ( d->lb_fortunes->count() >= 1 ) + d->lb_fortunes->setSelected(0, TRUE); + + d->sb_wrapAtColumn->setValue( opt->wrapAtColumn ); + d->ck_quoteEmptyLines->setChecked( opt->quoteEmptyLines ); + d->ck_stripEmptyLines->setChecked( opt->stripEmptyLines ); + d->ck_removeSignature->setChecked( opt->removeSignature ); + + d->ck_hideQuoteBtn->setChecked( opt->hideQuoteBtn ); + d->ck_defaultReplyWithoutQuoting->setChecked( opt->defaultReplyWithoutQuoting ); + d->ck_hideChatBtn->setChecked( opt->hideChatBtn ); + d->ck_showReplyInAuthRequests->setChecked( opt->replyInAuthReq ); + d->ck_cursorAtTop->setChecked( opt->cursorAtTopInEventDlg ); +} + +void OptionsTabMessages::setData(PsiCon *, QWidget *parentDialog) +{ + parentWidget = parentDialog; +} + +void OptionsTabMessages::selectFortune(int x) +{ + OptMessagesUI *d = (OptMessagesUI *)w; + + disconnect(d->te_fortune, SIGNAL(textChanged()), 0, 0); + + if ( x == -1 ) { + d->pb_fortuneDelete->setEnabled(false); + d->te_fortune->setText(""); + d->te_fortune->setEnabled(false); + + connect(d->te_fortune, SIGNAL(textChanged()), SLOT(changeFortune())); + return; + } + + d->pb_fortuneDelete->setEnabled(true); + + d->te_fortune->setText(d->lb_fortunes->getFortune(x)); + d->te_fortune->setEnabled(true); + + connect(d->te_fortune, SIGNAL(textChanged()), SLOT(changeFortune())); +} + +void OptionsTabMessages::newFortune() +{ + OptMessagesUI *d = (OptMessagesUI *)w; + + QString text; + + while(1) { + bool ok = FALSE; + text = MultiLineInputDialog::getMultiLineText( + CAP(tr("New Fortune")), + tr("Please enter the new fortune:"), true, + text, &ok, parentWidget); + if(!ok) + return; + + if(text.isEmpty()) + QMessageBox::information(parentWidget, tr("Error"), tr("Can't create a blank fortune!")); + else if(qFind(o->fortunes.begin(), o->fortunes.end(), text) != o->fortunes.end()) + QMessageBox::information(parentWidget, tr("Error"), tr("This fortune already exists!")); + else + break; + } + + o->fortunes.push_back(text); + d->lb_fortunes->insertFortune(text); + d->lb_fortunes->setSelected(d->lb_fortunes->count()-1, TRUE); + d->lb_fortunes->ensureCurrentVisible(); + + d->te_fortune->setFocus(); + + emit dataChanged(); +} + +void OptionsTabMessages::removeFortune() +{ + OptMessagesUI *d = (OptMessagesUI *)w; + int id = d->lb_fortunes->currentItem(); + if(id == -1) + return; + + emit dataChanged(); + + QValueVector::Iterator it = o->fortunes.begin(); + for ( int i = 0; it != o->fortunes.end() && i != id; ++i, ++it) + ; + o->fortunes.erase(it); + + d->lb_fortunes->removeItem(id); + + // select a new entry if possible + if(d->lb_fortunes->count() == 0) { + selectFortune(-1); + return; + } + + if(id >= (int)d->lb_fortunes->count()) + id = d->lb_fortunes->count()-1; + + d->lb_fortunes->setSelected(id, TRUE); + selectFortune(id); +} + +void OptionsTabMessages::changeFortune() +{ + OptMessagesUI *d = (OptMessagesUI *)w; + int id = d->lb_fortunes->currentItem(); + if(id == -1) + return; + + int para, index; + d->te_fortune->getCursorPosition(¶, &index); + + const QString text = d->te_fortune->text(); + o->fortunes[id] = text; + d->lb_fortunes->updateFortune(text, id); + + d->te_fortune->setFocus(); + d->te_fortune->setCursorPosition(para, index); + + emit dataChanged(); +} + +#include "opt_messages.moc" diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/opt_messages.h psi/psi/src/options/opt_messages.h --- psi_cvs-2005.05.17/psi/src/options/opt_messages.h Thu Jan 1 01:00:00 1970 +++ psi/psi/src/options/opt_messages.h Tue May 17 20:54:18 2005 @@ -0,0 +1,68 @@ +/* + * opt_messages.h - options tab for messages options + * Copyright (C) 2005 Maciej Niedzielski + * + * 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef OPT_MESSAGES_H +#define OPT_MESSAGES_H + +#include "optionstab.h" + +#include + +class QWidget; + +class OptionsTabMessages: public OptionsTab +{ + Q_OBJECT +public: + OptionsTabMessages(QObject *parent); + ~OptionsTabMessages(); + + QWidget *widget(); + void applyOptions(Options *opt); + void restoreOptions(const Options *opt); + + void setData(PsiCon *, QWidget *parentDialog); + +private slots: + void selectFortune(int x); + void newFortune(); + void removeFortune(); + void changeFortune(); + +private: + QWidget *w, *parentWidget; + Options *o; +}; + + +// dynamic listbox of fortunes + +class FortunesListBox : public QListBox +{ + Q_OBJECT +public: + FortunesListBox(QWidget* parent=0, const char* name=0, WFlags f=0); + + void insertFortune(const QString &fortune); + void updateFortune(const QString &fortune, int id); + QString getFortune(int id); +}; + +#endif diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/options.pri psi/psi/src/options/options.pri --- psi_cvs-2005.05.17/psi/src/options/options.pri Thu Nov 27 14:09:12 2003 +++ psi/psi/src/options/options.pri Tue May 17 20:54:18 2005 @@ -16,6 +16,7 @@ $$PSI_CPP/options/opt_application.h \ $$PSI_CPP/options/opt_chat.h \ $$PSI_CPP/options/opt_events.h \ + $$PSI_CPP/options/opt_messages.h \ $$PSI_CPP/options/opt_status.h \ $$PSI_CPP/options/opt_appearance.h \ $$PSI_CPP/options/opt_lookfeel.h \ @@ -28,6 +29,7 @@ $$PSI_CPP/options/opt_application.cpp \ $$PSI_CPP/options/opt_chat.cpp \ $$PSI_CPP/options/opt_events.cpp \ + $$PSI_CPP/options/opt_messages.cpp \ $$PSI_CPP/options/opt_status.cpp \ $$PSI_CPP/options/opt_appearance.cpp \ $$PSI_CPP/options/opt_lookfeel.cpp \ @@ -40,6 +42,7 @@ $$PSI_CPP/options/opt_application-ui.ui \ $$PSI_CPP/options/opt_chat-ui.ui \ $$PSI_CPP/options/opt_events-ui.ui \ + $$PSI_CPP/options/opt_messages-ui.ui \ $$PSI_CPP/options/opt_status-ui.ui \ $$PSI_CPP/options/opt_appearance-ui.ui \ $$PSI_CPP/options/opt_sound-ui.ui \ diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/options/optionsdlg.cpp psi/psi/src/options/optionsdlg.cpp --- psi_cvs-2005.05.17/psi/src/options/optionsdlg.cpp Sun May 15 22:26:44 2005 +++ psi/psi/src/options/optionsdlg.cpp Tue May 17 20:54:18 2005 @@ -19,6 +19,7 @@ #include "opt_appearance.h" #include "opt_chat.h" #include "opt_events.h" +#include "opt_messages.h" #include "opt_status.h" #include "opt_iconset.h" #include "opt_groupchat.h" @@ -306,6 +307,7 @@ tabs.append( new OptionsTabApplication(this) ); tabs.append( new OptionsTabChat(this) ); tabs.append( new OptionsTabEvents(this) ); + tabs.append( new OptionsTabMessages(this) ); tabs.append( new OptionsTabStatus(this) ); tabs.append( new OptionsTabAppearance(this) ); //tabs.append( new OptionsTabIconsetSystem(this) ); diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/psi_profiles.cpp psi/psi/src/psi_profiles.cpp --- psi_cvs-2005.05.17/psi/src/psi_profiles.cpp Sun May 15 22:26:44 2005 +++ psi/psi/src/psi_profiles.cpp Tue May 17 20:54:18 2005 @@ -615,6 +615,30 @@ prefs.dtPort = 8010; prefs.dtExternal = ""; + // machekku: smart forward and reply + prefs.quoteHeaderQuote = QObject::tr("On , wrote:"); + prefs.quoteHeaderReply = QObject::tr("In reply to your message from :"); + prefs.quoteHeaderForward = QObject::tr("On , wrote:"); + + prefs.useQuoteHeaderQuote = true; + prefs.useQuoteHeaderReply = false; + prefs.useQuoteHeaderForward = true; + + prefs.messageSignature = ""; + prefs.useMessageSignature = false; + prefs.autoMessageSignatureDelimiter = true; + + prefs.wrapAtColumn = 60; + prefs.quoteEmptyLines = true; + prefs.stripEmptyLines = true; + prefs.removeSignature = true; + + prefs.cursorAtTopInEventDlg = false; + prefs.hideQuoteBtn = false; + prefs.hideChatBtn = false; + prefs.replyInAuthReq = true; + prefs.defaultReplyWithoutQuoting = true; + // Avatars prefs.avatarsEnabled = true; prefs.avatarsChatdlgEnabled = true; @@ -925,6 +949,61 @@ } } + { // machekku: smart forward and reply + QDomElement p_messages = doc.createElement("messages"); + p.appendChild(p_messages); + + { + QDomElement p_quoteHeaders = doc.createElement("quoteHeaders"); + p_messages.appendChild(p_quoteHeaders); + + QDomElement headerQuote = textTag(doc, "quote", prefs.quoteHeaderQuote); + setBoolAttribute(headerQuote, "use", prefs.useQuoteHeaderQuote); + p_quoteHeaders.appendChild(headerQuote); + + QDomElement headerReply = textTag(doc, "reply", prefs.quoteHeaderReply); + setBoolAttribute(headerReply, "use", prefs.useQuoteHeaderReply); + p_quoteHeaders.appendChild(headerReply); + + QDomElement headerForward = textTag(doc, "forward", prefs.quoteHeaderForward); + setBoolAttribute(headerForward, "use", prefs.useQuoteHeaderForward); + p_quoteHeaders.appendChild(headerForward); + } + { + QDomElement p_messageSignature = textTag(doc, "signature", prefs.messageSignature); + p_messages.appendChild(p_messageSignature); + + setBoolAttribute(p_messageSignature, "use", prefs.useMessageSignature); + setBoolAttribute(p_messageSignature, "autoAddDelimiter", prefs.autoMessageSignatureDelimiter); + } + { + QDomElement p_fortunes = doc.createElement("fortunes"); + p_messages.appendChild(p_fortunes); + + for(QValueVector::ConstIterator it = prefs.fortunes.begin(); it != prefs.fortunes.end(); ++it) + p_fortunes.appendChild(textTag(doc, "item", *it)); + } + { + QDomElement p_quote = doc.createElement("quote"); + p_messages.appendChild(p_quote); + + p_quote.appendChild(textTag(doc, "wrapAtColumn", prefs.wrapAtColumn )); + p_quote.appendChild(textTag(doc, "quoteEmptyLines", prefs.quoteEmptyLines )); + p_quote.appendChild(textTag(doc, "stripEmptyLines", prefs.stripEmptyLines )); + p_quote.appendChild(textTag(doc, "removeSignature", prefs.removeSignature )); + } + { + QDomElement p_misc = doc.createElement("misc"); + p_messages.appendChild(p_misc); + + p_misc.appendChild(textTag(doc, "cursorAtTop", prefs.cursorAtTopInEventDlg )); + p_misc.appendChild(textTag(doc, "hideQuoteBtn", prefs.hideQuoteBtn )); + p_misc.appendChild(textTag(doc, "hideChatBtn", prefs.hideChatBtn )); + p_misc.appendChild(textTag(doc, "replyInAuthReq", prefs.replyInAuthReq )); + p_misc.appendChild(textTag(doc, "defaultReplyWithoutQuoting", prefs.defaultReplyWithoutQuoting )); + } + } + { QDomElement p_sound = doc.createElement("sound"); p.appendChild(p_sound); @@ -1469,6 +1548,79 @@ readEntry(tag, "message", &prefs.font[fMessage]); readEntry(tag, "chat", &prefs.font[fChat]); readEntry(tag, "popup", &prefs.font[fPopup]); + } + } + + // machekku: smart forward and reply + QDomElement p_messages = findSubTag(p, "messages", &found); + if(found) { + bool found; + + QDomElement p_quoteHeaders = findSubTag(p_messages, "quoteHeaders", &found); + if(found) { + bool found; + + QDomElement headerQuote = findSubTag(p_quoteHeaders, "quote", &found); + if(found) { + readBoolAttribute(headerQuote, "use", &prefs.useQuoteHeaderQuote); + prefs.quoteHeaderQuote = tagContent(headerQuote); + } + + QDomElement headerReply = findSubTag(p_quoteHeaders, "reply", &found); + if(found) { + readBoolAttribute(headerReply, "use", &prefs.useQuoteHeaderReply); + prefs.quoteHeaderReply = tagContent(headerReply); + } + + QDomElement headerForward = findSubTag(p_quoteHeaders, "forward", &found); + if(found) { + readBoolAttribute(headerForward, "use", &prefs.useQuoteHeaderForward); + prefs.quoteHeaderForward = tagContent(headerForward); + } + } + + QDomElement p_messageSignature = findSubTag(p_messages, "signature", &found); + if(found) { + readBoolAttribute(p_messageSignature, "use", &prefs.useMessageSignature); + readBoolAttribute(p_messageSignature, "autoAddDelimiter", &prefs.autoMessageSignatureDelimiter); + prefs.messageSignature = tagContent(p_messageSignature); + } + + QDomElement p_random = findSubTag(p_messages, "fortunes", &found); + + // FIX-ME! + // This is to be backward compatible with previous versions of Smart Forward and Reply. + // When including into CVS, this should probably be removed. + if(!found) p_random = findSubTag(p_messages, "randomSignatures", &found); + + if(found) { + for(QDomNode n = p_random.firstChild(); !n.isNull(); n = n.nextSibling()) { + QDomElement i = n.toElement(); + if(i.isNull()) + continue; + if(i.tagName() == "item") { + QDomText t = i.firstChild().toText(); + if(!t.isNull()) + prefs.fortunes.push_back(t.data()); + } + } + } + + QDomElement p_quote = findSubTag(p_messages, "quote", &found); + if(found) { + readNumEntry (p_quote, "wrapAtColumn", &prefs.wrapAtColumn ); + readBoolEntry(p_quote, "quoteEmptyLines", &prefs.quoteEmptyLines ); + readBoolEntry(p_quote, "stripEmptyLines", &prefs.stripEmptyLines ); + readBoolEntry(p_quote, "removeSignature", &prefs.removeSignature ); + } + + QDomElement p_misc = findSubTag(p_messages, "misc", &found); + if(found) { + readBoolEntry(p_misc, "cursorAtTop", &prefs.cursorAtTopInEventDlg ); + readBoolEntry(p_misc, "hideQuoteBtn", &prefs.hideQuoteBtn ); + readBoolEntry(p_misc, "hideChatBtn", &prefs.hideChatBtn ); + readBoolEntry(p_misc, "replyInAuthReq", &prefs.replyInAuthReq ); + readBoolEntry(p_misc, "defaultReplyWithoutQuoting", &prefs.defaultReplyWithoutQuoting ); } } diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/psiaccount.cpp psi/psi/src/psiaccount.cpp --- psi_cvs-2005.05.17/psi/src/psiaccount.cpp Sun May 15 22:26:44 2005 +++ psi/psi/src/psiaccount.cpp Tue May 17 20:54:18 2005 @@ -39,6 +39,8 @@ #include #include +#include + #include"psicon.h" #include"profiles.h" #include"im.h" @@ -77,6 +79,7 @@ #include"filetransdlg.h" #include"avatars.h" #include"tabdlg.h" +#include"templates.h" #if defined(Q_WS_MAC) && defined(HAVE_GROWL) #include "psigrowlnotifier.h" @@ -2195,7 +2198,7 @@ w = new EventDlg(j, this, true); connect(w, SIGNAL(aReadNext(const Jid &)), SLOT(processReadNext(const Jid &))); connect(w, SIGNAL(aChat(const Jid &)), SLOT(actionOpenChat(const Jid&))); - connect(w, SIGNAL(aReply(const Jid &, const QString &, const QString &, const QString &)), SLOT(dj_composeMessage(const Jid &, const QString &, const QString &, const QString &))); + connect(w, SIGNAL(aCompose(const Jid &, const QString &, const QString &, const QString &, ComposeType, const Jid &, const Jid &, const QDateTime &, const UrlList &)), SLOT(dj_composeMessage(const Jid &, const QString &, const QString &, const QString &, ComposeType, const Jid &, const Jid &, const QDateTime &, const UrlList &))); connect(w, SIGNAL(aAuth(const Jid &)), SLOT(dj_addAuth(const Jid &))); connect(w, SIGNAL(aDeny(const Jid &)), SLOT(dj_deny(const Jid &))); connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate())); @@ -2339,6 +2342,10 @@ void PsiAccount::actionSendMessage(const Jid &j) { EventDlg *w = d->psi->createEventDlg(j.full(), this); + + if(option.useMessageSignature) + w->setText(expandSignatureTemplate(option.messageSignature, option.autoMessageSignatureDelimiter), option.cursorAtTopInEventDlg); + w->show(); } @@ -2355,6 +2362,10 @@ } EventDlg *w = d->psi->createEventDlg(str, this); + + if(option.useMessageSignature) + w->setText(expandSignatureTemplate(option.messageSignature, option.autoMessageSignatureDelimiter), option.cursorAtTopInEventDlg); + w->show(); } @@ -2362,6 +2373,10 @@ { EventDlg *w = d->psi->createEventDlg(j.full(), this); w->setUrlOnShow(); + + if(option.useMessageSignature) + w->setText(expandSignatureTemplate(option.messageSignature, option.autoMessageSignatureDelimiter), option.cursorAtTopInEventDlg); + w->show(); } @@ -2419,7 +2434,7 @@ { EventDlg *w = new EventDlg(e->from(), this, false); connect(w, SIGNAL(aChat(const Jid &)), SLOT(actionOpenChat(const Jid&))); - connect(w, SIGNAL(aReply(const Jid &, const QString &, const QString &, const QString &)), SLOT(dj_composeMessage(const Jid &, const QString &, const QString &, const QString &))); + connect(w, SIGNAL(aCompose(const Jid &, const QString &, const QString &, const QString &, ComposeType, const Jid &, const Jid &,const QDateTime &, const UrlList &)), SLOT(dj_composeMessage(const Jid &, const QString &, const QString &, const QString &, ComposeType, const Jid &, const Jid &,const QDateTime &, const UrlList &))); connect(w, SIGNAL(aAuth(const Jid &)), SLOT(dj_addAuth(const Jid &))); connect(w, SIGNAL(aDeny(const Jid &)), SLOT(dj_deny(const Jid &))); connect(d->psi, SIGNAL(emitOptionsUpdate()), w, SLOT(optionsUpdate())); @@ -2666,26 +2681,211 @@ } } -void PsiAccount::dj_composeMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread) +// machekku: smart forward and reply + +/*! + Expands quote header template \a headerTemplate for a message with + subject \a subject, sender's JID \a jidSender, user's JID \a jidMe, + sent on \a originalMessageTime. +*/ + +QString PsiAccount::expandQuoteHeadlineTemplate(const Template &headerTemplate, + const QString &subject, const Jid &jidSender, + const Jid &jidMe, const QDateTime &originalMessageTime) { + QString header; + + if ( !headerTemplate.isEmpty() ) { + + QPtrList ul = findRelavent(jidSender); + UserListItem *uSender = 0; + if(!ul.isEmpty()) uSender = ul.first(); + + ul = findRelavent(jidMe); + UserListItem *uMe = 0; + if(!ul.isEmpty()) uMe = ul.first(); + + Template::ExpandData values; + + values["Message.DateTime"] = originalMessageTime.toString(LocalDate); + values["Message.subject"] = subject; + + values["Sender.jid.full"] = jidSender.full(); + values["Sender.jid.bare"] = jidSender.bare(); + values["Sender.nick"] = (uSender)? uSender->name() : ""; + values["Sender.nick-jid"] = jidnick(jidSender.bare(), (uSender)? uSender->name() : ""); + + values["Me.jid.full"] = jidMe.resource().isEmpty()? jidMe.full() + "/" + d->client->resource() : jidMe.full(); + values["Me.jid.bare"] = jidMe.bare(); + values["Me.nick"] = (uMe)? uMe->name() : "";; + values["Me.nick-jid"] = jidnick(jidMe.bare(), (uMe)? uMe->name() : ""); + + header = headerTemplate.expand(values); + } + + return header; +} + +/*! + Expands signature template \a signatureTemplate. + + If \a ensureDelimiter is true and signature template does not start with + signature delimiter ("-- \n"), it will be added at the beginning of expanded string. + + If \a signatureForNewMessage is true, this method will make sure that + there will be two empty lines before the real signature starts. +*/ + +QString PsiAccount::expandSignatureTemplate(const Template &signatureTemplate, bool ensureDelimiter, bool signatureForNewMessage /* = TRUE */) +{ + QString signature; + + if ( !signatureTemplate.isEmpty() ) { + + Template::ExpandData values; + + values["fortune"] = (option.fortunes.count())? option.fortunes[rand()%option.fortunes.count()] : ""; + + signature = signatureTemplate.expand(values); + + // add delimiter + if(ensureDelimiter && !signature.startsWith("-- \n")) + signature = "-- \n" + signature; + + if(signatureForNewMessage && !signature.startsWith("\n\n")) { // new message - two empty lines before sig + if (signature[0]=='\n') + signature = "\n" + signature; + else + signature = "\n\n" + signature; + } + } + + return signature; +} + +/*! + Composes a message to \a jid with body \a body, subject \a subject and thread \a thread. + + If compose type \ct is ctNew (new message is being created), rest of the arguments is ignored. + In other case \a originalJid_Sender is sender of the original message and + \a originalJid_Sender is receiver of the original message, which was sent on + \a originalMessageTime and contained \a originalMessageAttachements attachements. +*/ + +void PsiAccount::dj_composeMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread, + ComposeType ct, const Jid &originalJid_Sender, const Jid &originalJid_Me, + const QDateTime &originalMessageTime, const UrlList &originalMessageAttachements) +{ + EventDlg *w = d->psi->createEventDlg(jid.full(), this); - if(!body.isEmpty()) - w->setText(qstrquote(body)); - if(!subject.isEmpty() && subject.left(3) != "Re:") - w->setSubject("Re: " + subject); - else if (subject.left(3) == "Re:") - w->setSubject(subject); + // header + QString headerTemplate = ""; + + if ( ct == ctQuote && option.useQuoteHeaderQuote ) { + headerTemplate = option.quoteHeaderQuote; + } + else if ( ct == ctReply && option.useQuoteHeaderReply ) { + headerTemplate = option.quoteHeaderReply; + } + else if ( ct == ctForward && option.useQuoteHeaderForward ) { + headerTemplate = option.quoteHeaderForward; + } + QString header = expandQuoteHeadlineTemplate(headerTemplate, subject, originalJid_Sender, originalJid_Me, originalMessageTime); + + // body + QString messageBody = ""; + if ( ct == ctNew ) { + messageBody = body; + } + else if ( ct != ctReply ) { // ctReply -> empty body + messageBody = qstrquote(body, option.wrapAtColumn, option.quoteEmptyLines, option.stripEmptyLines, option.removeSignature); + } + + // header/body separator + // we want to have one '\n' between header and body + QString sepBody = ""; + if (!header.isEmpty() && !messageBody.isEmpty() && !header.endsWith("\n") && !messageBody.startsWith("\n")) + sepBody = "\n"; + + // signature + QString signature = (option.useMessageSignature)? expandSignatureTemplate(option.messageSignature, option.autoMessageSignatureDelimiter,FALSE) : ""; + + // body/signature separator + // we want to have one empty line between body and signature (at least two '\n'); + // or, when body is empty, an empty line between header and signature + QString sepSig = ""; + const QString &separated = (messageBody.isEmpty())? header : messageBody; - if(!thread.isEmpty()) + if (!signature.isEmpty()) { + int nNewLines = 0; + + if ( separated.endsWith("\n\n") ) + nNewLines = 2; + else if ( separated.endsWith("\n") ) + nNewLines = 1; + if ( signature.startsWith("\n\n") ) + nNewLines += 2; + else if ( signature.startsWith("\n") ) + ++nNewLines; + + if ( nNewLines == 1 ) + sepSig = "\n"; + else if ( nNewLines == 0 ) + sepSig = "\n\n"; + } + + // message text is ready + w->setText(header + sepBody + messageBody + sepSig + signature, option.cursorAtTopInEventDlg); + + // subject + QString prefix; + if ( ct == ctForward ) { + prefix = "Fw:"; + } + else if ( ct == ctReply || ct == ctQuote ) { + prefix = "Re:"; + } + + if (!prefix.isEmpty()) { + const int pl = prefix.length(); + if(!subject.isEmpty() && subject.left(pl) != prefix) + w->setSubject(prefix + " " + subject); + else if (subject.left(pl) == prefix) + w->setSubject(subject); + } + + // thread - copy thread only for reply/quote, not for forward + if(!thread.isEmpty() && (ct == ctReply || ct == ctQuote)) w->setThread(thread); + // attachements - copy when forwarding + if (ct == ctForward) { + for(QValueList::ConstIterator it = originalMessageAttachements.begin(); it != originalMessageAttachements.end(); ++it) { + const Url &u = *it; + w->addAttachement(u.url(), u.desc()); + } + } + w->show(); } +void PsiAccount::dj_composeMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread) +{ + Jid jDummy; + QDateTime qdtDummy; + UrlList ulDummy; + dj_composeMessage(jid, body, subject, thread, ctQuote , jDummy, jDummy, qdtDummy, ulDummy); +} + void PsiAccount::dj_composeMessage(const Jid &j, const QString &body) { - dj_composeMessage(j, body, QString::null, QString::null); + Jid jDummy; + QDateTime qdtDummy; + UrlList ulDummy; + dj_composeMessage(j, body, QString::null, QString::null, + ctNew, jDummy, jDummy, qdtDummy, ulDummy); + } void PsiAccount::dj_addAuth(const Jid &j) diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/psiaccount.h psi/psi/src/psiaccount.h --- psi_cvs-2005.05.17/psi/src/psiaccount.h Sun May 15 22:26:44 2005 +++ psi/psi/src/psiaccount.h Tue May 17 22:17:30 2005 @@ -230,6 +230,10 @@ void dj_sendMessage(const Message &, bool log=true); void dj_composeMessage(const Jid &jid, const QString &body); void dj_composeMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread); + // machekku: smart forward and reply + void dj_composeMessage(const Jid &jid, const QString &body, const QString &subject, const QString &thread, + ComposeType ct, const Jid &originalJid_Sender, const Jid &originalJid_Me, + const QDateTime &originalMessageTime, const UrlList &originalMessageAttachements); void dj_addAuth(const Jid &); void dj_add(const Jid &, const QString &, const QStringList &, bool authReq); void dj_authReq(const Jid &); @@ -237,7 +241,6 @@ void dj_deny(const Jid &); void dj_rename(const Jid &, const QString &); void dj_remove(const Jid &); - void actionDefault(const Jid &); void actionRecvEvent(const Jid &); void actionSendMessage(const Jid &); @@ -361,11 +364,16 @@ void promptPassphrase(); void processChats(const Jid &); void openChat(const Jid &); + EventDlg *ensureEventDlg(const Jid &); friend class PsiCon; bool isDisconnecting, notifyOnlineOk, doReconnect, usingAutoStatus, rosterDone, presenceSent, v_isActive; void cleanupStream(); + + QString expandQuoteHeadlineTemplate(const Template &headerTemplate, + const QString &subject, const Jid &jidSender, const Jid &jidMe, const QDateTime &originalMessageTime); + QString expandSignatureTemplate(const Template &signatureTemplate, bool ensureDelimiter, bool signatureForNewMessage = TRUE); friend class Private; }; diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/psicon.cpp psi/psi/src/psicon.cpp --- psi_cvs-2005.05.17/psi/src/psicon.cpp Sun May 15 22:26:44 2005 +++ psi/psi/src/psicon.cpp Tue May 17 20:54:18 2005 @@ -728,6 +728,10 @@ return; EventDlg *w = createEventDlg("", pa); + + if(option.useMessageSignature) + w->setText(pa->expandSignatureTemplate(option.messageSignature, option.autoMessageSignatureDelimiter), option.cursorAtTopInEventDlg); + w->show(); } diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/multilineinput/multilineinput.cpp psi/psi/src/tools/multilineinput/multilineinput.cpp --- psi_cvs-2005.05.17/psi/src/tools/multilineinput/multilineinput.cpp Thu Jan 1 01:00:00 1970 +++ psi/psi/src/tools/multilineinput/multilineinput.cpp Tue May 17 20:54:20 2005 @@ -0,0 +1,162 @@ +/* + * multilineinput.h - simple dialog to get MultiLine text from user + * Copyright (C) 2005 Maciej Niedzielski + * + * 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "multilineinput.h" + +#include +#include +#include +#include + +/* + Multiline edit control for MultiLineInputDialog class, + introduced to control hotkeys. +*/ + +class MultiLineInputDialog::Mle : public QTextEdit { +public: + Mle(QWidget *parent) : QTextEdit(parent) {} + + void keyPressEvent(QKeyEvent *e) { + if(e->key() == Key_Return && ((e->state() & ControlButton) || (e->state() & AltButton)) ) + e->ignore(); + else + QTextEdit::keyPressEvent(e); + } +}; + + +/*! + \class MultiLineInputDialog multilineinput.h + \brief The MultiLineInputDialog class provides a simple dialog to get a multiline string from the user. + + \mainclass + + MultiLineInputDialog class is a QInputDialog like class, providing a way to get a multiline string from the user. + + \code + bool ok; + QString text = MultiLineInputDialog::getMultiLineText( + "New Fortune", "Please enter the new fortune:", true, + QString::null, &ok, this); + + if ( ok && !text.isEmpty() ) { + // user entered something and pressed OK + } else { + // user entered nothing or pressed Cancel + } + \endcode + + Pressing Ctrl+Tab will always input tab into the edit field. + Ctrl+Enter or Alt+Enter will invoke Ok. + + \sa QInputDialog +*/ + +/*! + Constructs the dialog. The \a caption is the text in dialog's caption, + the \a label test is information for user what they are expected to enter. + The \a parent is the dialog's parent widget. The widget is called \a name. If \a + modal is TRUE (the default) the dialog will be modal. + + \sa getMultiLineText() +*/ + +MultiLineInputDialog::MultiLineInputDialog(const QString &caption, const QString &label, bool tabChangesFocus, + const QString &text, QWidget *parent, const char *name, bool modal, WFlags f) + : QDialog (parent, name, modal, f) { + + setCaption(caption); + + QVBoxLayout *vbox = new QVBoxLayout(this, 3); + vbox->addWidget(new QLabel(label, this)); + + mle = new Mle(this); + mle->setText(text); + mle->setTabChangesFocus(tabChangesFocus); + + vbox->addWidget(mle); + + QHBoxLayout *hbox = new QHBoxLayout(6); + vbox->addLayout(hbox, AlignRight); + + QPushButton *ok = new QPushButton(tr("OK"), this, "qt_ok_btn" ); + ok->setDefault(TRUE); + QPushButton *cancel = new QPushButton(tr("Cancel"), this, "qt_cancel_btn" ); + + QSize bs = ok->sizeHint().expandedTo(cancel->sizeHint()); + ok->setFixedSize(bs); + cancel->setFixedSize(bs); + + hbox->addStretch(); + hbox->addWidget(ok); + hbox->addWidget(cancel); + + connect( ok, SIGNAL( clicked() ), this, SLOT( accept() ) ); + connect( cancel, SIGNAL( clicked() ), this,SLOT( reject() ) ); + + QSize sh = sizeHint().expandedTo(QSize(400, 10)); + resize(sh.width(),vbox->heightForWidth(sh.width())); +} + +/*! + Static function to input multiline text from user. + + The \a caption is the text in dialog's caption, + the \a label test is information for user what they are expected to enter. + The \a parent is the dialog's parent widget. The widget is called \a name. If \a + tabChangesFocus is TRUE, pressing Tab key while edit area is focused will change focused + widget - otherwise it will input tab character. +*/ + +QString MultiLineInputDialog::getMultiLineText(const QString &caption, const QString &label, bool tabChangesFocus, + const QString &text, bool *ok, QWidget *parent, const char *name) { + + MultiLineInputDialog *dlg = new MultiLineInputDialog(caption, label, tabChangesFocus, text, parent, + name? name : "input_MultiLine_text_dlg", TRUE); + QString result; + + bool isOk = ( dlg->exec() == QDialog::Accepted ); + + if ( ok ) { + *ok = isOk; + } + + if ( isOk ) { + result = dlg->mle->text(); + } + + delete dlg; + return result; +} + +/*! + Keyboard events filter to enable desired hotkeys. +*/ + +void MultiLineInputDialog::keyPressEvent(QKeyEvent *e) +{ + if ( e->key() == Key_Tab && e->state() & ControlButton ) + mle->insert("\t"); + else if ( e->key() == Key_Return && ((e->state() & ControlButton) || (e->state() & AltButton)) ) + accept(); + else + e->ignore(); +} diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/multilineinput/multilineinput.h psi/psi/src/tools/multilineinput/multilineinput.h --- psi_cvs-2005.05.17/psi/src/tools/multilineinput/multilineinput.h Thu Jan 1 01:00:00 1970 +++ psi/psi/src/tools/multilineinput/multilineinput.h Tue May 17 20:54:20 2005 @@ -0,0 +1,36 @@ +/* + * multilineinput.h - simple dialog to get multiline text from user + * Copyright (C) 2005 Maciej Niedzielski + * + * 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include + +class MultiLineInputDialog : public QDialog +{ +public: + static QString getMultiLineText(const QString &caption, const QString &label, bool tabChangesFocus, + const QString &text, bool *ok=0, QWidget *parent=0, const char *name=0); +protected: + void keyPressEvent(QKeyEvent *); + +private: + class Mle; + Mle *mle; + MultiLineInputDialog(const QString &caption, const QString &label, bool tabChangesFocus, + const QString &text, QWidget *parent=0, const char *name=0, bool modal=FALSE, WFlags f=0); +}; diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/multilineinput/multilineinput.pri psi/psi/src/tools/multilineinput/multilineinput.pri --- psi_cvs-2005.05.17/psi/src/tools/multilineinput/multilineinput.pri Thu Jan 1 01:00:00 1970 +++ psi/psi/src/tools/multilineinput/multilineinput.pri Tue May 17 20:54:20 2005 @@ -0,0 +1,4 @@ +multilineinput { + HEADERS += $$MULTILINEINPUT_CPP/multilineinput.h + SOURCES += $$MULTILINEINPUT_CPP/multilineinput.cpp +} diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/templates/templates.cpp psi/psi/src/tools/templates/templates.cpp --- psi_cvs-2005.05.17/psi/src/tools/templates/templates.cpp Thu Jan 1 01:00:00 1970 +++ psi/psi/src/tools/templates/templates.cpp Tue May 17 20:54:18 2005 @@ -0,0 +1,277 @@ +/* + * templates.cpp - set of utils to make editing templates easier + * Copyright (C) 2005 Maciej Niedzielski + * + * 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "templates.h" + +#include +#include +#include + +//---------------------------------------------------------------------------- +// TemplatePopup +//---------------------------------------------------------------------------- + +/*! + \class TemplatePopup templates.h + \brief The TemplatePopup provides a convenient class to create a popup menu for template edition. + + TemplatePopup is a specialised QPopupMenu designed to be used when + editing templates in an edit box. + + insertTemplateItem() function is used to add new menu item which will automatically + insert an into the template's edit box. +*/ + +class TemplatePopup::Private { +public: + QTextEdit *edit; + QMap tags; +}; + +/*! + Constructs a menu called \a name with parent \a parent. + The menu will be associated with \a edit edit box - the items + will be inserted into this widget. +*/ + +TemplatePopup::TemplatePopup(QTextEdit *edit, QWidget *parent, const char *name) + : QPopupMenu(parent, name) +{ + d = new Private; + d->edit = edit; + connect(this, SIGNAL(activated(int)), this, SLOT(onActivated(int))); +} + +/*! + Destroys the popup menu. +*/ + +TemplatePopup::~TemplatePopup() +{ + delete d; + d = 0; +} + +/*! + Inserts new menuitem representing a template tag. + The item will be displayed as \a text and will insert \a tag tag. +*/ +int TemplatePopup::insertTemplateItem(const QString &text, const QString &tag, const QString &/*desc*/ /* ="" */) +{ + int id = insertItem(text); + //setWhatsThis(id, "" + tag + "
" + ((desc!="")?desc:name)); + d->tags[id] = tag; + + return id; +} + +/*! + Internal slot inserting template tags when a menuitem is choosen. +*/ + +void TemplatePopup::onActivated(int id) +{ + if ( d->edit && d->tags.contains(id) ) { + d->edit->insert("<" + d->tags[id] + ">"); + d->edit->setFocus(); + } +} + +//---------------------------------------------------------------------------- +// TemplateEditHighlighter +//---------------------------------------------------------------------------- + + +/*! + \class TemplateEditHighlighter templates.h + \brief The TemplateEditHighlighter provides a highlighter class for template edit boxes. + + TemplateEditHighlighter a specialised QSyntaxHighlighter designed to be used when + editing templates in an edit box. +*/ + +/*! + Constructs a syntax highlighter for \a edit edit box, + which will highlight all tahs listed in \a template tags vector. +*/ + +TemplateEditHighlighter::TemplateEditHighlighter(QTextEdit *edit, TagsVector templateTags) + : QSyntaxHighlighter(edit), tags(templateTags) +{ +} + +/*! + Formats a paragraph contained in \a text, highlighting all tags. + \a endStateOfLastPara is ignored. +*/ + +int TemplateEditHighlighter::highlightParagraph(const QString & text, int /*endStateOfLastPara*/) +{ + setFormat(0, text.length(), textEdit()->colorGroup().text()); + + for ( int ver = 0; ver <= 1; ++ver ) { + + // every stick has two ends: beginning and ending + // every tag has two versions: with and without '!' + const QString tagStart = (ver)? "<" : ""; + const int len = tag.length(); + + while ( (start = text.find(tag, first, false)) != -1 ) { + setFormat(start, len, textEdit()->colorGroup().link()); + // color of a link - it suggests something 'special' ;-) + // (and has good contrast) + + first = start + len + 1; + } + } + } + + return 0; +} + +//---------------------------------------------------------------------------- +// Template +//---------------------------------------------------------------------------- + +/*! + \class Template templates.h + \brief The Template is an extension of QString which makes working with templates easier. + + Template is a specialised QString representing a template. + + A template is a string with special parts (template items) written inside <> brackets. + Items may be filled by providing a list of values in the Template::ExpandData object + to expand() method. + + \code + + Template t = "Hello ! You just won ?"; + Template::ExpandData data; + data["name"] = "John"; + data["item"] = "a pen"; + QString s = t.expand(data); // s is now "Hello John! You just won ?"; + + \endcode + + In addition, every template has a corresponding version. + If information provided for such item is a not-empty string, it will be prepended by new line character. + + \code + + Template t = "<subtitle>"; + + Template::ExpandData book1; + book1["title"] = "Blue dot"; + book1["subtitle"] = ""; + + QString title1 = t.expand(book1); // title1 is now "Blue dot"; + + Template::ExpandData book2; + book2["title"] = "The God Particle"; + book2["subtitle"] = "If the Universe Is the Answer, What Is the Question?"; + + QString title2 = t.expand(book2); // title2 is now "The God Particle\nIf the Universe Is the Answer, What Is the Question?"; + + \endcode +*/ + + +/*! + \function Template() + + Constructs a new empty template. +*/ + +/*! + \function Template(const QString &s) + + Constructs a new template basing on \a s string. +*/ + +/*! + \function Template(const Template &t) + + Constructs a new template basing on \a t template. +*/ + +/*! + \function Template(const char *str) + + Constructs a new template basing on \a str string. +*/ + + +/*! + Expands a template using \a values data. + + If \a values does not contain a value for a template item, the item is left unchanged + in the output. + Otherwise, "<item>" is replaced by a corresponding value + and "<!item>" is either replaced by the value prepended with '\n' or with empty string if + the value is empty. + + ExpandData type is defined as: + typedef QMap<QString, QString> ExpandData; + + Note that if there was no value provided for an item, it is left unchanged. + The return type of this method is Template, so it may be easily expanded further + with another \a values. +*/ + +Template Template::expand(const Template::ExpandData &values) const +{ + Template res = *this; + + QRegExp repl; + repl.setCaseSensitive(FALSE); + + QString ins; + + for ( ExpandData::ConstIterator it = values.begin(); it != values.end(); ++it ) { + + ins = it.data(); + repl.setPattern("<" + it.key() + ">"); + res.replace(repl, ins); + + // every tag has <!tag> version, which adds new line before the value + + if( !ins.isEmpty() ) { + repl.setPattern("<!" + it.key() + ">"); + res.replace(repl, QString("\n") + ins); + } + } + + // "<>" is a safe way to write "<" inside the template + + ins = "<"; + repl.setPattern("<>"); + res.replace(repl, ins); + + return res; +} + + +#include "moc_templates.cpp" diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/templates/templates.h psi/psi/src/tools/templates/templates.h --- psi_cvs-2005.05.17/psi/src/tools/templates/templates.h Thu Jan 1 01:00:00 1970 +++ psi/psi/src/tools/templates/templates.h Tue May 17 20:54:20 2005 @@ -0,0 +1,86 @@ +/* + * templates.h - set of utils to make editing templates easier + * Copyright (C) 2005 Maciej Niedzielski + * + * 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef TEMPLATES_UTILS_H +#define TEMPLATES_UTILS_H + +#include <qpopupmenu.h> +#include <qsyntaxhighlighter.h> +#include <qvaluevector.h> +#include <qmap.h> + +class QTextEdit; + +//---------------------------------------------------------------------------- +// TemplatePopup +//---------------------------------------------------------------------------- + +// popup menu containing template tags + +class TemplatePopup : public QPopupMenu { + Q_OBJECT +public: + TemplatePopup(QTextEdit *edt, QWidget * parent = 0, const char * name = 0); + ~TemplatePopup(); + + int insertTemplateItem(const QString &name, const QString &tag, const QString &desc=""); +private: + class Private; + Private *d; +private slots: + void onActivated(int id); +}; + +//---------------------------------------------------------------------------- +// TemplateEditHighlighter +//---------------------------------------------------------------------------- + +// text highlighter highlighting template tags + +class TemplateEditHighlighter : public QSyntaxHighlighter { +public: + + typedef QValueVector<QString> TagsVector; + + TemplateEditHighlighter(QTextEdit *edt, TagsVector templateTags); + int highlightParagraph(const QString & text, int endStateOfLastPara); +private: + TagsVector tags; +}; + +//---------------------------------------------------------------------------- +// Template +//---------------------------------------------------------------------------- + +class Template : public QString +{ +public: + Template() : QString() {} + Template(const QString &s) : QString(s) {} + Template(const Template &t) : QString(t) {} + Template(const char *str) : QString(str) {} + + typedef QMap<QString, QString> ExpandData; + + Template expand(const ExpandData &values) const; +}; + + +#endif diff -X exclude -Naru psi_cvs-2005.05.17/psi/src/tools/templates/templates.pri psi/psi/src/tools/templates/templates.pri --- psi_cvs-2005.05.17/psi/src/tools/templates/templates.pri Thu Jan 1 01:00:00 1970 +++ psi/psi/src/tools/templates/templates.pri Tue May 17 21:57:30 2005 @@ -0,0 +1,4 @@ +templates { + HEADERS += $$TEMPLATES_CPP/templates.h + SOURCES += $$TEMPLATES_CPP/templates.cpp +}