diff --git a/libretroshare/src/services/p3msgservice.cc b/libretroshare/src/services/p3msgservice.cc index 99682ffae..9347478ea 100644 --- a/libretroshare/src/services/p3msgservice.cc +++ b/libretroshare/src/services/p3msgservice.cc @@ -124,7 +124,55 @@ int p3MsgService::status() return 1; } -int p3MsgService::incomingMsgs() +void p3MsgService::processMsg(RsMsgItem *mi) +{ + mi -> recvTime = time(NULL); + mi -> msgId = getNewUniqueMsgId(); + + std::string mesg; + + RsStackMutex stack(mMsgMtx); /*** STACK LOCKED MTX ***/ + + if (mi -> PeerId() == mConnMgr->getOwnId()) + { + /* from the loopback device */ + mi -> msgFlags |= RS_MSG_FLAGS_OUTGOING; + } + else + { + mi -> msgFlags = RS_MSG_FLAGS_NEW; + + /* from a peer */ + MsgInfoSummary mis; + initRsMIS(mi, mis); + + // msgNotifications.push_back(mis); + pqiNotify *notify = getPqiNotify(); + if (notify) + { + std::string message , title; + notify->AddPopupMessage(RS_POPUP_MSG, mi->PeerId(), + title.assign(mi->subject.begin(), mi->subject.end()), + message.assign(mi->message.begin(),mi->message.end())); + + std::ostringstream out; + out << mi->msgId; + notify->AddFeedItem(RS_FEED_ITEM_MESSAGE, out.str(), "", ""); + } + } + + imsg[mi->msgId] = mi; + RsMsgSrcId* msi = new RsMsgSrcId(); + msi->msgId = mi->msgId; + msi->srcId = mi->PeerId(); + mSrcIds.insert(std::pair(msi->msgId, msi)); + msgChanged.IndicateChanged(); + IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ + + /**** STACK UNLOCKED ***/ +} + +int p3MsgService::incomingMsgs() { RsMsgItem *mi; int i = 0; @@ -134,50 +182,8 @@ int p3MsgService::incomingMsgs() { changed = true ; ++i; - mi -> recvTime = time(NULL); - mi -> msgId = getNewUniqueMsgId(); - std::string mesg; - - RsStackMutex stack(mMsgMtx); /*** STACK LOCKED MTX ***/ - - if (mi -> PeerId() == mConnMgr->getOwnId()) - { - /* from the loopback device */ - mi -> msgFlags |= RS_MSG_FLAGS_OUTGOING; - } - else - { - mi -> msgFlags = RS_MSG_FLAGS_NEW; - - /* from a peer */ - MsgInfoSummary mis; - initRsMIS(mi, mis); - - // msgNotifications.push_back(mis); - pqiNotify *notify = getPqiNotify(); - if (notify) - { - std::string message , title; - notify->AddPopupMessage(RS_POPUP_MSG, mi->PeerId(), - title.assign(mi->subject.begin(), mi->subject.end()), - message.assign(mi->message.begin(),mi->message.end())); - - std::ostringstream out; - out << mi->msgId; - notify->AddFeedItem(RS_FEED_ITEM_MESSAGE, out.str(), "", ""); - } - } - - imsg[mi->msgId] = mi; - RsMsgSrcId* msi = new RsMsgSrcId(); - msi->msgId = mi->msgId; - msi->srcId = mi->PeerId(); - mSrcIds.insert(std::pair(msi->msgId, msi)); - msgChanged.IndicateChanged(); - IndicateConfigChanged(); /**** INDICATE MSG CONFIG CHANGED! *****/ - - /**** STACK UNLOCKED ***/ + processMsg(mi); } if(changed) rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_MESSAGELIST,NOTIFY_TYPE_MOD); @@ -307,8 +313,8 @@ bool p3MsgService::saveList(bool& cleanup, std::list& itemList) for(mit = msgOutgoing.begin(); mit != msgOutgoing.end(); mit++) itemList.push_back(mit->second) ; - for(mit2 = mTags.begin(); mit2 != mTags.end(); mit2++) - itemList.push_back(mit2->second); + for(mit2 = mTags.begin(); mit2 != mTags.end(); mit2++) + itemList.push_back(mit2->second); for(mit3 = mMsgTags.begin(); mit3 != mMsgTags.end(); mit3++) itemList.push_back(mit3->second); @@ -886,7 +892,14 @@ bool p3MsgService::MessageSend(MessageInfo &info) RsMsgItem *msg = initMIRsMsg(info, mConnMgr->getOwnId()); if (msg) { - sendMessage(msg); + /* use processMsg to get the new msgId */ +// sendMessage(msg); + processMsg(msg); + + // return new message id + std::ostringstream out; + out << msg->msgId; + info.msgId = out.str(); } return true; diff --git a/libretroshare/src/services/p3msgservice.h b/libretroshare/src/services/p3msgservice.h index 9968f6efb..aa92ebb63 100644 --- a/libretroshare/src/services/p3msgservice.h +++ b/libretroshare/src/services/p3msgservice.h @@ -105,6 +105,7 @@ int checkOutgoingMessages(); uint32_t getNewUniqueMsgId(); int sendMessage(RsMsgItem *item); int incomingMsgs(); +void processMsg(RsMsgItem *mi); void initRsMI(RsMsgItem *msg, MessageInfo &mi); void initRsMIS(RsMsgItem *msg, MsgInfoSummary &mis); @@ -136,7 +137,7 @@ void initStandardTagTypes(); uint32_t mMsgUniqueId; // used delete msgSrcIds after config save - std::map mSrcIds; + std::map mSrcIds; // save the parent of the messages in draft for replied and forwarded std::map mParentId; diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index 373adf9fa..4ce32b86b 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -269,6 +269,7 @@ HEADERS += rshare.h \ gui/channels/ShareKey.h \ gui/connect/ConfCertDialog.h \ gui/msgs/MessageComposer.h \ + gui/msgs/TagsMenu.h \ gui/msgs/textformat.h \ gui/images/retroshare_win.rc.h \ gui/settings/rsharesettings.h \ @@ -499,6 +500,7 @@ SOURCES += main.cpp \ gui/chat/ChatStyle.cpp \ gui/connect/ConfCertDialog.cpp \ gui/msgs/MessageComposer.cpp \ + gui/msgs/TagsMenu.cpp \ gui/common/vmessagebox.cpp \ gui/common/rwindow.cpp \ gui/common/html.cpp \ diff --git a/retroshare-gui/src/gui/MessagesDialog.cpp b/retroshare-gui/src/gui/MessagesDialog.cpp index 7323b7784..c9724f1da 100644 --- a/retroshare-gui/src/gui/MessagesDialog.cpp +++ b/retroshare-gui/src/gui/MessagesDialog.cpp @@ -20,8 +20,6 @@ ****************************************************************/ #include -#include -#include #include #include #include @@ -30,9 +28,12 @@ #include #include #include +#include +#include #include "MessagesDialog.h" #include "msgs/MessageComposer.h" +#include "msgs/TagsMenu.h" #include "util/printpreview.h" #include "settings/rsharesettings.h" #include "util/misc.h" @@ -45,6 +46,7 @@ #include #include #include +#include #include @@ -85,61 +87,6 @@ #define ROW_SENTBOX 3 #define ROW_TRASHBOX 4 -#define ACTION_TAGSINDEX_SIZE 3 -#define ACTION_TAGSINDEX_TYPE "Type" -#define ACTION_TAGSINDEX_ID "ID" -#define ACTION_TAGSINDEX_COLOR "Color" - -#define ACTION_TAGS_REMOVEALL 0 -#define ACTION_TAGS_TAG 1 -#define ACTION_TAGS_NEWTAG 2 - -class MessagesMenu : public QMenu -{ -public: - MessagesMenu(const QString &title, QWidget *parent) : QMenu (title, parent) - { - } - -protected: - virtual void paintEvent(QPaintEvent *e) - { - QMenu::paintEvent(e); - - QPainter p(this); - QRegion emptyArea = QRegion(rect()); - - //draw the items with color - foreach (QAction *pAction, actions()) { - QRect adjustedActionRect = actionGeometry(pAction); - if (!e->rect().intersects(adjustedActionRect)) - continue; - - const QMap &Values = pAction->data().toMap(); - if (Values.size () != ACTION_TAGSINDEX_SIZE) { - continue; - } - if (Values [ACTION_TAGSINDEX_TYPE] != ACTION_TAGS_TAG) { - continue; - } - - //set the clip region to be extra safe (and adjust for the scrollers) - QRegion adjustedActionReg(adjustedActionRect); - emptyArea -= adjustedActionReg; - p.setClipRegion(adjustedActionReg); - - QStyleOptionMenuItem opt; - initStyleOption(&opt, pAction); - - opt.palette.setColor(QPalette::ButtonText, QColor(Values [ACTION_TAGSINDEX_COLOR].toInt())); - // needed for Cleanlooks - opt.palette.setColor(QPalette::Text, QColor(Values [ACTION_TAGSINDEX_COLOR].toInt())); - - opt.rect = adjustedActionRect; - style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this); - } - } -}; MessagesDialog::LockUpdate::LockUpdate (MessagesDialog *pDialog, bool bUpdate) { @@ -366,6 +313,14 @@ MessagesDialog::MessagesDialog(QWidget *parent) ui.listWidget->setCurrentRow(ROW_INBOX); // 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); + + // fill tags fillTags(); // create timer for navigation @@ -464,95 +419,46 @@ bool MessagesDialog::eventFilter(QObject *obj, QEvent *event) void MessagesDialog::fillTags() { - MsgTagType Tags; - rsMsgs->getMessageTagTypes(Tags); - std::map >::iterator Tag; + MsgTagType tags; + rsMsgs->getMessageTagTypes(tags); + std::map >::iterator tag; - // create tag menu - QMenu *pMenu = new MessagesMenu (tr("Tags"), this); - connect(pMenu, SIGNAL(triggered (QAction*)), this, SLOT(tagTriggered(QAction*))); - connect(pMenu, SIGNAL(aboutToShow()), this, SLOT(tagAboutToShow())); + // fill tags + m_bInChange = true; - bool bUser = false; + // save current selection + QListWidgetItem *item = ui.tagWidget->currentItem(); + uint32_t nSelectecTagId = 0; + if (item) { + nSelectecTagId = item->data(Qt::UserRole).toInt(); + } - QString text; - QAction *pAction; - QMap Values; + QListWidgetItem *itemToSelect = NULL; - if (Tags.types.size()) { - pAction = new QAction(tr("Remove All Tags"), pMenu); - Values [ACTION_TAGSINDEX_TYPE] = ACTION_TAGS_REMOVEALL; - Values [ACTION_TAGSINDEX_ID] = 0; - Values [ACTION_TAGSINDEX_COLOR] = 0; - pAction->setData (Values); - pMenu->addAction(pAction); + QString text; - pMenu->addSeparator(); + ui.tagWidget->clear(); + for (tag = tags.types.begin(); tag != tags.types.end(); tag++) { + text = TagDefs::name(tag->first, tag->second.first); - for (Tag = Tags.types.begin(); Tag != Tags.types.end(); Tag++) { - text = TagDefs::name(Tag->first, Tag->second.first); + item = new QListWidgetItem (text, ui.tagWidget); + item->setForeground(QBrush(QColor(tag->second.second))); + item->setIcon(QIcon(":/images/foldermail.png")); + item->setData(Qt::UserRole, tag->first); + item->setData(Qt::UserRole + 1, text); // for updateMessageSummaryList - pAction = new QAction(text, pMenu); - Values [ACTION_TAGSINDEX_TYPE] = ACTION_TAGS_TAG; - Values [ACTION_TAGSINDEX_ID] = Tag->first; - Values [ACTION_TAGSINDEX_COLOR] = QRgb(Tag->second.second); - pAction->setData (Values); - pAction->setCheckable(true); + if (tag->first == nSelectecTagId) { + itemToSelect = item; + } + } - if (Tag->first >= RS_MSGTAGTYPE_USER && bUser == false) { - bUser = true; - pMenu->addSeparator(); - } + if (itemToSelect) { + ui.tagWidget->setCurrentItem(itemToSelect); + } - pMenu->addAction(pAction); - } + m_bInChange = false; - pMenu->addSeparator(); - } - - pAction = new QAction(tr("New tag ..."), pMenu); - Values [ACTION_TAGSINDEX_TYPE] = ACTION_TAGS_NEWTAG; - Values [ACTION_TAGSINDEX_ID] = 0; - Values [ACTION_TAGSINDEX_COLOR] = 0; - pAction->setData (Values); - pMenu->addAction(pAction); - - ui.tagButton->setMenu(pMenu); - - // fill tags - m_bInChange = true; - - // save current selection - QListWidgetItem *pItem = ui.tagWidget->currentItem(); - uint32_t nSelectecTagId = 0; - if (pItem) { - nSelectecTagId = pItem->data(Qt::UserRole).toInt(); - } - - QListWidgetItem *pItemToSelect = NULL; - - ui.tagWidget->clear(); - for (Tag = Tags.types.begin(); Tag != Tags.types.end(); Tag++) { - text = TagDefs::name(Tag->first, Tag->second.first); - - pItem = new QListWidgetItem (text, ui.tagWidget); - pItem->setForeground(QBrush(QColor(Tag->second.second))); - pItem->setIcon(QIcon(":/images/foldermail.png")); - pItem->setData(Qt::UserRole, Tag->first); - pItem->setData(Qt::UserRole + 1, text); // for updateMessageSummaryList - - if (Tag->first == nSelectecTagId) { - pItemToSelect = pItem; - } - } - - if (pItemToSelect) { - ui.tagWidget->setCurrentItem(pItemToSelect); - } - - m_bInChange = false; - - updateMessageSummaryList(); + updateMessageSummaryList(); } // replaced by shortcut @@ -982,6 +888,8 @@ void MessagesDialog::messagesTagsChanged() fillTags(); insertMessages(); + + showTagLabels(); } static void InitIconAndFont(QStandardItem *pItem [COLUMN_COUNT]) @@ -1533,6 +1441,7 @@ void MessagesDialog::showTagLabels() 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); @@ -2161,113 +2070,69 @@ void MessagesDialog::clearFilter() void MessagesDialog::tagAboutToShow() { - // activate actions from the first selected row - MsgTagInfo tagInfo; + TagsMenu *menu = dynamic_cast(ui.tagButton->menu()); + if (menu == NULL) { + return; + } - QList Rows; - getSelectedMsgCount (&Rows, NULL, NULL); + // activate actions from the first selected row + MsgTagInfo tagInfo; - if (Rows.size()) { - QStandardItem* pItem = MessagesModel->item(Rows [0], COLUMN_DATA); - std::string msgId = pItem->data(ROLE_MSGID).toString().toStdString(); + QList rows; + getSelectedMsgCount (&rows, NULL, NULL); - rsMsgs->getMessageTag(msgId, tagInfo); - } + if (rows.size()) { + QStandardItem* item = MessagesModel->item(rows [0], COLUMN_DATA); + std::string msgId = item->data(ROLE_MSGID).toString().toStdString(); - QMenu *pMenu = ui.tagButton->menu(); + rsMsgs->getMessageTag(msgId, tagInfo); + } - foreach(QObject *pObject, pMenu->children()) { - QAction *pAction = qobject_cast (pObject); - if (pAction == NULL) { - continue; - } - - const QMap &Values = pAction->data().toMap(); - if (Values.size () != ACTION_TAGSINDEX_SIZE) { - continue; - } - if (Values [ACTION_TAGSINDEX_TYPE] != ACTION_TAGS_TAG) { - continue; - } - - std::list::iterator tagId = std::find(tagInfo.tagIds.begin(), tagInfo.tagIds.end(), Values [ACTION_TAGSINDEX_ID]); - pAction->setChecked(tagId != tagInfo.tagIds.end()); - } + menu->activateActions(tagInfo.tagIds); } -void MessagesDialog::tagTriggered(QAction *pAction) +void MessagesDialog::tagRemoveAll() { - if (pAction == NULL) { - return; - } + LockUpdate Lock (this, false); - const QMap &Values = pAction->data().toMap(); - if (Values.size () != ACTION_TAGSINDEX_SIZE) { - return; - } + QList rows; + getSelectedMsgCount (&rows, NULL, NULL); + for (int row = 0; row < rows.size(); row++) { + QStandardItem* item = MessagesModel->item(rows [row], COLUMN_DATA); + std::string msgId = item->data(ROLE_MSGID).toString().toStdString(); - LockUpdate Lock (this, false); + rsMsgs->setMessageTag(msgId, 0, false); + Lock.setUpdate(true); + } - bool bRemoveAll = false; - int nId = 0; - bool bSet = false; + showTagLabels(); - if (Values [ACTION_TAGSINDEX_TYPE] == ACTION_TAGS_REMOVEALL) { - // remove all tags - bRemoveAll = true; - } else if (Values [ACTION_TAGSINDEX_TYPE] == ACTION_TAGS_NEWTAG) { - // new tag - MsgTagType Tags; - rsMsgs->getMessageTagTypes(Tags); + // LockUpdate -> insertMessages(); +} - NewTag TagDlg(Tags); - if (TagDlg.exec() == QDialog::Accepted && TagDlg.m_nId) { - std::map >::iterator Tag = Tags.types.find(TagDlg.m_nId); - if (Tag == Tags.types.end()) { - return; - } - if (rsMsgs->setMessageTagType(Tag->first, Tag->second.first, Tag->second.second) == false) { - return; - } - fillTags(); - nId = TagDlg.m_nId; - bSet = true; - } else { - return; - } - } else if (Values [ACTION_TAGSINDEX_TYPE].toInt() == ACTION_TAGS_TAG) { - nId = Values [ACTION_TAGSINDEX_ID].toInt(); - if (nId == 0) { - return; - } - bSet = pAction->isChecked(); - } else { - return; - } +void MessagesDialog::tagSet(int tagId, bool set) +{ + if (tagId == 0) { + return; + } - QList Rows; - getSelectedMsgCount (&Rows, NULL, NULL); - for (int nRow = 0; nRow < Rows.size(); nRow++) { - QStandardItem* pItem = MessagesModel->item(Rows [nRow], COLUMN_DATA); - std::string msgId = pItem->data(ROLE_MSGID).toString().toStdString(); + LockUpdate Lock (this, false); - if (bRemoveAll) { - // remove all - rsMsgs->setMessageTag(msgId, 0, false); - Lock.setUpdate(true); + QList rows; + getSelectedMsgCount (&rows, NULL, NULL); + for (int row = 0; row < rows.size(); row++) { + QStandardItem* item = MessagesModel->item(rows [row], COLUMN_DATA); + std::string msgId = item->data(ROLE_MSGID).toString().toStdString(); - } else { - // set or unset tag - MsgTagInfo tagInfo; - if (rsMsgs->setMessageTag(msgId, nId, bSet)) { - Lock.setUpdate(true); - } - } - } + if (rsMsgs->setMessageTag(msgId, tagId, set)) { + Lock.setUpdate(true); + } + } - showTagLabels(); - // LockUpdate -> insertMessages(); + showTagLabels(); + + // LockUpdate -> insertMessages(); } void MessagesDialog::emptyTrash() diff --git a/retroshare-gui/src/gui/MessagesDialog.h b/retroshare-gui/src/gui/MessagesDialog.h index 674f984c4..bca95de49 100644 --- a/retroshare-gui/src/gui/MessagesDialog.h +++ b/retroshare-gui/src/gui/MessagesDialog.h @@ -22,19 +22,11 @@ #ifndef _MESSAGESDIALOG_H #define _MESSAGESDIALOG_H -#include -#include -#include #include -#include - -#include #include "mainpage.h" #include "ui_MessagesDialog.h" -#include "settings/NewTag.h" - class MessagesDialog : public MainPage { Q_OBJECT @@ -105,8 +97,9 @@ private slots: void filterColumnChanged(); void clearFilter(); - void tagTriggered(QAction *pAction); void tagAboutToShow(); + void tagSet(int tagId, bool set); + void tagRemoveAll(); private: class LockUpdate diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.cpp b/retroshare-gui/src/gui/msgs/MessageComposer.cpp index 73409f625..d8156fc6b 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.cpp +++ b/retroshare-gui/src/gui/msgs/MessageComposer.cpp @@ -53,8 +53,12 @@ #include "gui/common/Emoticons.h" #include "textformat.h" #include "util/misc.h" +#include "TagsMenu.h" +#include "gui/common/TagDefs.h" +#include "gui/connect/ConfCertDialog.h" -#define IMAGE_GROUP16 ":/images/user/group16.png" +#define IMAGE_GROUP16 ":/images/user/group16.png" +#define IMAGE_FRIENDINFO ":/images/peerdetails_16x16.png" #define COLUMN_CONTACT_NAME 0 #define COLUMN_CONTACT_DATA 0 @@ -161,6 +165,7 @@ MessageComposer::MessageComposer(QWidget *parent, Qt::WFlags flags) connect(ui.msgText->document(), SIGNAL(redoAvailable(bool)), actionRedo, SLOT(setEnabled(bool))); connect(ui.msgFileList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuFileList(QPoint))); + connect(ui.msgSendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuMsgSendList(QPoint))); setWindowModified(ui.msgText->document()->isModified()); actionSave->setEnabled(ui.msgText->document()->isModified()); @@ -182,11 +187,11 @@ MessageComposer::MessageComposer(QWidget *parent, Qt::WFlags flags) connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged())); - connect(ui.addToButton, SIGNAL(clicked(void)), this, SLOT(btnClickEvent())); - connect(ui.addCcButton, SIGNAL(clicked(void)), this, SLOT(btnClickEvent())); - connect(ui.addBccButton, SIGNAL(clicked(void)), this, SLOT(btnClickEvent())); - connect(ui.addRecommendButton, SIGNAL(clicked(void)), this, SLOT(recommendButtonClicked())); - connect(ui.msgSendList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(btnClickEvent())); + connect(ui.addToButton, SIGNAL(clicked(void)), this, SLOT(addTo())); + connect(ui.addCcButton, SIGNAL(clicked(void)), this, SLOT(addCc())); + connect(ui.addBccButton, SIGNAL(clicked(void)), this, SLOT(addBcc())); + connect(ui.addRecommendButton, SIGNAL(clicked(void)), this, SLOT(addRecommend())); + connect(ui.msgSendList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(addTo())); connect(NotifyQt::getInstance(), SIGNAL(groupsChanged(int)), this, SLOT(groupsChanged(int))); connect(NotifyQt::getInstance(), SIGNAL(peerStatusChanged(const QString&,int)), this, SLOT(peerStatusChanged(const QString&,int))); @@ -289,6 +294,14 @@ MessageComposer::MessageComposer(QWidget *parent, Qt::WFlags flags) /* set focus to subject */ ui.titleEdit->setFocus(); + // 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); + setAcceptDrops(true); #ifdef RS_RELEASE_VERSION @@ -473,6 +486,29 @@ void MessageComposer::contextMenuFileList(QPoint) contextMnu.exec(QCursor::pos()); } +void MessageComposer::contextMenuMsgSendList(QPoint) +{ + QMenu contextMnu(this); + + int selectedCount = ui.msgSendList->selectedItems().count(); + + QAction *action = contextMnu.addAction(QIcon(), tr("Add to \"To\""), this, SLOT(addTo())); + action->setEnabled(selectedCount); + action = contextMnu.addAction(QIcon(), tr("Add to \"CC\""), this, SLOT(addCc())); + action->setEnabled(selectedCount); + action = contextMnu.addAction(QIcon(), tr("Add to \"BCC\""), this, SLOT(addBcc())); + action->setEnabled(selectedCount); + action = contextMnu.addAction(QIcon(), tr("Add as Recommend"), this, SLOT(addRecommend())); + action->setEnabled(selectedCount); + + contextMnu.addSeparator(); + + action = contextMnu.addAction(QIcon(IMAGE_FRIENDINFO), tr("Friend Details"), this, SLOT(friendDetails())); + action->setEnabled(selectedCount == 1); + + contextMnu.exec(QCursor::pos()); +} + void MessageComposer::pasteRecommended() { std::vector links; @@ -943,6 +979,12 @@ MessageComposer *MessageComposer::newMsg(const std::string &msgId /*= ""*/) msgComposer->addRecipient(MessageComposer::BCC, *it, false) ; } + MsgTagInfo tagInfo; + rsMsgs->getMessageTag(msgId, tagInfo); + msgComposer->m_tagIds = tagInfo.tagIds; + + msgComposer->showTagLabels(); + msgComposer->ui.msgText->document()->setModified(false); } @@ -1261,6 +1303,25 @@ bool MessageComposer::sendMessage_internal(bool bDraftbox) } } + if (mi.msgId.empty() == false) { + MsgTagInfo tagInfo; + rsMsgs->getMessageTag(mi.msgId, tagInfo); + + /* insert new tags */ + std::list::iterator tag; + for (tag = m_tagIds.begin(); tag != m_tagIds.end(); tag++) { + if (std::find(tagInfo.tagIds.begin(), tagInfo.tagIds.end(), *tag) == tagInfo.tagIds.end()) { + rsMsgs->setMessageTag(mi.msgId, *tag, true); + } else { + tagInfo.tagIds.remove(*tag); + } + } + + /* remove deleted tags */ + for (tag = tagInfo.tagIds.begin(); tag != tagInfo.tagIds.end(); tag++) { + rsMsgs->setMessageTag(mi.msgId, *tag, false); + } + } ui.msgText->document()->setModified(false); return true; } @@ -2302,19 +2363,8 @@ bool MessageComposer::FilterItem(QTreeWidgetItem *pItem, QString &sPattern) return (bVisible || nVisibleChildCount); } -void MessageComposer::btnClickEvent() +void MessageComposer::addContact(enumType type) { - enumType type; - if (QObject::sender() == ui.addToButton || QObject::sender() == ui.msgSendList) { - type = TO; - } else if (QObject::sender() == ui.addCcButton) { - type = CC; - } else if (QObject::sender() == ui.addBccButton) { - type = BCC; - } else { - return; - } - QTreeWidgetItemIterator itemIterator(ui.msgSendList); QTreeWidgetItem *item; while ((item = *itemIterator) != NULL) { @@ -2328,7 +2378,22 @@ void MessageComposer::btnClickEvent() } } -void MessageComposer::recommendButtonClicked() +void MessageComposer::addTo() +{ + addContact(TO); +} + +void MessageComposer::addCc() +{ + addContact(CC); +} + +void MessageComposer::addBcc() +{ + addContact(BCC); +} + +void MessageComposer::addRecommend() { std::list gpgIds; @@ -2375,6 +2440,22 @@ void MessageComposer::recommendButtonClicked() ui.msgText->setFocus(Qt::OtherFocusReason); } +void MessageComposer::friendDetails() +{ + QList selectedItems = ui.msgSendList->selectedItems(); + if (selectedItems.count() != 1) { + return; + } + + QTreeWidgetItem *item = selectedItems[0]; + if (item->type() == TYPE_GROUP) { + return; + } + + std::string id = item->data(COLUMN_CONTACT_DATA, ROLE_CONTACT_ID).toString().toStdString(); + ConfCertDialog::showIt(id, ConfCertDialog::PageDetails); +} + void MessageComposer::dragEnterEvent(QDragEnterEvent *event) { /* print out mimeType */ @@ -2450,3 +2531,78 @@ void MessageComposer::dropEvent(QDropEvent *event) event->setDropAction(Qt::CopyAction); event->accept(); } + +void MessageComposer::tagAboutToShow() +{ + TagsMenu *menu = dynamic_cast(ui.tagButton->menu()); + if (menu == NULL) { + return; + } + + menu->activateActions(m_tagIds); +} + +void MessageComposer::tagRemoveAll() +{ + m_tagIds.clear(); + + showTagLabels(); +} + +void MessageComposer::tagSet(int tagId, bool set) +{ + if (tagId == 0) { + return; + } + + std::list::iterator tag = std::find(m_tagIds.begin(), m_tagIds.end(), tagId); + if (tag == m_tagIds.end()) { + if (set) { + m_tagIds.push_back(tagId); + /* Keep the list sorted */ + m_tagIds.sort(); + } + } else { + if (set == false) { + m_tagIds.remove(tagId); + } + } + + showTagLabels(); +} + +void MessageComposer::clearTagLabels() +{ + /* clear all tags */ + while (tagLabels.size()) { + delete tagLabels.front(); + tagLabels.pop_front(); + } + while (ui.tagLayout->count()) { + delete ui.tagLayout->takeAt(0); + } +} + +void MessageComposer::showTagLabels() +{ + clearTagLabels(); + + if (m_tagIds.empty() == false) { + MsgTagType tags; + rsMsgs->getMessageTagTypes(tags); + + std::map >::iterator tag; + for (std::list::iterator tagId = m_tagIds.begin(); tagId != m_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(); + } +} diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.h b/retroshare-gui/src/gui/msgs/MessageComposer.h index a9b111a3f..fc34dfc28 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.h +++ b/retroshare-gui/src/gui/msgs/MessageComposer.h @@ -88,6 +88,7 @@ private slots: void contextMenu(QPoint); void pasteLink(); void contextMenuFileList(QPoint); + void contextMenuMsgSendList(QPoint); void pasteRecommended(); void on_contactsdockWidget_visibilityChanged(bool visible); void toggleContacts(); @@ -135,16 +136,24 @@ private slots: void titleChanged(); // Add to To/Cc/Bcc address fields - void btnClickEvent(); - void recommendButtonClicked(); + void addTo(); + void addCc(); + void addBcc(); + void addRecommend(); void editingRecipientFinished(); + void friendDetails(); void groupsChanged(int type); void peerStatusChanged(const QString& peer_id, int status); + void tagAboutToShow(); + void tagSet(int tagId, bool set); + void tagRemoveAll(); + private: void processSettings(bool bLoad); + void addContact(enumType type); void setTextColor(const QColor& col) ; void setupFileActions(); void setupEditActions(); @@ -173,6 +182,9 @@ private: bool getRecipientFromRow(int row, enumType &type, std::string &id, bool &group); void setRecipientToRow(int row, enumType type, std::string id, bool group); + void clearTagLabels(); + void showTagLabels(); + QAction *actionSave, *actionAlignLeft, *actionAlignCenter, @@ -201,6 +213,8 @@ private: std::string m_msgParentId; // parent message id std::string m_sDraftMsgId; // existing message id enumMessageType m_msgType; + std::list m_tagIds; + QList tagLabels; /* maps of files */ std::list mAttachments; diff --git a/retroshare-gui/src/gui/msgs/MessageComposer.ui b/retroshare-gui/src/gui/msgs/MessageComposer.ui index ede171600..516aa5ac9 100644 --- a/retroshare-gui/src/gui/msgs/MessageComposer.ui +++ b/retroshare-gui/src/gui/msgs/MessageComposer.ui @@ -17,7 +17,7 @@ Compose - + :/images/folder-draft.png:/images/folder-draft.png @@ -168,6 +168,9 @@ border-image: url(:/images/closepressed.png) 0 + + Qt::CustomContextMenu + QAbstractItemView::ExtendedSelection @@ -394,7 +397,7 @@ border: 1px solid #CCCCCC;} - + :/images/textedit/format_font_size_more.png:/images/textedit/format_font_size_more.png @@ -426,7 +429,7 @@ border: 1px solid #CCCCCC;} - + :/images/textedit/format_font_size_less.png:/images/textedit/format_font_size_less.png @@ -464,7 +467,7 @@ border: 1px solid #CCCCCC;} - + :/images/textedit/textbold.png:/images/textedit/textbold.png @@ -505,7 +508,7 @@ border: 1px solid #CCCCCC;} - + :/images/textedit/textitalic.png:/images/textedit/textitalic.png @@ -611,7 +614,7 @@ border: 1px solid #CCCCCC;} - + :/images/add_image24.png:/images/add_image24.png @@ -637,7 +640,7 @@ border: 1px solid #CCCCCC;} - + :/images/textedit/hi22-action-format-text-code.png:/images/textedit/hi22-action-format-text-code.png @@ -670,7 +673,7 @@ border: 1px solid #CCCCCC;} Qt::NoFocus - + :/images/emoticons/kopete/kopete020.png:/images/emoticons/kopete/kopete020.png @@ -708,7 +711,7 @@ border: 1px solid #CCCCCC;} - + :/images/textedit/textunder.png:/images/textedit/textunder.png @@ -746,33 +749,6 @@ border: 1px solid #CCCCCC;} - - - - 6 - - - QLayout::SetNoConstraint - - - - - - 10 - 75 - true - - - - Subject: - - - - - - - - @@ -819,6 +795,72 @@ border: 1px solid #CCCCCC;} + + + + QLayout::SetNoConstraint + + + + + Subject: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Tags: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Tags + + + + :/images/tag24.png:/images/tag24.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + @@ -964,7 +1006,7 @@ border: 1px solid #CCCCCC;} - + :/images/send24.png:/images/send24.png @@ -976,7 +1018,7 @@ border: 1px solid #CCCCCC;} - + :/images/replymail24.png:/images/replymail24.png @@ -985,7 +1027,7 @@ border: 1px solid #CCCCCC;} - + :/images/contacts24.png:/images/contacts24.png @@ -997,7 +1039,7 @@ border: 1px solid #CCCCCC;} - + :/images/save24.png:/images/save24.png @@ -1009,7 +1051,7 @@ border: 1px solid #CCCCCC;} - + :/images/attach.png:/images/attach.png @@ -1024,7 +1066,7 @@ border: 1px solid #CCCCCC;} true - + :/images/quote_24.png:/images/quote_24.png @@ -1051,8 +1093,6 @@ border: 1px solid #CCCCCC;} comboFont hashBox - - - + diff --git a/retroshare-gui/src/gui/msgs/TagsMenu.cpp b/retroshare-gui/src/gui/msgs/TagsMenu.cpp new file mode 100644 index 000000000..cc4fcc181 --- /dev/null +++ b/retroshare-gui/src/gui/msgs/TagsMenu.cpp @@ -0,0 +1,199 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2006,2007 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 "TagsMenu.h" +#include "gui/common/TagDefs.h" +#include "gui/settings/NewTag.h" +#include "gui/notifyqt.h" + +#define ACTION_TAGSINDEX_SIZE 3 +#define ACTION_TAGSINDEX_TYPE "Type" +#define ACTION_TAGSINDEX_ID "ID" +#define ACTION_TAGSINDEX_COLOR "Color" + +#define ACTION_TAGS_REMOVEALL 0 +#define ACTION_TAGS_TAG 1 +#define ACTION_TAGS_NEWTAG 2 + +TagsMenu::TagsMenu(const QString &title, QWidget *parent) + : QMenu (title, parent) +{ + connect(this, SIGNAL(triggered (QAction*)), this, SLOT(tagTriggered(QAction*))); + connect(NotifyQt::getInstance(), SIGNAL(messagesTagsChanged()), this, SLOT(fillTags())); + + fillTags(); +} + +void TagsMenu::paintEvent(QPaintEvent *e) +{ + QMenu::paintEvent(e); + + QPainter p(this); + QRegion emptyArea = QRegion(rect()); + + //draw the items with color + foreach (QAction *action, actions()) { + QRect adjustedActionRect = actionGeometry(action); + if (!e->rect().intersects(adjustedActionRect)) + continue; + + const QMap &values = action->data().toMap(); + if (values.size () != ACTION_TAGSINDEX_SIZE) { + continue; + } + if (values [ACTION_TAGSINDEX_TYPE] != ACTION_TAGS_TAG) { + continue; + } + + //set the clip region to be extra safe (and adjust for the scrollers) + QRegion adjustedActionReg(adjustedActionRect); + emptyArea -= adjustedActionReg; + p.setClipRegion(adjustedActionReg); + + QStyleOptionMenuItem opt; + initStyleOption(&opt, action); + + opt.palette.setColor(QPalette::ButtonText, QColor(values [ACTION_TAGSINDEX_COLOR].toInt())); + // needed for Cleanlooks + opt.palette.setColor(QPalette::Text, QColor(values [ACTION_TAGSINDEX_COLOR].toInt())); + + opt.rect = adjustedActionRect; + style()->drawControl(QStyle::CE_MenuItem, &opt, &p, this); + } +} + +void TagsMenu::fillTags() +{ + clear(); + + MsgTagType tags; + rsMsgs->getMessageTagTypes(tags); + std::map >::iterator tag; + + bool user = false; + + QString text; + QAction *action; + QMap values; + + if (tags.types.size()) { + action = new QAction(tr("Remove All Tags"), this); + values [ACTION_TAGSINDEX_TYPE] = ACTION_TAGS_REMOVEALL; + values [ACTION_TAGSINDEX_ID] = 0; + values [ACTION_TAGSINDEX_COLOR] = 0; + action->setData (values); + addAction(action); + + addSeparator(); + + for (tag = tags.types.begin(); tag != tags.types.end(); tag++) { + text = TagDefs::name(tag->first, tag->second.first); + + action = new QAction(text, this); + values [ACTION_TAGSINDEX_TYPE] = ACTION_TAGS_TAG; + values [ACTION_TAGSINDEX_ID] = tag->first; + values [ACTION_TAGSINDEX_COLOR] = QRgb(tag->second.second); + action->setData (values); + action->setCheckable(true); + + if (tag->first >= RS_MSGTAGTYPE_USER && user == false) { + user = true; + addSeparator(); + } + + addAction(action); + } + + addSeparator(); + } + + action = new QAction(tr("New tag ..."), this); + values [ACTION_TAGSINDEX_TYPE] = ACTION_TAGS_NEWTAG; + values [ACTION_TAGSINDEX_ID] = 0; + values [ACTION_TAGSINDEX_COLOR] = 0; + action->setData (values); + addAction(action); +} + +void TagsMenu::activateActions(std::list& tagIds) +{ + foreach(QObject *object, children()) { + QAction *action = qobject_cast (object); + if (action == NULL) { + continue; + } + + const QMap &values = action->data().toMap(); + if (values.size () != ACTION_TAGSINDEX_SIZE) { + continue; + } + if (values [ACTION_TAGSINDEX_TYPE] != ACTION_TAGS_TAG) { + continue; + } + + std::list::iterator tagId = std::find(tagIds.begin(), tagIds.end(), values [ACTION_TAGSINDEX_ID]); + action->setChecked(tagId != tagIds.end()); + } +} + +void TagsMenu::tagTriggered(QAction *action) +{ + if (action == NULL) { + return; + } + + const QMap &values = action->data().toMap(); + if (values.size () != ACTION_TAGSINDEX_SIZE) { + return; + } + + if (values [ACTION_TAGSINDEX_TYPE] == ACTION_TAGS_REMOVEALL) { + // remove all tags + emit tagRemoveAll(); + } else if (values [ACTION_TAGSINDEX_TYPE] == ACTION_TAGS_NEWTAG) { + // new tag + MsgTagType tags; + rsMsgs->getMessageTagTypes(tags); + + NewTag tagDlg(tags); + if (tagDlg.exec() == QDialog::Accepted && tagDlg.m_nId) { + std::map >::iterator tag = tags.types.find(tagDlg.m_nId); + if (tag != tags.types.end()) { + if (rsMsgs->setMessageTagType(tag->first, tag->second.first, tag->second.second)) { + emit tagSet(tagDlg.m_nId, true); + } + } + } + } else if (values [ACTION_TAGSINDEX_TYPE].toInt() == ACTION_TAGS_TAG) { + int tagId = values [ACTION_TAGSINDEX_ID].toInt(); + if (tagId) { + emit tagSet(tagId, action->isChecked()); + } + } +} diff --git a/retroshare-gui/src/gui/msgs/TagsMenu.h b/retroshare-gui/src/gui/msgs/TagsMenu.h new file mode 100644 index 000000000..142b48a57 --- /dev/null +++ b/retroshare-gui/src/gui/msgs/TagsMenu.h @@ -0,0 +1,48 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2007, 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 _TAGSMENU_H +#define _TAGSMENU_H + +#include + +class TagsMenu : public QMenu +{ + Q_OBJECT + +public: + TagsMenu(const QString &title, QWidget *parent); + + void activateActions(std::list& tagIds); + +signals: + void tagSet(int tagId, bool set); + void tagRemoveAll(); + +protected: + virtual void paintEvent(QPaintEvent *e); + +private slots: + void fillTags(); + void tagTriggered(QAction *action); +}; + +#endif diff --git a/retroshare-gui/src/gui/settings/MessagePage.cpp b/retroshare-gui/src/gui/settings/MessagePage.cpp index 1f6a5e7b1..5e6ab761b 100644 --- a/retroshare-gui/src/gui/settings/MessagePage.cpp +++ b/retroshare-gui/src/gui/settings/MessagePage.cpp @@ -28,7 +28,6 @@ #include -#include "../MainWindow.h" #include "NewTag.h" MessagePage::MessagePage(QWidget * parent, Qt::WFlags flags) diff --git a/retroshare-gui/src/lang/retroshare_de.qm b/retroshare-gui/src/lang/retroshare_de.qm index d1e5d3f7f..0a472b90d 100644 Binary files a/retroshare-gui/src/lang/retroshare_de.qm and b/retroshare-gui/src/lang/retroshare_de.qm differ diff --git a/retroshare-gui/src/lang/retroshare_de.ts b/retroshare-gui/src/lang/retroshare_de.ts index d9c2f19a5..0b2ba0727 100644 --- a/retroshare-gui/src/lang/retroshare_de.ts +++ b/retroshare-gui/src/lang/retroshare_de.ts @@ -1440,7 +1440,7 @@ p, li { white-space: pre-wrap; } ConfCertDialog - + Cancel Abbrechen @@ -1450,7 +1450,7 @@ p, li { white-space: pre-wrap; } OK - + Peer Info Nachbar Info @@ -1470,7 +1470,7 @@ p, li { white-space: pre-wrap; } Peer ID - + Peer Address Adresse des Nachbarn @@ -1511,7 +1511,7 @@ p, li { white-space: pre-wrap; } Nachbar Schlüssel ist unterzeichnet von: - + Last Contact Letzter Kontakt @@ -1531,7 +1531,7 @@ p, li { white-space: pre-wrap; } Ort - + Status Status @@ -1600,18 +1600,18 @@ p, li { white-space: pre-wrap; } - + RetroShare - - + + Error : cannot get peer details. Fehler: Kann Peer Details nicht ermitteln. - + Your key is signed by : Ihr Schlüssel ist unterzeichnet von: @@ -1658,7 +1658,7 @@ und meinen GPG Schlüssel unterzeichnet und meinen GPG Schlüssel nicht unterzeichnet - + Signature Failure Signatur Fehler @@ -1683,17 +1683,16 @@ und meinen GPG Schlüssel nicht unterzeichnet Zeige Hilfe - + RetroShare ID - Copy Peer - Kopiere Nachbar + Kopiere Nachbar - + Certificate Zertifikat @@ -5652,18 +5651,18 @@ Bitte gib etwas Speicher frei und drücke OK. MessageComposer - + Compose Verfassen - + Contacts Kontakte - + Search for Name: Suche Name: @@ -5673,7 +5672,7 @@ Bitte gib etwas Speicher frei und drücke OK. Zurücksetzen - + Send To: Senden an: @@ -5693,22 +5692,22 @@ Bitte gib etwas Speicher frei und drücke OK. >> Bcc - + Subject: Betreff: - + Paragraph Absatz - + Search Friends Suche Freunde - + >> Recommend >> Empfehlen @@ -5769,7 +5768,18 @@ Bitte gib etwas Speicher frei und drücke OK. Unterstrichen - + + Tags: + Schlagwörter: + + + + + Tags + Schlagwörter + + + Italic Kursiv @@ -5794,7 +5804,7 @@ Bitte gib etwas Speicher frei und drücke OK. Setzt Schriftart auf Codestil - + To An @@ -5809,7 +5819,7 @@ Bitte gib etwas Speicher frei und drücke OK. Bcc - + Recommended Files Empfohlene Dateien @@ -5879,7 +5889,7 @@ Bitte gib etwas Speicher frei und drücke OK. Blockquote hinzufügen - + &Left &Links @@ -5899,13 +5909,13 @@ Bitte gib etwas Speicher frei und drücke OK. &Blocksatz - - + + Save Message Nachricht speichern - + Message has not been Sent. Do you want to save message to draft box? Nachricht wurde noch nicht gesendet. @@ -5918,7 +5928,32 @@ Möchtest Du die Nachricht in den Entwürfen speichern? RetroShare Link einfügen - + + Add to "To" + Zu "An" hinzufügen + + + + Add to "CC" + Zu "Cc" hinzufügen + + + + Add to "BCC" + Zu "Bcc" hinzufügen + + + + Add as Recommend + Als empfohlen hinzufügen + + + + Friend Details + Freund-Details + + + Re: Re: @@ -5944,7 +5979,7 @@ Möchtest Du die Nachricht in den Entwürfen speichern? Bitte geben sie mindestens einen Empfänger ein. - + Unknown Unbekannt @@ -6107,7 +6142,7 @@ Willst Du die Nachricht speichern ? Zusätzliche Datei hinzufügen - + Drop file error. Dateifehler bei Drag'n'Drop. @@ -6123,7 +6158,7 @@ Willst Du die Nachricht speichern ? Datei nicht gefunden oder Dateiname nicht akzeptiert. - + Friend Recommendation(s) Freundempfehlung(en) @@ -6176,7 +6211,7 @@ Willst Du die Nachricht speichern ? Standard - + Edit Tag Schlagwort bearbeiten @@ -6208,7 +6243,7 @@ Willst Du die Nachricht speichern ? MessagesDialog - + New Message Neue Nachricht @@ -6224,14 +6259,14 @@ Willst Du die Nachricht speichern ? - + Date Datum - + From Von @@ -6316,15 +6351,15 @@ p, li { white-space: pre-wrap; } - + Inbox Posteingang - - + + Outbox Postausgang @@ -6336,7 +6371,7 @@ p, li { white-space: pre-wrap; } - + Sent Gesendet @@ -6403,13 +6438,13 @@ p, li { white-space: pre-wrap; } Speichern unter... - + Print Document Dokument drucken - + Subject Betreff @@ -6444,12 +6479,12 @@ p, li { white-space: pre-wrap; } Drucken - + Forward selected Message Gewählte Nachricht weiterleiten - + Remove Messages Löschen @@ -6459,31 +6494,38 @@ p, li { white-space: pre-wrap; } Weiterleiten + Click to sort by attachments - Klicken, um nach Anhang zu sortieren + Klicken, um nach Anhang zu sortieren + Click to sort by subject - Klicken, um nach Betreff zu sortieren + Klicken, um nach Betreff zu sortieren + Click to sort by read - Klicken, um nach Gelesen / Ungelesen zu sortieren + Klicken, um nach Gelesen / Ungelesen zu sortieren + + Click to sort by from - Klicken, um nach Von zu sortieren + Klicken, um nach Von zu sortieren + Click to sort by date - Klicken, um nach Datum zu sortieren + Klicken, um nach Datum zu sortieren + Click to sort by tags - Klicken, um nach Schlagwörter zu sortieren + Klicken, um nach Schlagwörter zu sortieren - + Download Herunterladen @@ -6498,11 +6540,12 @@ p, li { white-space: pre-wrap; } Empfohlene Dateien einblenden + Click to sort by to - Klicken, um nach Empfänger zu sortieren + Klicken, um nach Empfänger zu sortieren - + File Datei @@ -6522,8 +6565,8 @@ p, li { white-space: pre-wrap; } HTML-Dateien (*.htm *.html);;Alle Dateien (*) - - + + Reply to All Allen antworten @@ -6541,7 +6584,7 @@ p, li { white-space: pre-wrap; } - + Content Inhalt @@ -6549,7 +6592,7 @@ p, li { white-space: pre-wrap; } - + Tags Schlagwörter @@ -6560,8 +6603,8 @@ p, li { white-space: pre-wrap; } - - + + Trash Papierkorb @@ -6577,17 +6620,15 @@ p, li { white-space: pre-wrap; } Ordner - Remove All Tags - Alle Schlagwörter entfernen + Alle Schlagwörter entfernen - New tag ... - Neues Schlagwort... + Neues Schlagwort... - + Mark as read Als gelesen markieren @@ -6608,23 +6649,23 @@ p, li { white-space: pre-wrap; } - + Drafts Entwürfe - + To An - + Edit... Editieren... - + @@ -9019,7 +9060,7 @@ Lockdatei: Vielleicht ist das Passwort falsch - + File Request Confirmation Bestätigung der Dateianforderung @@ -9029,7 +9070,7 @@ Lockdatei: Die Datei wurde zur Downloadliste hinzugefügt. - + File Request canceled Dateianforderung abgebrochen @@ -9048,17 +9089,17 @@ Lockdatei: - + Friend Request Confirmation Freundanfrage bestätigen - + The friend is already in your list. Der Freund ist schon in Deiner Liste. - + The friend has been added to your list. Der Freund wurde zu Deiner Liste hinzugefügt. @@ -11490,6 +11531,19 @@ p, li { white-space: pre-wrap; } Später + + TagsMenu + + + Remove All Tags + Alle Schlagwörter entfernen + + + + New tag ... + Neues Schlagwort... + + TextPage