From 7661f4486d45301da16c9d982e221b587ce97e68 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Sat, 4 Jun 2011 00:46:02 +0000 Subject: [PATCH] Redesigned the MessagesDialog to open the message in a new tab or new window for reading. The MessageComposer is now only for writing a new message or editing a message from the draft box. Added a new setting to the MessagePage. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4230 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- retroshare-gui/src/RetroShare.pro | 6 + retroshare-gui/src/gui/MessagesDialog.cpp | 828 ++++++------------ retroshare-gui/src/gui/MessagesDialog.h | 54 +- retroshare-gui/src/gui/MessagesDialog.ui | 465 +--------- retroshare-gui/src/gui/msgs/MessageWidget.cpp | 651 ++++++++++++++ retroshare-gui/src/gui/msgs/MessageWidget.h | 93 ++ retroshare-gui/src/gui/msgs/MessageWidget.ui | 502 +++++++++++ retroshare-gui/src/gui/msgs/MessageWindow.cpp | 229 +++++ retroshare-gui/src/gui/msgs/MessageWindow.h | 64 ++ retroshare-gui/src/gui/msgs/MessageWindow.ui | 400 +++++++++ .../src/gui/settings/MessagePage.cpp | 5 + .../src/gui/settings/MessagePage.ui | 16 +- .../src/gui/settings/rsharesettings.cpp | 26 + .../src/gui/settings/rsharesettings.h | 9 + retroshare-gui/src/lang/retroshare_de.qm | Bin 330549 -> 333506 bytes retroshare-gui/src/lang/retroshare_de.ts | 563 +++++++++--- 16 files changed, 2740 insertions(+), 1171 deletions(-) create mode 100644 retroshare-gui/src/gui/msgs/MessageWidget.cpp create mode 100644 retroshare-gui/src/gui/msgs/MessageWidget.h create mode 100644 retroshare-gui/src/gui/msgs/MessageWidget.ui create mode 100644 retroshare-gui/src/gui/msgs/MessageWindow.cpp create mode 100644 retroshare-gui/src/gui/msgs/MessageWindow.h create mode 100644 retroshare-gui/src/gui/msgs/MessageWindow.ui diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index 5329aaa3f..b244634c9 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -270,6 +270,8 @@ HEADERS += rshare.h \ gui/channels/ShareKey.h \ gui/connect/ConfCertDialog.h \ gui/msgs/MessageComposer.h \ + gui/msgs/MessageWindow.h \ + gui/msgs/MessageWidget.h \ gui/msgs/TagsMenu.h \ gui/msgs/textformat.h \ gui/images/retroshare_win.rc.h \ @@ -384,6 +386,8 @@ FORMS += gui/StartDialog.ui \ gui/chat/PopupChatDialog.ui \ gui/connect/ConfCertDialog.ui \ gui/msgs/MessageComposer.ui \ + gui/msgs/MessageWindow.ui\ + gui/msgs/MessageWidget.ui\ gui/settings/settings.ui \ gui/settings/GeneralPage.ui \ gui/settings/DirectoriesPage.ui \ @@ -503,6 +507,8 @@ SOURCES += main.cpp \ gui/chat/ChatStyle.cpp \ gui/connect/ConfCertDialog.cpp \ gui/msgs/MessageComposer.cpp \ + gui/msgs/MessageWidget.cpp \ + gui/msgs/MessageWindow.cpp \ gui/msgs/TagsMenu.cpp \ gui/common/vmessagebox.cpp \ gui/common/rwindow.cpp \ diff --git a/retroshare-gui/src/gui/MessagesDialog.cpp b/retroshare-gui/src/gui/MessagesDialog.cpp index 28e528b60..f80ae0836 100644 --- a/retroshare-gui/src/gui/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/MessagesDialog.cpp @@ -19,33 +19,22 @@ * Boston, MA 02110-1301, USA. ****************************************************************/ -#include #include #include #include #include -#include -#include -#include -#include #include -#include #include "MessagesDialog.h" #include "msgs/MessageComposer.h" +#include "msgs/MessageWidget.h" #include "msgs/TagsMenu.h" -#include "util/printpreview.h" #include "settings/rsharesettings.h" -#include "util/misc.h" #include "common/TagDefs.h" #include "common/PeerDefs.h" #include "common/RSItemDelegate.h" -#include "common/Emoticons.h" -#include "RetroShareLink.h" -#include #include -#include #include #include @@ -56,8 +45,6 @@ #define IMAGE_MESSAGEREPLYALL ":/images/mail_replyall.png" #define IMAGE_MESSAGEFORWARD ":/images/mail_forward.png" #define IMAGE_MESSAGEREMOVE ":/images/message-mail-imapdelete.png" -#define IMAGE_DOWNLOAD ":/images/start.png" -#define IMAGE_DOWNLOADALL ":/images/startall.png" #define IMAGE_STAR_ON ":/images/star-on-16.png" #define IMAGE_STAR_OFF ":/images/star-off-16.png" @@ -79,11 +66,6 @@ #define ROLE_UNREAD Qt::UserRole + 3 #define ROLE_MSGFLAGS Qt::UserRole + 4 -#define COLUMN_FILE_NAME 0 -#define COLUMN_FILE_SIZE 1 -#define COLUMN_FILE_HASH 2 -#define COLUMN_FILE_COUNT 3 - #define ROW_INBOX 0 #define ROW_OUTBOX 1 #define ROW_DRAFTBOX 2 @@ -165,44 +147,36 @@ MessagesDialog::MessagesDialog(QWidget *parent) m_bInChange = false; m_nLockUpdate = 0; - connect( ui.messagestreeView, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( messageslistWidgetCostumPopupMenu( QPoint ) ) ); - connect( ui.msgList, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( msgfilelistWidgetCostumPopupMenu( QPoint ) ) ); - connect( ui.listWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( folderlistWidgetCostumPopupMenu( QPoint ) ) ); - connect( ui.messagestreeView, SIGNAL(clicked ( const QModelIndex &) ) , this, SLOT( clicked( const QModelIndex & ) ) ); - connect( ui.messagestreeView, SIGNAL(doubleClicked ( const QModelIndex& ) ) , this, SLOT( doubleClicked( const QModelIndex & ) ) ); - connect( ui.listWidget, SIGNAL( currentRowChanged ( int) ), this, SLOT( changeBox ( int) ) ); - connect( ui.tagWidget, SIGNAL( currentRowChanged ( int) ), this, SLOT( changeTag ( int) ) ); - + connect(ui.messagestreeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(messageslistWidgetCostumPopupMenu(QPoint))); + connect(ui.listWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(folderlistWidgetCostumPopupMenu(QPoint))); + connect(ui.messagestreeView, SIGNAL(clicked(const QModelIndex&)) , this, SLOT(clicked(const QModelIndex&))); + connect(ui.messagestreeView, SIGNAL(doubleClicked(const QModelIndex&)) , this, SLOT(doubleClicked(const QModelIndex&))); + connect(ui.listWidget, SIGNAL(currentRowChanged(int)), this, SLOT(changeBox(int))); + connect(ui.tagWidget, SIGNAL(currentRowChanged(int)), this, SLOT(changeTag(int))); + connect(ui.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int))); + connect(ui.tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int))); connect(ui.newmessageButton, SIGNAL(clicked()), this, SLOT(newmessage())); - connect(ui.removemessageButton, SIGNAL(clicked()), this, SLOT(removemessage())); - connect(ui.replymessageButton, SIGNAL(clicked()), this, SLOT(replytomessage())); - connect(ui.replyallmessageButton, SIGNAL(clicked()), this, SLOT(replyallmessage())); - connect(ui.forwardmessageButton, SIGNAL(clicked()), this, SLOT(forwardmessage())); - connect(ui.actionPrint, SIGNAL(triggered()), this, SLOT(print())); - ui.actionPrint->setDisabled(true); - connect(ui.actionPrintPreview, SIGNAL(triggered()), this, SLOT(printpreview())); - ui.actionPrintPreview->setDisabled(true); - connect(ui.printbutton, SIGNAL(clicked()), this, SLOT(print())); + connect(ui.actionTextBesideIcon, SIGNAL(triggered()), this, SLOT(buttonStyle())); + connect(ui.actionIconOnly, SIGNAL(triggered()), this, SLOT(buttonStyle())); + connect(ui.actionTextUnderIcon, SIGNAL(triggered()), this, SLOT(buttonStyle())); - connect(ui.expandFilesButton, SIGNAL(clicked()), this, SLOT(togglefileview())); - connect(ui.downloadButton, SIGNAL(clicked()), this, SLOT(getallrecommended())); + ui.actionTextBesideIcon->setData(Qt::ToolButtonTextBesideIcon); + ui.actionIconOnly->setData(Qt::ToolButtonIconOnly); + ui.actionTextUnderIcon->setData(Qt::ToolButtonTextUnderIcon); - connect(ui.actionTextBesideIcon, SIGNAL(triggered()), this, SLOT(buttonstextbesideicon())); - connect(ui.actionIconOnly, SIGNAL(triggered()), this, SLOT(buttonsicononly())); - connect(ui.actionTextUnderIcon, SIGNAL(triggered()), this, SLOT(buttonstextundericon())); - - connect(ui.actionSave_as, SIGNAL(triggered()), this, SLOT(fileSaveAs())); - ui.actionSave_as->setDisabled(true); - - connect( ui.clearButton, SIGNAL(clicked()), this, SLOT(clearFilter())); - connect( ui.filterPatternLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterRegExpChanged())); + connect(ui.clearButton, SIGNAL(clicked()), this, SLOT(clearFilter())); + connect(ui.filterPatternLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(filterRegExpChanged())); connect(ui.filterColumnComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterColumnChanged())); + msgWidget = new MessageWidget(true, this); + ui.msgLayout->addWidget(msgWidget); + + connectActions(); + m_eListMode = LIST_NOTHING; - mCurrCertId = ""; mCurrMsgId = ""; // Set the QStandardItemModel @@ -231,6 +205,7 @@ MessagesDialog::MessagesDialog(QWidget *parent) proxyModel->sort (COLUMN_DATE, Qt::DescendingOrder); ui.messagestreeView->setModel(proxyModel); ui.messagestreeView->setSelectionBehavior(QTreeView::SelectRows); + connect(ui.messagestreeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(updateInterface())); RSItemDelegate *itemDelegate = new RSItemDelegate(this); itemDelegate->removeFocusRect(COLUMN_UNREAD); @@ -252,10 +227,6 @@ MessagesDialog::MessagesDialog(QWidget *parent) Shortcut = new QShortcut(QKeySequence (Qt::SHIFT | Qt::Key_Delete), ui.messagestreeView, 0, 0, Qt::WidgetShortcut); connect(Shortcut, SIGNAL(activated()), this, SLOT( removemessage ())); - /* hide the Tree +/- */ - ui.msgList->setRootIsDecorated( false ); - ui.msgList->setSelectionMode( QAbstractItemView::ExtendedSelection ); - /* Set header initial section sizes */ QHeaderView * msgwheader = ui.messagestreeView->header () ; msgwheader->resizeSection (COLUMN_ATTACHEMENTS, 24); @@ -268,16 +239,6 @@ MessagesDialog::MessagesDialog(QWidget *parent) msgwheader->setResizeMode (COLUMN_STAR, QHeaderView::Fixed); msgwheader->resizeSection (COLUMN_STAR, 24); - /* Set header resize modes and initial section sizes */ - QHeaderView * msglheader = ui.msgList->header () ; - msglheader->setResizeMode (COLUMN_FILE_NAME, QHeaderView::Interactive); - msglheader->setResizeMode (COLUMN_FILE_SIZE, QHeaderView::Interactive); - msglheader->setResizeMode (COLUMN_FILE_HASH, QHeaderView::Interactive); - - msglheader->resizeSection (COLUMN_FILE_NAME, 200); - msglheader->resizeSection (COLUMN_FILE_SIZE, 100); - msglheader->resizeSection (COLUMN_FILE_HASH, 200); - ui.forwardmessageButton->setToolTip(tr("Forward selected Message")); ui.replyallmessageButton->setToolTip(tr("Reply to All")); @@ -292,11 +253,6 @@ MessagesDialog::MessagesDialog(QWidget *parent) //viewmenu->addAction(ui.actionTextUnderIcon); ui.viewtoolButton->setMenu(viewmenu); - loadToolButtonsettings(); - - mFont = QFont("Arial", 10, QFont::Bold); - ui.subjectText->setFont(mFont); - ui.filterPatternLineEdit->setMinimumWidth(20); //setting default filter by column as subject @@ -304,11 +260,6 @@ MessagesDialog::MessagesDialog(QWidget *parent) ui.clearButton->hide(); - ui.bcclabel->setVisible(false); - ui.bccText->setVisible(false); - ui.cclabel->setVisible(false); - ui.ccText->setVisible(false); - // load settings processSettings(true); @@ -343,6 +294,13 @@ MessagesDialog::MessagesDialog(QWidget *parent) ui.messagestreeView->installEventFilter(this); + // remove close button of the the first tab + QTabBar::ButtonPosition buttonPosition = (QTabBar::ButtonPosition) ui.tabWidget->tabBar()->style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, 0); + QWidget *tabButton = ui.tabWidget->tabBar()->tabButton(0, buttonPosition); + if (tabButton) { + tabButton->hide(); + } + /* Hide platform specific features */ #ifdef Q_WS_WIN @@ -359,7 +317,7 @@ MessagesDialog::~MessagesDialog() processSettings(false); } -void MessagesDialog::processSettings(bool bLoad) +void MessagesDialog::processSettings(bool load) { int messageTreeVersion = 2; // version number for the settings to solve problems when modifying the column count @@ -367,17 +325,11 @@ void MessagesDialog::processSettings(bool bLoad) QHeaderView *msgwheader = ui.messagestreeView->header () ; - Settings->beginGroup(QString("MessageDialog")); + Settings->beginGroup("MessageDialog"); - if (bLoad) { + if (load) { // load settings - // expandFiles - bool bValue = Settings->value("expandFiles", true).toBool(); - ui.expandFilesButton->setChecked(bValue); - ui.msgList->setVisible(bValue); - togglefileview_internal(); - // filterColumn int nValue = FilterColumnToComboBox(Settings->value("filterColumn", true).toInt()); ui.filterColumnComboBox->setCurrentIndex(nValue); @@ -388,13 +340,17 @@ void MessagesDialog::processSettings(bool bLoad) } // state of tag list - bValue = Settings->value("tagList", true).toBool(); - ui.Tags_Button->setChecked(bValue); + bool value = Settings->value("tagList", true).toBool(); + ui.Tags_Button->setChecked(value); // state of splitter ui.msgSplitter->restoreState(Settings->value("Splitter").toByteArray()); ui.msgSplitter_2->restoreState(Settings->value("Splitter2").toByteArray()); ui.listSplitter->restoreState(Settings->value("Splitter3").toByteArray()); + + /* toolbar button style */ + Qt::ToolButtonStyle style = (Qt::ToolButtonStyle) Settings->value("ToolButon_Stlye", Qt::ToolButtonIconOnly).toInt(); + setToolbarButtonStyle(style); } else { // save settings @@ -409,10 +365,17 @@ void MessagesDialog::processSettings(bool bLoad) Settings->setValue("Splitter", ui.msgSplitter->saveState()); Settings->setValue("Splitter2", ui.msgSplitter_2->saveState()); Settings->setValue("Splitter3", ui.listSplitter->saveState()); + + /* toolbar button style */ + Settings->setValue("ToolButon_Stlye", ui.newmessageButton->toolButtonStyle()); } Settings->endGroup(); + if (msgWidget) { + msgWidget->processSettings("MessageDialog", load); + } + m_bProcessSettings = false; } @@ -543,7 +506,13 @@ bool MessagesDialog::hasMessageStar(int nRow) void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint point ) { - QMenu contextMnu( this ); + std::string cid; + std::string mid; + + MessageInfo msgInfo; + if (getCurrentMsg(cid, mid)) { + rsMsgs->getMessage(mid, msgInfo); + } QList RowsRead; QList RowsUnread; @@ -552,7 +521,21 @@ void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint point ) /** Defines the actions for the context menu */ - QAction *action = contextMnu.addAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply to Message"), this, SLOT(replytomessage())); + QMenu contextMnu( this ); + + QAction *action = contextMnu.addAction(tr("Open in a new window"), this, SLOT(openAsWindow())); + if (nCount != 1) { + action->setDisabled(true); + } + + action = contextMnu.addAction(tr("Open in a new tab"), this, SLOT(openAsTab())); + if (nCount != 1) { + action->setDisabled(true); + } + + contextMnu.addSeparator(); + + action = contextMnu.addAction(QIcon(IMAGE_MESSAGEREPLY), tr("Reply to Message"), this, SLOT(replytomessage())); if (nCount != 1) { action->setDisabled(true); } @@ -565,11 +548,6 @@ void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint point ) action->setDisabled(true); } - action = contextMnu.addAction(tr("Edit..."), this, SLOT(editmessage())); - if (nCount != 1) { - action->setDisabled(true); - } - contextMnu.addSeparator(); action = contextMnu.addAction(QIcon(":/images/message-mail-read.png"), tr("Mark as read"), this, SLOT(markAsRead())); @@ -591,8 +569,20 @@ void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint point ) // add tags contextMnu.addMenu(ui.tagButton->menu()); + contextMnu.addSeparator(); + QString text; + if ((msgInfo.msgflags & RS_MSG_BOXMASK) == RS_MSG_DRAFTBOX) { + text = tr("Edit"); + } else { + text = tr("Edit as new"); + } + action = contextMnu.addAction(text, this, SLOT(editmessage())); + if (nCount != 1) { + action->setDisabled(true); + } + action = contextMnu.addAction(QIcon(IMAGE_MESSAGEREMOVE), (nCount > 1) ? tr("Remove Messages") : tr("Remove Message"), this, SLOT(removemessage())); if (nCount == 0) { action->setDisabled(true); @@ -606,7 +596,7 @@ void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint point ) } } - contextMnu.addAction(ui.actionSave_as); + contextMnu.addAction(ui.actionSaveAs); contextMnu.addAction(ui.actionPrintPreview); contextMnu.addAction(ui.actionPrint); contextMnu.addSeparator(); @@ -616,22 +606,6 @@ void MessagesDialog::messageslistWidgetCostumPopupMenu( QPoint point ) contextMnu.exec(QCursor::pos()); } - -void MessagesDialog::msgfilelistWidgetCostumPopupMenu( QPoint point ) -{ - QMenu contextMnu( this ); - - QAction* getRecAct = new QAction(QIcon(IMAGE_DOWNLOAD), tr( "Download" ), &contextMnu ); - connect( getRecAct , SIGNAL( triggered() ), this, SLOT( getcurrentrecommended() ) ); - -// QAction* getAllRecAct = new QAction(QIcon(IMAGE_DOWNLOADALL), tr( "Download" ), &contextMnu ); -// connect( getAllRecAct , SIGNAL( triggered() ), this, SLOT( getallrecommended() ) ); - - contextMnu.addAction( getRecAct); -// contextMnu.addAction( getAllRecAct); - contextMnu.exec(QCursor::pos()); -} - void MessagesDialog::folderlistWidgetCostumPopupMenu(QPoint point) { if (ui.listWidget->currentRow() != ROW_TRASHBOX) { @@ -653,11 +627,45 @@ void MessagesDialog::newmessage() return; } - /* fill it in */ - //std::cerr << "MessagesDialog::newmessage()" << std::endl; nMsgDialog->show(); nMsgDialog->activateWindow(); + /* window will destroy itself! */ +} + +void MessagesDialog::openAsWindow() +{ + std::string cid; + std::string mid; + + if(!getCurrentMsg(cid, mid)) + return ; + + MessageWidget *msgWidget = MessageWidget::openMsg(mid, true); + if (msgWidget == NULL) { + return; + } + + msgWidget->activateWindow(); + + /* window will destroy itself! */ +} + +void MessagesDialog::openAsTab() +{ + std::string cid; + std::string mid; + + if(!getCurrentMsg(cid, mid)) + return ; + + MessageWidget *msgWidget = MessageWidget::openMsg(mid, false); + if (msgWidget == NULL) { + return; + } + + ui.tabWidget->addTab(msgWidget, msgWidget->subject(true)); + ui.tabWidget->setCurrentWidget(msgWidget); /* window will destroy itself! */ } @@ -670,182 +678,17 @@ void MessagesDialog::editmessage() if(!getCurrentMsg(cid, mid)) return ; - MessageComposer *pMsgDialog = MessageComposer::newMsg(mid); - if (pMsgDialog == NULL) { + MessageComposer *msgComposer = MessageComposer::newMsg(mid); + if (msgComposer == NULL) { return; } - pMsgDialog->show(); - pMsgDialog->activateWindow(); + msgComposer->show(); + msgComposer->activateWindow(); /* window will destroy itself! */ } -void MessagesDialog::replytomessage() -{ - /* put msg on msgBoard, and switch to it. */ - - std::string cid; - std::string mid; - - if(!getCurrentMsg(cid, mid)) - return ; - - mCurrCertId = cid; - mCurrMsgId = mid; - - MessageComposer *nMsgDialog = MessageComposer::replyMsg(mid, false); - if (nMsgDialog == NULL) { - return; - } - - nMsgDialog->show(); - nMsgDialog->activateWindow(); - - /* window will destroy itself! */ -} - -void MessagesDialog::replyallmessage() -{ - /* put msg on msgBoard, and switch to it. */ - - std::string cid; - std::string mid; - - if(!getCurrentMsg(cid, mid)) - return ; - - mCurrCertId = cid; - mCurrMsgId = mid; - - MessageComposer *nMsgDialog = MessageComposer::replyMsg(mid, true); - if (nMsgDialog == NULL) { - return; - } - - nMsgDialog->show(); - nMsgDialog->activateWindow(); - - /* window will destroy itself! */ -} - -void MessagesDialog::forwardmessage() -{ - /* put msg on msgBoard, and switch to it. */ - - std::string cid; - std::string mid; - - if(!getCurrentMsg(cid, mid)) - return ; - - mCurrCertId = cid; - mCurrMsgId = mid; - - MessageComposer *nMsgDialog = MessageComposer::forwardMsg(mid); - if (nMsgDialog == NULL) { - return; - } - - nMsgDialog->show(); - nMsgDialog->activateWindow(); - - /* window will destroy itself! */ -} - -void MessagesDialog::togglefileview_internal() -{ - /* if msg header visible -> change icon and tooltip - * three widgets... - */ - - if (ui.expandFilesButton->isChecked()) { - ui.expandFilesButton->setIcon(QIcon(QString(":/images/edit_remove24.png"))); - ui.expandFilesButton->setToolTip(tr("Hide")); - } else { - ui.expandFilesButton->setIcon(QIcon(QString(":/images/edit_add24.png"))); - ui.expandFilesButton->setToolTip(tr("Expand")); - } -} - -void MessagesDialog::togglefileview() -{ - // save state of files view - Settings->setValueToGroup("MessageDialog", "expandFiles", ui.expandFilesButton->isChecked()); - - togglefileview_internal(); -} - - -/* download the recommendations... */ -void MessagesDialog::getcurrentrecommended() -{ - MessageInfo msgInfo; - if (!rsMsgs -> getMessage(mCurrMsgId, msgInfo)) - return; - - std::list srcIds; - srcIds.push_back(msgInfo.srcId); - - QModelIndexList list = ui.msgList->selectionModel()->selectedIndexes(); - - std::map files ; - - for(QModelIndexList::const_iterator it(list.begin());it!=list.end();++it) - { - FileInfo& f(files[it->row()]) ; - - switch(it->column()) - { - case COLUMN_FILE_NAME: - f.fname = it->data().toString().toStdString() ; - break ; - case COLUMN_FILE_SIZE: - f.size = it->data().toULongLong() ; - break ; - case COLUMN_FILE_HASH: - f.hash = it->data().toString().toStdString() ; - break ; - } - } - - for(std::map::const_iterator it(files.begin());it!=files.end();++it) - { - const FileInfo& f(it->second) ; - std::cout << "Requesting file " << f.fname << ", size=" << f.size << ", hash=" << f.hash << std::endl ; - - if(! rsFiles->FileRequest(it->second.fname,it->second.hash,it->second.size, "", RS_FILE_HINTS_NETWORK_WIDE, srcIds)) - { - QMessageBox mb(QObject::tr("File Request canceled"), QObject::tr("The following has not been added to your download list, because you already have it:\n ")+QString::fromStdString(it->second.fname),QMessageBox::Critical,QMessageBox::Ok,0,0); - mb.setWindowIcon(QIcon(QString::fromUtf8(":/images/rstray3.png"))); - mb.exec(); - } - } -} - -void MessagesDialog::getallrecommended() -{ - /* get Message */ - MessageInfo msgInfo; - if (!rsMsgs -> getMessage(mCurrMsgId, msgInfo)) - { - return; - } - - const std::list &recList = msgInfo.files; - std::list::const_iterator it; - - /* do the requests */ - for(it = recList.begin(); it != recList.end(); it++) - { - std::cerr << "MessagesDialog::getallrecommended() Calling File Request"; - std::cerr << std::endl; - std::list srcIds; - srcIds.push_back(msgInfo.srcId); - rsFiles->FileRequest(it->fname, it->hash, it->size, "", RS_FILE_HINTS_NETWORK_WIDE, srcIds); - } -} - void MessagesDialog::changeBox(int) { if (m_bInChange) { @@ -894,8 +737,6 @@ void MessagesDialog::messagesTagsChanged() fillTags(); insertMessages(); - - showTagLabels(); } static void InitIconAndFont(QStandardItem *item[COLUMN_COUNT]) @@ -965,7 +806,6 @@ void MessagesDialog::insertMessages() } std::cerr <<"MessagesDialog::insertMessages called"; - fflush(0); std::list msgList; std::list::const_iterator it; @@ -976,7 +816,6 @@ void MessagesDialog::insertMessages() rsMsgs -> getMessageSummaries(msgList); std::cerr << "MessagesDialog::insertMessages()" << std::endl; - fflush(0); int nFilterColumn = FilterColumnFromComboBox(ui.filterColumnComboBox->currentIndex()); @@ -1284,9 +1123,7 @@ void MessagesDialog::insertMessages() // No of Files. { - std::ostringstream out; - out << it -> count; - item[COLUMN_ATTACHEMENTS] -> setText(QString::fromStdString(out.str())); + item[COLUMN_ATTACHEMENTS] -> setText(QString::number(it -> count)); item[COLUMN_ATTACHEMENTS] -> setData(item[COLUMN_ATTACHEMENTS]->text() + dateString, ROLE_SORT); item[COLUMN_ATTACHEMENTS] -> setTextAlignment(Qt::AlignHCenter); } @@ -1378,8 +1215,31 @@ void MessagesDialog::doubleClicked(const QModelIndex &index) /* activate row */ clicked (index); + std::string cid; + std::string mid; + + if(!getCurrentMsg(cid, mid)) + return ; + + MessageInfo msgInfo; + if (!rsMsgs->getMessage(mid, msgInfo)) { + return; + } + + if ((msgInfo.msgflags & RS_MSG_BOXMASK) == RS_MSG_DRAFTBOX) { + editmessage(); + return; + } + /* edit message */ - editmessage(); + switch (Settings->getMsgOpen()) { + case RshareSettings::MSG_OPEN_TAB: + openAsTab(); + break; + case RshareSettings::MSG_OPEN_WINDOW: + openAsWindow(); + break; + } } // show current message directly @@ -1479,55 +1339,6 @@ void MessagesDialog::setMsgStar(const QList &Rows, bool star) // LockUpdate } -void MessagesDialog::clearTagLabels() -{ - /* clear all tags */ - while (tagLabels.size()) { - delete tagLabels.front(); - tagLabels.pop_front(); - } - while (ui.taglayout->count()) { - delete ui.taglayout->takeAt(0); - } - - ui.tagslabel->setVisible(false); -} - -void MessagesDialog::showTagLabels() -{ - clearTagLabels(); - - if (mCurrMsgId.empty()) { - return; - } - - MsgTagInfo tagInfo; - rsMsgs->getMessageTag(mCurrMsgId, tagInfo); - - if (tagInfo.tagIds.empty() == false) { - ui.tagslabel->setVisible(true); - - MsgTagType Tags; - rsMsgs->getMessageTagTypes(Tags); - - std::map >::iterator Tag; - for (std::list::iterator tagId = tagInfo.tagIds.begin(); tagId != tagInfo.tagIds.end(); tagId++) { - Tag = Tags.types.find(*tagId); - if (Tag != Tags.types.end()) { - QLabel *tagLabel = new QLabel(TagDefs::name(Tag->first, Tag->second.first), this); - tagLabel->setMaximumHeight(16); - tagLabel->setStyleSheet(TagDefs::labelStyleSheet(Tag->second.second)); - tagLabels.push_back(tagLabel); - ui.taglayout->addWidget(tagLabel); - ui.taglayout->addSpacing(3); - } - } - ui.taglayout->addStretch(); - } else { - ui.tagslabel->setVisible(false); - } -} - void MessagesDialog::insertMsgTxtAndFiles(QModelIndex Index, bool bSetToRead) { std::cerr << "MessagesDialog::insertMsgTxtAndFiles()" << std::endl; @@ -1537,52 +1348,29 @@ void MessagesDialog::insertMsgTxtAndFiles(QModelIndex Index, bool bSetToRead) std::string mid; QModelIndex currentIndex = proxyModel->mapToSource(Index); - if (currentIndex.isValid() == false) - { - mCurrCertId.clear(); + if (currentIndex.isValid() == false) { mCurrMsgId.clear(); - - /* blank it */ - ui.dateText-> setText(""); - ui.toText->setText(""); - ui.fromText->setText(""); - ui.filesText->setText(""); - - ui.cclabel->setVisible(false); - ui.ccText->setVisible(false); - ui.ccText->clear(); - - ui.bcclabel->setVisible(false); - ui.bccText->setVisible(false); - ui.bccText->clear(); - - ui.subjectText->setText(""); - ui.msgList->clear(); - ui.msgText->clear(); - - ui.actionSave_as->setDisabled(true); - ui.actionPrintPreview->setDisabled(true); - ui.actionPrint->setDisabled(true); - - clearTagLabels(); - + msgWidget->fill(mCurrMsgId); + updateInterface(); return; } QStandardItem *item = MessagesModel->item(currentIndex.row(),COLUMN_DATA); if (item == NULL) { + mCurrMsgId.clear(); + msgWidget->fill(mCurrMsgId); + updateInterface(); return; } - cid = item->data(ROLE_SRCID).toString().toStdString(); mid = item->data(ROLE_MSGID).toString().toStdString(); int nCount = getSelectedMsgCount (NULL, NULL, NULL, NULL); if (nCount == 1) { - ui.actionSave_as->setEnabled(true); + ui.actionSaveAs->setEnabled(true); ui.actionPrintPreview->setEnabled(true); ui.actionPrint->setEnabled(true); } else { - ui.actionSave_as->setDisabled(true); + ui.actionSaveAs->setDisabled(true); ui.actionPrintPreview->setDisabled(true); ui.actionPrint->setDisabled(true); } @@ -1592,16 +1380,12 @@ void MessagesDialog::insertMsgTxtAndFiles(QModelIndex Index, bool bSetToRead) return; } - clearTagLabels(); - /* Save the Data.... for later */ - mCurrCertId = cid; - mCurrMsgId = mid; + mCurrMsgId = mid; MessageInfo msgInfo; - if (!rsMsgs -> getMessage(mid, msgInfo)) - { + if (!rsMsgs -> getMessage(mid, msgInfo)) { std::cerr << "MessagesDialog::insertMsgTxtAndFiles() Couldn't find Msg" << std::endl; return; } @@ -1628,114 +1412,8 @@ void MessagesDialog::insertMsgTxtAndFiles(QModelIndex Index, bool bSetToRead) } } - const std::list &recList = msgInfo.files; - std::list::const_iterator it; - - /* get a link to the table */ - QTreeWidget *tree = ui.msgList; - - /* get the MessageInfo */ - - tree->clear(); - - QList items; - for(it = recList.begin(); it != recList.end(); it++) - { - /* make a widget per person */ - QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget*)0); - /* (0) Filename */ - item -> setText(COLUMN_FILE_NAME, QString::fromStdString(it->fname)); - //std::cerr << "Msg FileItem(" << it->fname.length() << ") :" << it->fname << std::endl; - - item -> setText(COLUMN_FILE_SIZE, QString::number(it->size)); /* (1) Size */ - item -> setText(COLUMN_FILE_HASH, QString::fromStdString(it->hash)); - - /* add to the list */ - items.append(item); - } - - /* add the items in! */ - tree->insertTopLevelItems(0, items); - - /* iterate through the sources */ - std::list::const_iterator pit; - - RetroShareLink link; - QString text; - - for(pit = msgInfo.msgto.begin(); pit != msgInfo.msgto.end(); pit++) - { - if (link.createMessage(*pit, "")) { - text += link.toHtml() + " "; - } - } - ui.toText->setText(text); - - if (msgInfo.msgcc.size() > 0) { - ui.cclabel->setVisible(true); - ui.ccText->setVisible(true); - - text.clear(); - for(pit = msgInfo.msgcc.begin(); pit != msgInfo.msgcc.end(); pit++) - { - if (link.createMessage(*pit, "")) { - text += link.toHtml() + " "; - } - } - ui.ccText->setText(text); - } else { - ui.cclabel->setVisible(false); - ui.ccText->setVisible(false); - ui.ccText->clear(); - } - - if (msgInfo.msgbcc.size() > 0) { - ui.bcclabel->setVisible(true); - ui.bccText->setVisible(true); - - text.clear(); - for(pit = msgInfo.msgbcc.begin(); pit != msgInfo.msgbcc.end(); pit++) - { - if (link.createMessage(*pit, "")) { - text += link.toHtml() + " "; - } - } - ui.bccText->setText(text); - } else { - ui.bcclabel->setVisible(false); - ui.bccText->setVisible(false); - ui.bccText->clear(); - } - - { - QDateTime qtime; - qtime.setTime_t(msgInfo.ts); - QString timestamp = qtime.toString("dd.MM.yyyy hh:mm:ss"); - ui.dateText-> setText(timestamp); - } - - std::string srcId; - if ((msgInfo.msgflags & RS_MSG_BOXMASK) == RS_MSG_OUTBOX) { - // outgoing message are from me - srcId = rsPeers->getOwnId(); - } else { - srcId = msgInfo.srcId; - } - link.createMessage(srcId, ""); - - ui.fromText->setText(link.toHtml()); - ui.fromText->setToolTip(PeerDefs::rsidFromId(srcId)); - - ui.subjectText->setText(QString::fromStdWString(msgInfo.title)); - - text = RsHtml::formatText(QString::fromStdWString(msgInfo.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); - ui.msgText->setHtml(text); - - ui.filesText->setText(QString("(%1 %2)").arg(msgInfo.count).arg(msgInfo.count == 1 ? tr("File") : tr("Files"))); - - showTagLabels(); - - std::cerr << "MessagesDialog::insertMsgTxtAndFiles() Msg Displayed OK!" << std::endl; + msgWidget->fill(mCurrMsgId); + updateInterface(); } bool MessagesDialog::getCurrentMsg(std::string &cid, std::string &mid) @@ -1782,8 +1460,7 @@ void MessagesDialog::removemessage() for(QList::iterator it = selectedIndexList.begin(); it != selectedIndexList.end(); it++) { selectedIndex = proxyModel->mapToSource(*it); int row = selectedIndex.row(); - if (rowList.contains(row) == false) - { + if (rowList.contains(row) == false) { rowList.append(row); } } @@ -1802,6 +1479,10 @@ void MessagesDialog::removemessage() QStandardItem *pItem = MessagesModel->item((*it1), COLUMN_DATA); if (pItem) { QString mid = pItem->data(ROLE_MSGID).toString(); + + // close tab showing this message +// closeTab(mid.toStdString()); + if (bDelete) { rsMsgs->MessageDelete(mid.toStdString()); } else { @@ -1827,63 +1508,6 @@ void MessagesDialog::undeletemessage() // LockUpdate -> insertMessages(); } -void MessagesDialog::print() -{ -#ifndef QT_NO_PRINTER - QPrinter printer(QPrinter::HighResolution); - printer.setFullPage(true); - QPrintDialog *dlg = new QPrintDialog(&printer, this); - if (ui.msgText->textCursor().hasSelection()) - dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection); - dlg->setWindowTitle(tr("Print Document")); - if (dlg->exec() == QDialog::Accepted) { - ui.msgText->print(&printer); - } - delete dlg; -#endif -} - -void MessagesDialog::printpreview() -{ - PrintPreview *preview = new PrintPreview(ui.msgText->document(), this); - preview->setWindowModality(Qt::WindowModal); - preview->setAttribute(Qt::WA_DeleteOnClose); - preview->show(); -} - -bool MessagesDialog::fileSave() -{ - if (fileName.isEmpty()) - return fileSaveAs(); - - QFile file(fileName); - if (!file.open(QFile::WriteOnly)) - return false; - QTextStream ts(&file); - ts.setCodec(QTextCodec::codecForName("UTF-8")); - ts << ui.msgText->document()->toHtml("UTF-8"); - ui.msgText->document()->setModified(false); - return true; -} - -bool MessagesDialog::fileSaveAs() -{ - QString fn = QFileDialog::getSaveFileName(this, tr("Save as..."), - QString(), tr("HTML-Files (*.htm *.html);;All Files (*)")); - if (fn.isEmpty()) - return false; - setCurrentFileName(fn); - return fileSave(); -} - -void MessagesDialog::setCurrentFileName(const QString &fileName) -{ - this->fileName = fileName; - ui.msgText->document()->setModified(false); - - setWindowModified(false); -} - void MessagesDialog::setToolbarButtonStyle(Qt::ToolButtonStyle style) { ui.newmessageButton->setToolButtonStyle(style); @@ -1896,31 +1520,9 @@ void MessagesDialog::setToolbarButtonStyle(Qt::ToolButtonStyle style) ui.viewtoolButton->setToolButtonStyle(style); } -void MessagesDialog::buttonsicononly() +void MessagesDialog::buttonStyle() { - setToolbarButtonStyle(Qt::ToolButtonIconOnly); - - Settings->setValueToGroup("MessageDialog", "ToolButon_Stlye", Qt::ToolButtonIconOnly); -} - -void MessagesDialog::buttonstextbesideicon() -{ - setToolbarButtonStyle(Qt::ToolButtonTextBesideIcon); - - Settings->setValueToGroup("MessageDialog", "ToolButon_Stlye", Qt::ToolButtonTextBesideIcon); -} - -void MessagesDialog::buttonstextundericon() -{ - setToolbarButtonStyle(Qt::ToolButtonTextUnderIcon); - - Settings->setValueToGroup("MessageDialog", "ToolButon_Stlye", Qt::ToolButtonTextUnderIcon); -} - -void MessagesDialog::loadToolButtonsettings() -{ - Qt::ToolButtonStyle style = (Qt::ToolButtonStyle) Settings->valueFromGroup("MessageDialog", "ToolButon_Stlye", Qt::ToolButtonIconOnly).toInt(); - setToolbarButtonStyle(style); + setToolbarButtonStyle((Qt::ToolButtonStyle) dynamic_cast(sender())->data().toInt()); } void MessagesDialog::filterRegExpChanged() @@ -2179,8 +1781,6 @@ void MessagesDialog::tagRemoveAll() Lock.setUpdate(true); } - showTagLabels(); - // LockUpdate -> insertMessages(); } @@ -2203,9 +1803,6 @@ void MessagesDialog::tagSet(int tagId, bool set) } } - - showTagLabels(); - // LockUpdate -> insertMessages(); } @@ -2225,3 +1822,98 @@ void MessagesDialog::emptyTrash() // LockUpdate -> insertMessages(); } + +void MessagesDialog::tabChanged(int tab) +{ + connectActions(); + updateInterface(); +} + +void MessagesDialog::tabCloseRequested(int tab) +{ + if (tab == 0) { + return; + } + + QWidget *widget = ui.tabWidget->widget(tab); + + if (widget) { + widget->deleteLater(); + } +} + +void MessagesDialog::closeTab(const std::string &msgId) +{ + QList msgWidgets; + + for (int tab = 1; tab < ui.tabWidget->count(); tab++) { + MessageWidget *msgWidget = dynamic_cast(ui.tabWidget->widget(tab)); + if (msgWidget && msgWidget->msgId() == msgId) { + msgWidgets.append(msgWidget); + } + } + qDeleteAll(msgWidgets); +} + +void MessagesDialog::connectActions() +{ + int tab = ui.tabWidget->currentIndex(); + + MessageWidget *msg; + if (tab == 0) { + msg = msgWidget; + } else { + msg = dynamic_cast(ui.tabWidget->widget(tab)); + } + + ui.replymessageButton->disconnect(); + ui.replyallmessageButton->disconnect(); + ui.forwardmessageButton->disconnect(); + ui.printbutton->disconnect(); + ui.actionPrint->disconnect(); + ui.actionPrintPreview->disconnect(); + ui.actionSaveAs->disconnect(); + ui.removemessageButton->disconnect(); + + if (msg) { + if (tab == 0) { + // connect with own slot to remove multiple messages + connect(ui.removemessageButton, SIGNAL(clicked()), this, SLOT(removemessage())); + } else { + msg->connectAction(MessageWidget::ACTION_REMOVE, ui.removemessageButton); + } + msg->connectAction(MessageWidget::ACTION_REPLY, ui.replymessageButton); + msg->connectAction(MessageWidget::ACTION_REPLY_ALL, ui.replyallmessageButton); + msg->connectAction(MessageWidget::ACTION_FORWARD, ui.forwardmessageButton); + msg->connectAction(MessageWidget::ACTION_PRINT, ui.printbutton); + msg->connectAction(MessageWidget::ACTION_PRINT, ui.actionPrint); + msg->connectAction(MessageWidget::ACTION_PRINT_PREVIEW, ui.actionPrintPreview); + msg->connectAction(MessageWidget::ACTION_SAVE_AS, ui.actionSaveAs); + } +} + +void MessagesDialog::updateInterface() +{ + int count = 0; + + int tab = ui.tabWidget->currentIndex(); + + if (tab == 0) { + count = getSelectedMsgCount(NULL, NULL, NULL, NULL); + } else { + MessageWidget *msg = dynamic_cast(ui.tabWidget->widget(tab)); + if (msg && msg->msgId().empty() == false) { + count = 1; + } + } + + ui.replymessageButton->setEnabled(count == 1); + ui.replyallmessageButton->setEnabled(count == 1); + ui.forwardmessageButton->setEnabled(count == 1); + ui.printbutton->setEnabled(count == 1); + ui.actionPrint->setEnabled(count == 1); + ui.actionPrintPreview->setEnabled(count == 1); + ui.actionSaveAs->setEnabled(count == 1); + ui.removemessageButton->setEnabled(count >= 1); + ui.tagButton->setEnabled(count >= 1); +} diff --git a/retroshare-gui/src/gui/MessagesDialog.h b/retroshare-gui/src/gui/MessagesDialog.h index 2ed6476a3..f3efb46b7 100644 --- a/retroshare-gui/src/gui/MessagesDialog.h +++ b/retroshare-gui/src/gui/MessagesDialog.h @@ -27,6 +27,8 @@ #include "mainpage.h" #include "ui_MessagesDialog.h" +class MessageWidget; + class MessagesDialog : public MainPage { Q_OBJECT @@ -50,7 +52,6 @@ public slots: private slots: /** Create the context popup menu and it's submenus */ void messageslistWidgetCostumPopupMenu( QPoint point ); - void msgfilelistWidgetCostumPopupMenu(QPoint); void folderlistWidgetCostumPopupMenu(QPoint); void changeBox( int newrow ); @@ -61,18 +62,10 @@ private slots: void doubleClicked(const QModelIndex &); void newmessage(); + void openAsWindow(); + void openAsTab(); void editmessage(); - void replytomessage(); - void replyallmessage(); - void forwardmessage(); - - void print(); - void printpreview(); - - bool fileSave(); - bool fileSaveAs(); - void removemessage(); void undeletemessage(); @@ -82,17 +75,7 @@ private slots: void emptyTrash(); - void getcurrentrecommended(); - void getallrecommended(); - - /* handle splitter */ - void togglefileview(); - - void buttonstextbesideicon(); - void buttonsicononly(); - void buttonstextundericon(); - - void loadToolButtonsettings(); + void buttonStyle(); void filterRegExpChanged(); void filterColumnChanged(); @@ -102,6 +85,11 @@ private slots: void tagSet(int tagId, bool set); void tagRemoveAll(); + void tabChanged(int tab); + void tabCloseRequested(int tab); + + void updateInterface(); + private: class LockUpdate { @@ -119,6 +107,8 @@ private: class QStandardItemModel *MessagesModel; QSortFilterProxyModel *proxyModel; + void connectActions(); + void updateMessageSummaryList(); void insertMsgTxtAndFiles(QModelIndex index = QModelIndex(), bool bSetToRead = true); @@ -126,39 +116,31 @@ private: void setMsgAsReadUnread(const QList &Rows, bool read); void setMsgStar(const QList &Rows, bool mark); - void setCurrentFileName(const QString &fileName); - int getSelectedMsgCount (QList *pRows, QList *pRowsRead, QList *pRowsUnread, QList *pRowsStar); bool isMessageRead(int nRow); bool hasMessageStar(int nRow); - /* internal handle splitter */ - void togglefileview_internal(); - - void processSettings(bool bLoad); - - void clearTagLabels(); - void showTagLabels(); + void processSettings(bool load); void setToolbarButtonStyle(Qt::ToolButtonStyle style); void fillTags(); + + void closeTab(const std::string &msgId); + bool m_bProcessSettings; bool m_bInChange; int m_nLockUpdate; // use with LockUpdate enum { LIST_NOTHING, LIST_BOX, LIST_TAG } m_eListMode; - std::string mCurrCertId; std::string mCurrMsgId; - QList tagLabels; - - QString fileName; - QFont mFont; // timer and index for showing message QTimer *timer; QModelIndex timerIndex; + MessageWidget *msgWidget; + /** Qt Designer generated object */ Ui::MessagesDialog ui; }; diff --git a/retroshare-gui/src/gui/MessagesDialog.ui b/retroshare-gui/src/gui/MessagesDialog.ui index 045fd5d2b..96b3e4f31 100644 --- a/retroshare-gui/src/gui/MessagesDialog.ui +++ b/retroshare-gui/src/gui/MessagesDialog.ui @@ -990,7 +990,7 @@ border-image: url(:/images/closepressed.png) Tags - Tag + Tags @@ -1014,7 +1014,7 @@ border-image: url(:/images/closepressed.png) - + Qt::LeftToRight @@ -1023,8 +1023,8 @@ border-image: url(:/images/closepressed.png) } - - 0 + + true @@ -1318,436 +1318,9 @@ padding: 4px; - - - - - - 0 - 0 - - - - true - - - true - - - - - - - - - 0 - - - 6 - - - - - - - - :/images/attachment.png - - - - - - - <html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal; text-decoration:none;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Recommended Files</span></p></body></html> - - - - - - - - 10 - true - - - - - - - - - - - - - Qt::Horizontal - - - - 351 - 20 - - - - - - - - Qt::NoFocus - - - Download all Recommended Files - - - - :/images/down.png:/images/down.png - - - - - - - Qt::NoFocus - - - - - - - :/images/edit_remove24.png:/images/edit_remove24.png - - - true - - - true - - - - - - - - - 6 - - - 0 - - - 6 - - - 0 - - - - - 6 - - - 3 - - - - - - 0 - 0 - - - - - 9 - 50 - false - - - - Subject: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 9 - 50 - false - - - - From: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 2 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - 9 - - - - true - - - true - - - - - - - - 0 - 0 - - - - - 9 - 50 - false - - - - To: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - true - - - true - - - - - - - - 0 - 0 - - - - - 9 - 50 - false - - - - Cc: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - false - - - - - - - - 0 - 0 - - - - - 9 - 50 - false - - - - Bcc: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - true - - - true - - - - - - - true - - - true - - - - - - - - 0 - 0 - - - - - 9 - 50 - false - - - - Tags: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - 0 - 0 - - - - - 9 - - - - true - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 0 - 0 - - - - - 9 - - - - Qt::LeftToRight - - - Date - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - - - + - - - - 9 - - - - Qt::CustomContextMenu - - - - - - true - - - - File Name - - - - - Size - - - - - Hash - - - @@ -1793,39 +1366,29 @@ p, li { white-space: pre-wrap; } Set Text Under Icon - + Save As... + + + RSTabWidget + QTabWidget +
gui/common/RSTabWidget.h
+ 1 +
+
newmessageButton replymessageButton listWidget - msgText - msgList - - expandFilesButton - clicked(bool) - msgList - setVisible(bool) - - - 184 - 348 - - - 399 - 397 - - - Tags_Button toggled(bool) diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.cpp b/retroshare-gui/src/gui/msgs/MessageWidget.cpp new file mode 100644 index 000000000..d1a1ae6e6 --- /dev/null +++ b/retroshare-gui/src/gui/msgs/MessageWidget.cpp @@ -0,0 +1,651 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006 - 2011 RetroShare Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "gui/notifyqt.h" +#include "gui/RetroShareLink.h" +#include "gui/common/TagDefs.h" +#include "gui/common/PeerDefs.h" +#include "gui/common/Emoticons.h" +#include "gui/settings/rsharesettings.h" +#include "MessageComposer.h" +#include "MessageWidget.h" +#include "MessageWindow.h" +#include "util/misc.h" +#include "util/printpreview.h" + +#include +#include +#include + +/* Images for context menu icons */ +#define IMAGE_DOWNLOAD ":/images/start.png" +#define IMAGE_DOWNLOADALL ":/images/startall.png" + +#define COLUMN_FILE_NAME 0 +#define COLUMN_FILE_SIZE 1 +#define COLUMN_FILE_HASH 2 +#define COLUMN_FILE_COUNT 3 + +MessageWidget *MessageWidget::openMsg(const std::string &msgId, bool window) +{ + if (msgId.empty()) { + return NULL; + } + + MessageInfo msgInfo; + if (!rsMsgs->getMessage(msgId, msgInfo)) { + std::cerr << "MessageWidget::openMsg() Couldn't find Msg" << std::endl; + return NULL; + } + + MessageWindow *parent = NULL; + if (window) { + parent = new MessageWindow; + } + MessageWidget *msgWidget = new MessageWidget(false, parent); + msgWidget->isWindow = window; + msgWidget->fill(msgId); + if (parent) { + parent->addWidget(msgWidget); + } + + if (parent) { + parent->show(); + parent->activateWindow(); + } + + return msgWidget; +} + +/** Constructor */ +MessageWidget::MessageWidget(bool controlled, QWidget *parent, Qt::WFlags flags) +: QWidget(parent, flags) +{ + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); + + isControlled = controlled; + isWindow = false; + + connect(ui.msgList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(msgfilelistWidgetCostumPopupMenu(QPoint))); + connect(ui.expandFilesButton, SIGNAL(clicked()), this, SLOT(togglefileview())); + connect(ui.downloadButton, SIGNAL(clicked()), this, SLOT(getallrecommended())); + + connect(NotifyQt::getInstance(), SIGNAL(messagesTagsChanged()), this, SLOT(messagesTagsChanged())); + connect(NotifyQt::getInstance(), SIGNAL(messagesChanged()), this, SLOT(messagesChanged())); + + /* hide the Tree +/- */ + ui.msgList->setRootIsDecorated( false ); + ui.msgList->setSelectionMode( QAbstractItemView::ExtendedSelection ); + + /* Set header resize modes and initial section sizes */ + QHeaderView * msglheader = ui.msgList->header () ; + msglheader->setResizeMode (COLUMN_FILE_NAME, QHeaderView::Interactive); + msglheader->setResizeMode (COLUMN_FILE_SIZE, QHeaderView::Interactive); + msglheader->setResizeMode (COLUMN_FILE_HASH, QHeaderView::Interactive); + + msglheader->resizeSection (COLUMN_FILE_NAME, 200); + msglheader->resizeSection (COLUMN_FILE_SIZE, 100); + msglheader->resizeSection (COLUMN_FILE_HASH, 200); + + QFont font = QFont("Arial", 10, QFont::Bold); + ui.subjectText->setFont(font); + + ui.bcclabel->setVisible(false); + ui.bccText->setVisible(false); + ui.cclabel->setVisible(false); + ui.ccText->setVisible(false); + + ui.tagsLabel->setVisible(false); + + if (isControlled == false) { + processSettings("MessageWidget", true); + } + + /* Hide platform specific features */ +#ifdef Q_WS_WIN + +#endif +} + +MessageWidget::~MessageWidget() +{ + if (isControlled == false) { + processSettings("MessageWidget", false); + } +} + +void MessageWidget::connectAction(enumActionType actionType, QToolButton* button) +{ + switch (actionType) { + case ACTION_REMOVE: + connect(button, SIGNAL(clicked()), this, SLOT(remove())); + break; + case ACTION_REPLY: + connect(button, SIGNAL(clicked()), this, SLOT(reply())); + break; + case ACTION_REPLY_ALL: + connect(button, SIGNAL(clicked()), this, SLOT(replyAll())); + break; + case ACTION_FORWARD: + connect(button, SIGNAL(clicked()), this, SLOT(forward())); + break; + case ACTION_PRINT: + connect(button, SIGNAL(clicked()), this, SLOT(print())); + break; + case ACTION_PRINT_PREVIEW: + connect(button, SIGNAL(clicked()), this, SLOT(printPreview())); + break; + case ACTION_SAVE_AS: + connect(button, SIGNAL(clicked()), this, SLOT(saveAs())); + break; + } +} + +void MessageWidget::connectAction(enumActionType actionType, QAction *action) +{ + switch (actionType) { + case ACTION_REMOVE: + connect(action, SIGNAL(triggered()), this, SLOT(remove())); + break; + case ACTION_REPLY: + connect(action, SIGNAL(triggered()), this, SLOT(reply())); + break; + case ACTION_REPLY_ALL: + connect(action, SIGNAL(triggered()), this, SLOT(replyAll())); + break; + case ACTION_FORWARD: + connect(action, SIGNAL(triggered()), this, SLOT(forward())); + break; + case ACTION_PRINT: + connect(action, SIGNAL(triggered()), this, SLOT(print())); + break; + case ACTION_PRINT_PREVIEW: + connect(action, SIGNAL(triggered()), this, SLOT(printPreview())); + break; + case ACTION_SAVE_AS: + connect(action, SIGNAL(triggered()), this, SLOT(saveAs())); + break; + } +} + +void MessageWidget::processSettings(const QString &settingsGroup, bool load) +{ + Settings->beginGroup(settingsGroup); + + if (load) { + // load settings + + // expandFiles + bool value = Settings->value("expandFiles", true).toBool(); + ui.expandFilesButton->setChecked(value); + ui.msgList->setVisible(value); + togglefileview(); + } else { + // save settings + + // expandFiles + Settings->setValue("expandFiles", ui.expandFilesButton->isChecked()); + } + + Settings->endGroup(); +} + +QString MessageWidget::subject(bool noEmpty) +{ + QString subject = ui.subjectText->text(); + if (subject.isEmpty() && noEmpty) { + return "[" + tr("No subject") + "]"; + } + + return subject; +} + +void MessageWidget::msgfilelistWidgetCostumPopupMenu( QPoint point ) +{ + QMenu contextMnu(this); + + contextMnu.addAction(QIcon(IMAGE_DOWNLOAD), tr("Download"), this, SLOT(getcurrentrecommended())); + contextMnu.addAction(QIcon(IMAGE_DOWNLOADALL), tr("Download all"), this, SLOT(getallrecommended())); + + contextMnu.exec(QCursor::pos()); +} + +void MessageWidget::togglefileview() +{ + /* if msg header visible -> change icon and tooltip + * three widgets... + */ + + if (ui.expandFilesButton->isChecked()) { + ui.expandFilesButton->setIcon(QIcon(QString(":/images/edit_remove24.png"))); + ui.expandFilesButton->setToolTip(tr("Hide")); + } else { + ui.expandFilesButton->setIcon(QIcon(QString(":/images/edit_add24.png"))); + ui.expandFilesButton->setToolTip(tr("Expand")); + } +} + +/* download the recommendations... */ +void MessageWidget::getcurrentrecommended() +{ + MessageInfo msgInfo; + if (rsMsgs->getMessage(currMsgId, msgInfo) == false) { + return; + } + + std::list srcIds; + srcIds.push_back(msgInfo.srcId); + + QModelIndexList list = ui.msgList->selectionModel()->selectedIndexes(); + + std::map files ; + + for (QModelIndexList::const_iterator it(list.begin());it!=list.end();++it) { + FileInfo& fi(files[it->row()]) ; + + switch (it->column()) { + case COLUMN_FILE_NAME: + fi.fname = it->data().toString().toStdString() ; + break ; + case COLUMN_FILE_SIZE: + fi.size = it->data().toULongLong() ; + break ; + case COLUMN_FILE_HASH: + fi.hash = it->data().toString().toStdString() ; + break ; + } + } + + for(std::map::const_iterator it(files.begin());it!=files.end();++it) { + const FileInfo& fi(it->second) ; + std::cout << "Requesting file " << fi.fname << ", size=" << fi.size << ", hash=" << fi.hash << std::endl ; + + if (rsFiles->FileRequest(fi.fname, fi.hash, fi.size, "", RS_FILE_HINTS_NETWORK_WIDE, srcIds) == false) { + QMessageBox mb(QObject::tr("File Request canceled"), QObject::tr("The following has not been added to your download list, because you already have it:\n ") + QString::fromStdString(fi.fname), QMessageBox::Critical, QMessageBox::Ok, 0, 0); + mb.setWindowIcon(QIcon(QString::fromUtf8(":/images/rstray3.png"))); + mb.exec(); + } + } +} + +void MessageWidget::getallrecommended() +{ + /* get Message */ + MessageInfo msgInfo; + if (rsMsgs->getMessage(currMsgId, msgInfo) == false) { + return; + } + + const std::list &recList = msgInfo.files; + std::list::const_iterator it; + + /* do the requests */ + for(it = recList.begin(); it != recList.end(); it++) { + std::cerr << "MessageWidget::getallrecommended() Calling File Request" << std::endl; + std::list srcIds; + srcIds.push_back(msgInfo.srcId); + rsFiles->FileRequest(it->fname, it->hash, it->size, "", RS_FILE_HINTS_NETWORK_WIDE, srcIds); + } +} + +void MessageWidget::messagesTagsChanged() +{ + showTagLabels(); +} + +void MessageWidget::messagesChanged() +{ + if (isControlled) { + /* processed by MessagesDialog */ + return; + } + + /* test Message */ + MessageInfo msgInfo; + if (rsMsgs->getMessage(currMsgId, msgInfo) == false) { + /* messages was removed */ + if (isWindow) { + window()->close(); + } else { + deleteLater(); + } + } +} + +void MessageWidget::clearTagLabels() +{ + /* clear all tags */ + while (tagLabels.size()) { + delete tagLabels.front(); + tagLabels.pop_front(); + } + while (ui.tagLayout->count()) { + delete ui.tagLayout->takeAt(0); + } + + ui.tagsLabel->setVisible(false); +} + +void MessageWidget::showTagLabels() +{ + clearTagLabels(); + + if (currMsgId.empty()) { + return; + } + + MsgTagInfo tagInfo; + rsMsgs->getMessageTag(currMsgId, tagInfo); + + if (tagInfo.tagIds.empty() == false) { + ui.tagsLabel->setVisible(true); + + MsgTagType Tags; + rsMsgs->getMessageTagTypes(Tags); + + std::map >::iterator Tag; + for (std::list::iterator tagId = tagInfo.tagIds.begin(); tagId != tagInfo.tagIds.end(); tagId++) { + Tag = Tags.types.find(*tagId); + if (Tag != Tags.types.end()) { + QLabel *tagLabel = new QLabel(TagDefs::name(Tag->first, Tag->second.first), this); + tagLabel->setMaximumHeight(16); + tagLabel->setStyleSheet(TagDefs::labelStyleSheet(Tag->second.second)); + tagLabels.push_back(tagLabel); + ui.tagLayout->addWidget(tagLabel); + ui.tagLayout->addSpacing(3); + } + } + ui.tagLayout->addStretch(); + } else { + ui.tagsLabel->setVisible(false); + } +} + +void MessageWidget::fill(const std::string &msgId) +{ + if (currMsgId == msgId) { + // message doesn't changed + return; + } + + currMsgId = msgId; + + if (currMsgId.empty()) { + /* blank it */ + ui.dateText-> setText(""); + ui.toText->setText(""); + ui.fromText->setText(""); + ui.filesText->setText(""); + + ui.cclabel->setVisible(false); + ui.ccText->setVisible(false); + ui.ccText->clear(); + + ui.bcclabel->setVisible(false); + ui.bccText->setVisible(false); + ui.bccText->clear(); + + ui.subjectText->setText(""); + ui.msgList->clear(); + ui.msgText->clear(); + + clearTagLabels(); + + return; + } + + clearTagLabels(); + + MessageInfo msgInfo; + if (rsMsgs->getMessage(currMsgId, msgInfo) == false) { + std::cerr << "MessageWidget::fill() Couldn't find Msg" << std::endl; + return; + } + + const std::list &recList = msgInfo.files; + std::list::const_iterator it; + + ui.msgList->clear(); + + QList items; + for (it = recList.begin(); it != recList.end(); it++) { + QTreeWidgetItem *item = new QTreeWidgetItem; + item->setText(COLUMN_FILE_NAME, QString::fromStdString(it->fname)); + item->setText(COLUMN_FILE_SIZE, QString::number(it->size)); + item->setText(COLUMN_FILE_HASH, QString::fromStdString(it->hash)); + + /* add to the list */ + items.append(item); + } + + /* add the items in! */ + ui.msgList->insertTopLevelItems(0, items); + + /* iterate through the sources */ + std::list::const_iterator pit; + + RetroShareLink link; + QString text; + + for(pit = msgInfo.msgto.begin(); pit != msgInfo.msgto.end(); pit++) { + if (link.createMessage(*pit, "")) { + text += link.toHtml() + " "; + } + } + ui.toText->setText(text); + + if (msgInfo.msgcc.size() > 0) { + ui.cclabel->setVisible(true); + ui.ccText->setVisible(true); + + text.clear(); + for(pit = msgInfo.msgcc.begin(); pit != msgInfo.msgcc.end(); pit++) { + if (link.createMessage(*pit, "")) { + text += link.toHtml() + " "; + } + } + ui.ccText->setText(text); + } else { + ui.cclabel->setVisible(false); + ui.ccText->setVisible(false); + ui.ccText->clear(); + } + + if (msgInfo.msgbcc.size() > 0) { + ui.bcclabel->setVisible(true); + ui.bccText->setVisible(true); + + text.clear(); + for(pit = msgInfo.msgbcc.begin(); pit != msgInfo.msgbcc.end(); pit++) { + if (link.createMessage(*pit, "")) { + text += link.toHtml() + " "; + } + } + ui.bccText->setText(text); + } else { + ui.bcclabel->setVisible(false); + ui.bccText->setVisible(false); + ui.bccText->clear(); + } + + { + QDateTime qtime; + qtime.setTime_t(msgInfo.ts); + QString timestamp = qtime.toString("dd.MM.yyyy hh:mm:ss"); + ui.dateText->setText(timestamp); + } + + std::string srcId; + if ((msgInfo.msgflags & RS_MSG_BOXMASK) == RS_MSG_OUTBOX) { + // outgoing message are from me + srcId = rsPeers->getOwnId(); + } else { + srcId = msgInfo.srcId; + } + link.createMessage(srcId, ""); + + ui.fromText->setText(link.toHtml()); + ui.fromText->setToolTip(PeerDefs::rsidFromId(srcId)); + + ui.subjectText->setText(QString::fromStdWString(msgInfo.title)); + + text = RsHtml::formatText(QString::fromStdWString(msgInfo.msg), RSHTML_FORMATTEXT_EMBED_SMILEYS | RSHTML_FORMATTEXT_EMBED_LINKS); + ui.msgText->setHtml(text); + + ui.filesText->setText(QString("(%1 %2)").arg(msgInfo.count).arg(msgInfo.count == 1 ? tr("File") : tr("Files"))); + + showTagLabels(); +} + +void MessageWidget::remove() +{ + MessageInfo msgInfo; + if (rsMsgs->getMessage(currMsgId, msgInfo) == false) { + std::cerr << "MessageWidget::fill() Couldn't find Msg" << std::endl; + return; + } + + bool deleteReal = false; + if (msgInfo.msgflags & RS_MSG_TRASH) { + deleteReal = true; + } else { + if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { + deleteReal = true; + } + } + + if (deleteReal) { + rsMsgs->MessageDelete(currMsgId); + } else { + rsMsgs->MessageToTrash(currMsgId, true); + } + + if (isWindow) { + window()->close(); + } else { + deleteLater(); + } +} + +void MessageWidget::print() +{ +#ifndef QT_NO_PRINTER + QPrinter printer(QPrinter::HighResolution); + printer.setFullPage(true); + QPrintDialog *dlg = new QPrintDialog(&printer, this); + if (ui.msgText->textCursor().hasSelection()) + dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection); + dlg->setWindowTitle(tr("Print Document")); + if (dlg->exec() == QDialog::Accepted) { + ui.msgText->print(&printer); + } + delete dlg; +#endif +} + +void MessageWidget::printPreview() +{ + PrintPreview *preview = new PrintPreview(ui.msgText->document(), this); + preview->setWindowModality(Qt::WindowModal); + preview->setAttribute(Qt::WA_DeleteOnClose); + preview->show(); + + /* window will destroy itself! */ +} + +void MessageWidget::saveAs() +{ + QString filename; + if (misc::getSaveFileName(window(), RshareSettings::LASTDIR_MESSAGES, tr("Save as..."), tr("HTML-Files (*.htm *.html);;All Files (*)"), filename)) { + QFile file(filename); + if (!file.open(QFile::WriteOnly)) + return; + QTextStream ts(&file); + ts.setCodec(QTextCodec::codecForName("UTF-8")); + ts << ui.msgText->document()->toHtml("UTF-8"); + ui.msgText->document()->setModified(false); + } +} + +void MessageWidget::reply() +{ + /* put msg on msgBoard, and switch to it. */ + + if (currMsgId.empty()) { + return; + } + + MessageComposer *msgComposer = MessageComposer::replyMsg(currMsgId, false); + if (msgComposer == NULL) { + return; + } + + msgComposer->show(); + msgComposer->activateWindow(); + + /* window will destroy itself! */ +} + +void MessageWidget::replyAll() +{ + /* put msg on msgBoard, and switch to it. */ + + if (currMsgId.empty()) { + return; + } + + MessageComposer *msgComposer = MessageComposer::replyMsg(currMsgId, true); + if (msgComposer == NULL) { + return; + } + + msgComposer->show(); + msgComposer->activateWindow(); + + /* window will destroy itself! */ +} + +void MessageWidget::forward() +{ + /* put msg on msgBoard, and switch to it. */ + + if (currMsgId.empty()) { + return; + } + + MessageComposer *msgComposer = MessageComposer::forwardMsg(currMsgId); + if (msgComposer == NULL) { + return; + } + + msgComposer->show(); + msgComposer->activateWindow(); + + /* window will destroy itself! */ +} diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.h b/retroshare-gui/src/gui/msgs/MessageWidget.h new file mode 100644 index 000000000..07fb4cc4e --- /dev/null +++ b/retroshare-gui/src/gui/msgs/MessageWidget.h @@ -0,0 +1,93 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006 - 2011, RetroShare Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#ifndef _MESSAGEWIDGET_H +#define _MESSAGEWIDGET_H + +#include +#include "ui_MessageWidget.h" + +class QToolButton; +class QAction; +class QTextEdit; + +class MessageWidget : public QWidget +{ + Q_OBJECT + +public: + enum enumActionType { + ACTION_REMOVE, + ACTION_REPLY, + ACTION_REPLY_ALL, + ACTION_FORWARD, + ACTION_PRINT, + ACTION_PRINT_PREVIEW, + ACTION_SAVE_AS + }; + +public: + MessageWidget(bool controlled, QWidget *parent = 0, Qt::WFlags flags = 0); + ~MessageWidget(); + + static MessageWidget *openMsg(const std::string &msgId, bool window); + + std::string msgId() { return currMsgId; } + void connectAction(enumActionType actionType, QToolButton* button); + void connectAction(enumActionType actionType, QAction* action); + + void fill(const std::string &msgId); + void processSettings(const QString &settingsGroup, bool load); + + QString subject(bool noEmpty); + +private slots: + void reply(); + void replyAll(); + void forward(); + void remove(); + void print(); + void printPreview(); + void saveAs(); + + void msgfilelistWidgetCostumPopupMenu(QPoint); + void messagesTagsChanged(); + void messagesChanged(); + + void togglefileview(); + void getcurrentrecommended(); + void getallrecommended(); + +private: + void clearTagLabels(); + void showTagLabels(); + + bool isControlled; + bool isWindow; + std::string currMsgId; + + QList tagLabels; + + /** Qt Designer generated object */ + Ui::MessageWidget ui; +}; + +#endif diff --git a/retroshare-gui/src/gui/msgs/MessageWidget.ui b/retroshare-gui/src/gui/msgs/MessageWidget.ui new file mode 100644 index 000000000..b172e1e9e --- /dev/null +++ b/retroshare-gui/src/gui/msgs/MessageWidget.ui @@ -0,0 +1,502 @@ + + + MessageWidget + + + + 0 + 0 + 698 + 539 + + + + + :/images/rstray3.png:/images/rstray3.png + + + + 0 + + + 2 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + true + + + true + + + + + + + + + 0 + + + 6 + + + + + + + + :/images/attachment.png + + + + + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Recommended Files</span></p></body></html> + + + + + + + + 10 + true + + + + + + + + + + + + + Qt::Horizontal + + + + 351 + 20 + + + + + + + + Qt::NoFocus + + + Download all Recommended Files + + + + :/images/down.png:/images/down.png + + + + + + + Qt::NoFocus + + + + + + + :/images/edit_remove24.png:/images/edit_remove24.png + + + true + + + true + + + + + + + + + 6 + + + 0 + + + 6 + + + 0 + + + + + 6 + + + 3 + + + + + + 0 + 0 + + + + + 9 + 50 + false + + + + Subject: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 9 + 50 + false + + + + From: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 2 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 9 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 9 + 50 + false + + + + To: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 9 + 50 + false + + + + Cc: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + + 9 + 50 + false + + + + Bcc: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + true + + + + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 9 + 50 + false + + + + Tags: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + 0 + 0 + + + + + 9 + + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + + 9 + + + + Qt::LeftToRight + + + Date + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + + + + + + + + + 9 + + + + Qt::CustomContextMenu + + + true + + + + File Name + + + + + Size + + + + + Hash + + + + + + + + + Print + + + + + Print Preview + + + + + + + + + expandFilesButton + clicked(bool) + msgList + setVisible(bool) + + + 672 + 334 + + + 348 + 432 + + + + + diff --git a/retroshare-gui/src/gui/msgs/MessageWindow.cpp b/retroshare-gui/src/gui/msgs/MessageWindow.cpp new file mode 100644 index 000000000..d4e721790 --- /dev/null +++ b/retroshare-gui/src/gui/msgs/MessageWindow.cpp @@ -0,0 +1,229 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006 - 2011 RetroShare Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#include "MessageWindow.h" +#include "MessageWidget.h" +#include "MessageComposer.h" +#include "TagsMenu.h" +#include "gui/settings/rsharesettings.h" + +#include + +/** Constructor */ +MessageWindow::MessageWindow(QWidget *parent, Qt::WFlags flags) +: RWindow("MessageWindow", parent, flags) +{ + /* Invoke the Qt Designer generated object setup routine */ + ui.setupUi(this); + + setAttribute ( Qt::WA_DeleteOnClose, true ); + + actionSaveAs = NULL; + actionPrint = NULL; + actionPrintPreview = NULL; + + setupFileActions(); + + connect(ui.newmessageButton, SIGNAL(clicked()), this, SLOT(newmessage())); + + connect(ui.actionTextBesideIcon, SIGNAL(triggered()), this, SLOT(buttonStyle())); + connect(ui.actionIconOnly, SIGNAL(triggered()), this, SLOT(buttonStyle())); + connect(ui.actionTextUnderIcon, SIGNAL(triggered()), this, SLOT(buttonStyle())); + + ui.actionTextBesideIcon->setData(Qt::ToolButtonTextBesideIcon); + ui.actionIconOnly->setData(Qt::ToolButtonIconOnly); + ui.actionTextUnderIcon->setData(Qt::ToolButtonTextUnderIcon); + + msgWidget = NULL; + + // create tag menu + TagsMenu *menu = new TagsMenu (tr("Tags"), this); + connect(menu, SIGNAL(aboutToShow()), this, SLOT(tagAboutToShow())); + connect(menu, SIGNAL(tagSet(int, bool)), this, SLOT(tagSet(int, bool))); + connect(menu, SIGNAL(tagRemoveAll()), this, SLOT(tagRemoveAll())); + + ui.tagButton->setMenu(menu); + + // create print menu + QMenu *printmenu = new QMenu(); + printmenu->addAction(ui.actionPrint); + printmenu->addAction(ui.actionPrint_Preview); + ui.printbutton->setMenu(printmenu); + + // create view menu + QMenu *viewmenu = new QMenu(); + viewmenu->addAction(ui.actionTextBesideIcon); + viewmenu->addAction(ui.actionIconOnly); + //viewmenu->addAction(ui.actionTextUnderIcon); + ui.viewtoolButton->setMenu(viewmenu); + + processSettings(true); + + /* Hide platform specific features */ +#ifdef Q_WS_WIN + +#endif +} + +MessageWindow::~MessageWindow() +{ + processSettings(false); +} + +void MessageWindow::processSettings(bool load) +{ + Settings->beginGroup(QString("MessageDialog")); + + if (load) { + // load settings + + /* toolbar button style */ + Qt::ToolButtonStyle style = (Qt::ToolButtonStyle) Settings->value("ToolButon_Stlye", Qt::ToolButtonIconOnly).toInt(); + setToolbarButtonStyle(style); + } else { + // save settings + + /* toolbar button style */ + Settings->setValue("ToolButon_Stlye", ui.newmessageButton->toolButtonStyle()); + } + + Settings->endGroup(); +} + +void MessageWindow::addWidget(MessageWidget *widget) +{ + if (msgWidget) { + delete(msgWidget); + } + + msgWidget = widget; + if (msgWidget) { + ui.msgLayout->addWidget(msgWidget); + setWindowTitle(msgWidget->subject(true)); + + msgWidget->connectAction(MessageWidget::ACTION_REMOVE, ui.removemessageButton); + msgWidget->connectAction(MessageWidget::ACTION_REPLY, ui.replymessageButton); + msgWidget->connectAction(MessageWidget::ACTION_REPLY_ALL, ui.replyallmessageButton); + msgWidget->connectAction(MessageWidget::ACTION_FORWARD, ui.forwardmessageButton); + msgWidget->connectAction(MessageWidget::ACTION_PRINT, ui.printbutton); + msgWidget->connectAction(MessageWidget::ACTION_PRINT, ui.actionPrint); + msgWidget->connectAction(MessageWidget::ACTION_PRINT, actionPrint); + msgWidget->connectAction(MessageWidget::ACTION_PRINT_PREVIEW, ui.actionPrint_Preview); + msgWidget->connectAction(MessageWidget::ACTION_PRINT_PREVIEW, actionPrintPreview); +// msgWidget->connectAction(ACTION_SAVE, + msgWidget->connectAction(MessageWidget::ACTION_SAVE_AS, actionSaveAs); + } else { + setWindowTitle(""); + } +} + +void MessageWindow::newmessage() +{ + MessageComposer *msgComposer = MessageComposer::newMsg(); + if (msgComposer == NULL) { + return; + } + + /* fill it in */ + msgComposer->show(); + msgComposer->activateWindow(); + + /* window will destroy itself! */ +} + +void MessageWindow::tagAboutToShow() +{ + if (msgWidget == NULL) { + return; + } + + TagsMenu *menu = dynamic_cast(ui.tagButton->menu()); + if (menu == NULL) { + return; + } + + // activate actions + MsgTagInfo tagInfo; + rsMsgs->getMessageTag(msgWidget->msgId(), tagInfo); + + menu->activateActions(tagInfo.tagIds); +} + +void MessageWindow::tagRemoveAll() +{ + if (msgWidget == NULL) { + return; + } + + rsMsgs->setMessageTag(msgWidget->msgId(), 0, false); +} + +void MessageWindow::tagSet(int tagId, bool set) +{ + if (msgWidget == NULL) { + return; + } + + if (tagId == 0) { + return; + } + + rsMsgs->setMessageTag(msgWidget->msgId(), tagId, set); +} + +void MessageWindow::setupFileActions() +{ + QMenu *menu = new QMenu(tr("&File"), this); + menuBar()->addMenu(menu); + + actionSaveAs = menu->addAction(tr("Save &As File")); + actionPrint = menu->addAction(QIcon(":/images/textedit/fileprint.png"), tr("&Print...")); + actionPrint->setShortcut(QKeySequence::Print); + + actionPrintPreview = menu->addAction(QIcon(":/images/textedit/fileprint.png"), tr("Print Preview...")); + +// a = new QAction(QIcon(":/images/textedit/exportpdf.png"), tr("&Export PDF..."), this); +// a->setShortcut(Qt::CTRL + Qt::Key_D); +// connect(a, SIGNAL(triggered()), this, SLOT(filePrintPdf())); +// menu->addAction(a); + + menu->addSeparator(); + + QAction *action = menu->addAction(tr("&Quit"), this, SLOT(close())); + action->setShortcut(Qt::CTRL + Qt::Key_Q); +} + +void MessageWindow::setToolbarButtonStyle(Qt::ToolButtonStyle style) +{ + ui.newmessageButton->setToolButtonStyle(style); + ui.removemessageButton->setToolButtonStyle(style); + ui.replymessageButton->setToolButtonStyle(style); + ui.replyallmessageButton->setToolButtonStyle(style); + ui.forwardmessageButton->setToolButtonStyle(style); + ui.tagButton->setToolButtonStyle(style); + ui.printbutton->setToolButtonStyle(style); + ui.viewtoolButton->setToolButtonStyle(style); +} + +void MessageWindow::buttonStyle() +{ + setToolbarButtonStyle((Qt::ToolButtonStyle) dynamic_cast(sender())->data().toInt()); +} diff --git a/retroshare-gui/src/gui/msgs/MessageWindow.h b/retroshare-gui/src/gui/msgs/MessageWindow.h new file mode 100644 index 000000000..40217f9f5 --- /dev/null +++ b/retroshare-gui/src/gui/msgs/MessageWindow.h @@ -0,0 +1,64 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006 - 2011, RetroShare Team + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + ****************************************************************/ + +#ifndef _MESSAGEWINDOW_H +#define _MESSAGEWINDOW_H + +#include "gui/common/rwindow.h" +#include "ui_MessageWindow.h" + +class MessageWidget; + +class MessageWindow : public RWindow +{ + Q_OBJECT + +public: + /** Default Constructor */ + + MessageWindow(QWidget *parent = 0, Qt::WFlags flags = 0); + ~MessageWindow(); + + void addWidget(MessageWidget *widget); + +private slots: + void newmessage(); + void tagAboutToShow(); + void tagSet(int tagId, bool set); + void tagRemoveAll(); + + void buttonStyle(); + +private: + void setupFileActions(); + void processSettings(bool load); + void setToolbarButtonStyle(Qt::ToolButtonStyle style); + + MessageWidget *msgWidget; + QAction *actionSaveAs; + QAction *actionPrint; + QAction *actionPrintPreview; + + /** Qt Designer generated object */ + Ui::MessageWindow ui; +}; + +#endif diff --git a/retroshare-gui/src/gui/msgs/MessageWindow.ui b/retroshare-gui/src/gui/msgs/MessageWindow.ui new file mode 100644 index 000000000..53fbde101 --- /dev/null +++ b/retroshare-gui/src/gui/msgs/MessageWindow.ui @@ -0,0 +1,400 @@ + + + MessageWindow + + + + 0 + 0 + 698 + 539 + + + + + :/images/rstray3.png:/images/rstray3.png + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 36 + + + + + 0 + 68 + + + + QFrame#frame{ +background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, +stop:0 #FEFEFE, stop:1 #E8E8E8); + +border: 1px solid #CCCCCC;} + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 2 + + + 6 + + + + + Qt::NoFocus + + + New Message + + + Compose + + + + :/images/folder-draft24.png:/images/folder-draft24.png + + + + 24 + 24 + + + + Qt::ToolButtonIconOnly + + + true + + + + + + + Qt::Vertical + + + + + + + Qt::NoFocus + + + Reply to selected message + + + Reply + + + + :/images/replymail-pressed.png:/images/replymail-pressed.png + + + + 24 + 24 + + + + Qt::ToolButtonIconOnly + + + true + + + + + + + Qt::NoFocus + + + Reply all to selected message + + + Reply all + + + + :/images/replymailall24-hover.png:/images/replymailall24-hover.png + + + + 24 + 24 + + + + Qt::ToolButtonIconOnly + + + true + + + + + + + + 0 + 0 + + + + + 16777 + 16777 + + + + Qt::NoFocus + + + Forward selected message + + + Foward + + + + :/images/mailforward24-hover.png:/images/mailforward24-hover.png + + + + 24 + 24 + + + + Qt::ToolButtonIconOnly + + + true + + + + + + + Qt::Vertical + + + + + + + Qt::NoFocus + + + Remove selected message + + + Delete + + + + :/images/deletemail24.png:/images/deletemail24.png + + + + 24 + 24 + + + + Qt::ToolButtonIconOnly + + + true + + + + + + + Qt::NoFocus + + + Print selected message + + + Print + + + + :/images/print24.png:/images/print24.png + + + + 24 + 24 + + + + QToolButton::MenuButtonPopup + + + Qt::ToolButtonIconOnly + + + true + + + + + + + Qt::NoFocus + + + Display + + + + :/images/looknfeel.png:/images/looknfeel.png + + + + 24 + 24 + + + + QToolButton::MenuButtonPopup + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::NoFocus + + + Tags + + + Tags + + + + :/images/tag24.png:/images/tag24.png + + + + 24 + 24 + + + + QToolButton::MenuButtonPopup + + + true + + + + + + + + + + + + + + + + 0 + 0 + 698 + 20 + + + + + + Print + + + + + Print Preview + + + + + Buttons Icon Only + + + Buttons Icon Only + + + + + Buttons Text Beside Icon + + + Buttons with Text + + + + + Buttons Text Under Icon + + + Set Text Under Icon + + + + + + + + diff --git a/retroshare-gui/src/gui/settings/MessagePage.cpp b/retroshare-gui/src/gui/settings/MessagePage.cpp index 5e6ab761b..3c8814490 100644 --- a/retroshare-gui/src/gui/settings/MessagePage.cpp +++ b/retroshare-gui/src/gui/settings/MessagePage.cpp @@ -47,6 +47,9 @@ MessagePage::MessagePage(QWidget * parent, Qt::WFlags flags) ui.editpushButton->setEnabled(false); ui.deletepushButton->setEnabled(false); + + ui.openComboBox->addItem(tr("A new tab"), RshareSettings::MSG_OPEN_TAB); + ui.openComboBox->addItem(tr("A new window"), RshareSettings::MSG_OPEN_WINDOW); } MessagePage::~MessagePage() @@ -65,6 +68,7 @@ bool MessagePage::save(QString &errmsg) { Settings->setMsgSetToReadOnActivate(ui.setMsgToReadOnActivate->isChecked()); + Settings->setMsgOpen((RshareSettings::enumMsgOpen) ui.openComboBox->itemData(ui.openComboBox->currentIndex()).toInt()); std::map >::iterator Tag; for (Tag = m_pTags->types.begin(); Tag != m_pTags->types.end(); Tag++) { @@ -92,6 +96,7 @@ void MessagePage::load() { ui.setMsgToReadOnActivate->setChecked(Settings->getMsgSetToReadOnActivate()); + ui.openComboBox->setCurrentIndex(ui.openComboBox->findData(Settings->getMsgOpen())); // fill items rsMsgs->getMessageTagTypes(*m_pTags); diff --git a/retroshare-gui/src/gui/settings/MessagePage.ui b/retroshare-gui/src/gui/settings/MessagePage.ui index aa095d386..233d7fd58 100644 --- a/retroshare-gui/src/gui/settings/MessagePage.ui +++ b/retroshare-gui/src/gui/settings/MessagePage.ui @@ -503,7 +503,7 @@ - Misc + Reading @@ -513,6 +513,20 @@ + + + + + + Open messages in + + + + + + + + diff --git a/retroshare-gui/src/gui/settings/rsharesettings.cpp b/retroshare-gui/src/gui/settings/rsharesettings.cpp index b3c291a54..e9eaf8e61 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.cpp +++ b/retroshare-gui/src/gui/settings/rsharesettings.cpp @@ -627,6 +627,32 @@ void RshareSettings::setMsgSetToReadOnActivate (bool bValue) setValueToGroup("MessageDialog", "SetMsgToReadOnActivate", bValue); } +RshareSettings::enumMsgOpen RshareSettings::getMsgOpen() +{ + enumMsgOpen value = (enumMsgOpen) valueFromGroup("MessageDialog", "msgOpen", MSG_OPEN_TAB).toInt(); + + switch (value) { + case MSG_OPEN_TAB: + case MSG_OPEN_WINDOW: + return value; + } + + return MSG_OPEN_TAB; +} + +void RshareSettings::setMsgOpen(enumMsgOpen value) +{ + switch (value) { + case MSG_OPEN_TAB: + case MSG_OPEN_WINDOW: + break; + default: + value = MSG_OPEN_TAB; + } + + setValueToGroup("MessageDialog", "msgOpen", value); +} + /* Forums */ bool RshareSettings::getForumMsgSetToReadOnActivate () { diff --git a/retroshare-gui/src/gui/settings/rsharesettings.h b/retroshare-gui/src/gui/settings/rsharesettings.h index a6bc6393b..18bda3e8c 100644 --- a/retroshare-gui/src/gui/settings/rsharesettings.h +++ b/retroshare-gui/src/gui/settings/rsharesettings.h @@ -75,6 +75,12 @@ public: TOASTERPOS_BOTTOMRIGHT }; + enum enumMsgOpen + { + MSG_OPEN_TAB, + MSG_OPEN_WINDOW + }; + public: /* create settings object */ static void Create (); @@ -210,6 +216,9 @@ public: bool getMsgSetToReadOnActivate (); void setMsgSetToReadOnActivate (bool bValue); + enumMsgOpen getMsgOpen(); + void setMsgOpen(enumMsgOpen value); + /* Forums */ bool getForumMsgSetToReadOnActivate (); void setForumMsgSetToReadOnActivate (bool bValue); diff --git a/retroshare-gui/src/lang/retroshare_de.qm b/retroshare-gui/src/lang/retroshare_de.qm index 3bb29e5c2a3db7035322d139d71b76150f436e0e..ca3b5b2c16303ac6328597b8d31a22b9cbe98685 100644 GIT binary patch delta 13637 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 EFKZDAc>n+a delta 12248 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 IvzovD2iAI4ga7~l diff --git a/retroshare-gui/src/lang/retroshare_de.ts b/retroshare-gui/src/lang/retroshare_de.ts index 25379e033..ae6382ade 100644 --- a/retroshare-gui/src/lang/retroshare_de.ts +++ b/retroshare-gui/src/lang/retroshare_de.ts @@ -4370,7 +4370,7 @@ p, li { white-space: pre-wrap; } Willst du diesen Freund entfernen? - + is typing... tippt... @@ -6604,9 +6604,13 @@ Willst Du die Nachricht speichern ? MessagePage - Misc - Verschiedenes + Verschiedenes + + + + Reading + Lesen @@ -6614,7 +6618,12 @@ Willst Du die Nachricht speichern ? Setze Nachricht beim Aktivieren als gelesen - + + Open messages in + Nachricht durch Doppelklick öffnen in + + + Tags Schlagwörter @@ -6644,7 +6653,17 @@ Willst Du die Nachricht speichern ? Standard - + + A new tab + Neuem Tab + + + + A new window + Neuem Fenster + + + Edit Tag Schlagwort bearbeiten @@ -6673,43 +6692,13 @@ Willst Du die Nachricht speichern ? - MessagesDialog + MessageWidget - - - New Message - Neue Nachricht + MainWindow + Hauptfenster - - Reply to Message - Antworten nur an Absender - - - - Remove Message - Nachricht entfernen - - - - - Date - Datum - - - - - - From - Von - - - - Size - Grösse - - - + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal; text-decoration:none;"> @@ -6717,7 +6706,306 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Empfohlene Dateien</span></p></body></html> - + + Download all Recommended Files + Alle Dateien runterladen + + + + Subject: + Betreff: + + + + From: + Von: + + + + To: + An: + + + + Cc: + Cc: + + + + Bcc: + Bcc: + + + + Tags: + Schlagwörter: + + + + File Name + Dateiname + + + + Size + Grösse + + + + Hash + Prüfsumme + + + + Print + Drucken + + + + Print Preview + Druckvorschau + + + + No subject + Kein Betreff + + + + Download + Herunterladen + + + + Download all + Alle herunterladen + + + + Hide + Verbergen + + + + Expand + Erweitern + + + + File + Datei + + + + Files + Dateien + + + + Print Document + Dokument drucken + + + + Save as... + Speichern unter... + + + + HTML-Files (*.htm *.html);;All Files (*) + HTML-Dateien (*.htm *.html);;Alle Dateien (*) + + + + MessageWindow + + MainWindow + Hauptfenster + + + + New Message + Neue Nachricht + + + + Compose + Verfassen + + + + Reply to selected message + Auf gewählte Nachricht antworten + + + + Reply + Antwort + + + + Reply all to selected message + Auf gewählte Nachricht an alle Empfänger antworten + + + + Reply all + Allen antworten + + + + Forward selected message + Gewählte Nachricht weiterleiten + + + + Foward + Weiterleiten + + + + Remove selected message + Gewählte Nachricht entfernen + + + + Delete + Löschen + + + + Print selected message + Gewählte Nachricht drucken + + + + + Print + Drucken + + + + Display + Anzeige + + + + + + Tags + Schlagwörter + + + + Print Preview + Druckvorschau + + + + + Buttons Icon Only + Buttons nur mit Icon + + + + Buttons Text Beside Icon + Button Text neben Icon + + + + Buttons with Text + Buttons mit Text + + + + Buttons Text Under Icon + Buttons Text unter dem Icon + + + + Set Text Under Icon + Text unter dem Icon + + + + &File + &Datei + + + + Save &As File + Speichern &unter + + + + &Print... + &Drucken... + + + + Print Preview... + Druckvorschau... + + + + &Quit + &Schliessen + + + + MessagesDialog + + + + New Message + Neue Nachricht + + + + Reply to Message + Antworten nur an Absender + + + + Open in a new window + In neuem Fenster öffnen + + + + Open in a new tab + In neuem Tab öffnen + + + + Remove Message + Nachricht entfernen + + + + + Date + Datum + + + + + + From + Von + + + Size + Grösse + + + <html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal; text-decoration:none;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Recommended Files</span></p></body></html> + <html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Arial'; font-size:8pt; font-weight:400; font-style:normal; text-decoration:none;"><p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Empfohlene Dateien</span></p></body></html> + + + Reply Antworten @@ -6783,16 +7071,16 @@ p, li { white-space: pre-wrap; } - - + + Inbox Posteingang - - + + Outbox Postausgang @@ -6804,32 +7092,28 @@ p, li { white-space: pre-wrap; } - + Sent Gesendet - Download all Recommended Files - Alle Dateien runterladen + Alle Dateien runterladen - Cc: - Cc: + Cc: - Bcc: - Bcc: + Bcc: - Tags: - Schlagwörter: + Schlagwörter: - + Print... Drucken... @@ -6871,63 +7155,67 @@ p, li { white-space: pre-wrap; } Speichern unter... - Print Document - Dokument drucken + Dokument drucken - - + + Subject Betreff - Subject: - Betreff: + Betreff: - From: - Von: + Von: - To: - An: + An: - File Name - Dateiname + Dateiname - Hash - Prüfsumme + Prüfsumme - + Print Drucken - + Forward selected Message Gewählte Nachricht weiterleiten - + + Edit + Bearbeiten + + + + Edit as new + Als neu bearbeiten + + + Remove Messages Nachrichten entfernen - + Forward Message Weiterleiten - + Click to sort by attachments Klicken, um nach Anhang zu sortieren @@ -6943,12 +7231,12 @@ p, li { white-space: pre-wrap; } - + Click to sort by from Klicken, um nach Von zu sortieren - + Click to sort by date Klicken, um nach Datum zu sortieren @@ -6962,48 +7250,41 @@ p, li { white-space: pre-wrap; } Klicken, um nach Kennzeichnung zu sortieren - Download - Herunterladen + Herunterladen - Hide - Empfohlene Dateien ausblenden + Empfohlene Dateien ausblenden - Expand - Empfohlene Dateien einblenden + Empfohlene Dateien einblenden - + Click to sort by to Klicken, um nach Empfänger zu sortieren - File - Datei + Datei - Files - Dateien + Dateien - Save as... - Speichern unter... + Speichern unter... - HTML-Files (*.htm *.html);;All Files (*) - HTML-Dateien (*.htm *.html);;Alle Dateien (*) + HTML-Dateien (*.htm *.html);;Alle Dateien (*) - - + + Reply to All Allen antworten @@ -7021,27 +7302,27 @@ p, li { white-space: pre-wrap; } - + Content Inhalt + - + Tags Schlagwörter - Tag - Schlagwort + Schlagwort - - + + Trash Papierkorb @@ -7065,7 +7346,7 @@ p, li { white-space: pre-wrap; } Neues Schlagwort... - + Mark as read Als gelesen markieren @@ -7085,34 +7366,33 @@ p, li { white-space: pre-wrap; } Wiederherstellen - + Empty trash Papierkorb leeren - - + + Drafts Entwürfe - + To An - Edit... - Editieren... + Editieren... - + Click to sort by star Klicken, um nach Kennzeichnung zu sortieren - + @@ -9411,13 +9691,13 @@ Lockdatei: Die Datei wurde zur Downloadliste hinzugefügt. - - + + File Request canceled Dateianforderung abgebrochen - + The following has not been added to your download list, because you already have it: Die folgende Datei wurde nicht zur Downloadliste hinzugefügt, da Du diese schon hast: @@ -9564,6 +9844,26 @@ Lockdatei: Start with a RetroShare link is only supported for Windows. Der Start mit einem RetroShare Link wird nur unter Windows unterstützt. + + + (Age in seconds) + + + + + (Depth) + + + + + Evolution of search requests: + + + + + Evolution of tunnel requests: + + QuickStartWizard @@ -12532,14 +12832,14 @@ p, li { white-space: pre-wrap; } TurtleRouterDialog - - + + Search requests Suchanfragen - - + + Tunnel requests Tunnelanfragen @@ -12552,11 +12852,44 @@ p, li { white-space: pre-wrap; } Router Statistiken - + F2F router information F2F Routerinformationen + + TurtleRouterStatisticsWidget + + + Turtle router traffic: + + + + + Tunnel requests Up + + + + + Tunnel requests Dn + + + + + Incoming file data + + + + + Outgoing file data + + + + + Forwarded data + + + ULListDelegate