Move message context menu to a separate module.

This commit is contained in:
John Preston 2018-01-25 13:10:52 +03:00
parent 65df137610
commit fe1a90bd39
24 changed files with 472 additions and 406 deletions

View File

@ -81,7 +81,8 @@ TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities) {
return result;
}
std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(const TextWithEntities &forClipboard) {
std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(
const TextWithEntities &forClipboard) {
if (forClipboard.text.isEmpty()) {
return nullptr;
}
@ -93,11 +94,21 @@ std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(const TextWithEntities &
for (auto &tag : tags) {
tag.id = ConvertTagToMimeTag(tag.id);
}
result->setData(Ui::FlatTextarea::tagsMimeType(), Ui::FlatTextarea::serializeTagsList(tags));
result->setData(
Ui::FlatTextarea::tagsMimeType(),
Ui::FlatTextarea::serializeTagsList(tags));
}
return result;
}
void SetClipboardWithEntities(
const TextWithEntities &forClipboard,
QClipboard::Mode mode) {
if (auto data = MimeDataFromTextWithEntities(forClipboard)) {
QApplication::clipboard()->setMimeData(data.release(), mode);
}
}
MessageField::MessageField(QWidget *parent, not_null<Window::Controller*> controller, const style::FlatTextarea &st, base::lambda<QString()> placeholderFactory, const QString &val) : Ui::FlatTextarea(parent, st, std::move(placeholderFactory), val)
, _controller(controller) {
setMinHeight(st::historySendSize.height() - 2 * st::historySendPadding);

View File

@ -17,8 +17,13 @@ class Controller;
QString ConvertTagToMimeTag(const QString &tagId);
EntitiesInText ConvertTextTagsToEntities(const TextWithTags::Tags &tags);
TextWithTags::Tags ConvertEntitiesToTextTags(const EntitiesInText &entities);
std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(const TextWithEntities &forClipboard);
TextWithTags::Tags ConvertEntitiesToTextTags(
const EntitiesInText &entities);
std::unique_ptr<QMimeData> MimeDataFromTextWithEntities(
const TextWithEntities &forClipboard);
void SetClipboardWithEntities(
const TextWithEntities &forClipboard,
QClipboard::Mode mode = QClipboard::Clipboard);
class MessageField final : public Ui::FlatTextarea {
Q_OBJECT

View File

@ -48,7 +48,8 @@ public:
}
// Copy to clipboard support.
virtual void copyToClipboard() const {
virtual QString copyToClipboardText() const {
return QString();
}
virtual QString copyToClipboardContextItemText() const {
return QString();

View File

@ -15,11 +15,8 @@ public:
TextClickHandler(bool fullDisplayed = true) : _fullDisplayed(fullDisplayed) {
}
void copyToClipboard() const override {
auto u = url();
if (!u.isEmpty()) {
QApplication::clipboard()->setText(u);
}
QString copyToClipboardText() const override {
return url();
}
QString tooltip() const override {

View File

@ -856,7 +856,7 @@ void InnerWidget::keyPressEvent(QKeyEvent *e) {
copySelectedText();
#ifdef Q_OS_MAC
} else if (e->key() == Qt::Key_E && e->modifiers().testFlag(Qt::ControlModifier)) {
setToClipboard(getSelectedText(), QClipboard::FindBuffer);
SetClipboardWithEntities(getSelectedText(), QClipboard::FindBuffer);
#endif // Q_OS_MAC
} else {
e->ignore();
@ -911,7 +911,8 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
HistoryStateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = App::mousedItem()->getState(mousePos, request);
if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) {
if (dragState.cursor == HistoryInTextCursorState
&& base::in_range(dragState.symbol, selFrom, selTo)) {
isUponSelected = 1;
}
}
@ -922,13 +923,13 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_menu = base::make_unique_q<Ui::PopupMenu>(nullptr);
_contextMenuLink = ClickHandler::getActive();
const auto link = ClickHandler::getActive();
auto view = App::hoveredItem()
? App::hoveredItem()
: App::hoveredLinkItem();
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.get());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get());
auto lnkPeer = dynamic_cast<PeerClickHandler*>(_contextMenuLink.get());
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(link.get());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(link.get());
auto lnkPeer = dynamic_cast<PeerClickHandler*>(link.get());
auto lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideoFile() : false;
auto lnkIsVoice = lnkDocument ? lnkDocument->document()->isVoiceMessage() : false;
auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false;
@ -936,22 +937,22 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (isUponSelected > 0) {
_menu->addAction(lang(lng_context_copy_selected), [=] {
copySelectedText();
})->setEnabled(true);
});
}
if (lnkPhoto) {
const auto photo = lnkPhoto->photo();
_menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] {
savePhotoToFile(photo);
}))->setEnabled(true);
}));
_menu->addAction(lang(lng_context_copy_image), [=] {
copyContextImage(photo);
})->setEnabled(true);
});
} else {
auto document = lnkDocument->document();
if (document->loading()) {
_menu->addAction(lang(lng_context_cancel_download), [=] {
cancelContextDownload(document);
})->setEnabled(true);
});
} else {
if (document->loaded() && document->isGifv()) {
if (!cAutoPlayGif()) {
@ -960,17 +961,17 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
: FullMsgId();
_menu->addAction(lang(lng_context_open_gif), [=] {
openContextGif(itemId);
})->setEnabled(true);
});
}
}
if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] {
showContextInFolder(document);
})->setEnabled(true);
});
}
_menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsVoice ? lng_context_save_audio : (lnkIsAudio ? lng_context_save_audio_file : lng_context_save_file))), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}));
}
}
} else if (lnkPeer) { // suggest to block
@ -985,7 +986,7 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
auto msg = dynamic_cast<HistoryMessage*>(item);
if (isUponSelected > 0) {
_menu->addAction(lang(lng_context_copy_selected), [this] { copySelectedText(); })->setEnabled(true);
_menu->addAction(lang(lng_context_copy_selected), [this] { copySelectedText(); });
} else {
if (item && !isUponSelected) {
auto mediaHasTextForCopy = false;
@ -1003,45 +1004,51 @@ void InnerWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
_menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}));
}
} else if (media->type() == MediaTypeGif && !_contextMenuLink) {
} else if (media->type() == MediaTypeGif && !link) {
if (auto document = media->getDocument()) {
if (document->loading()) {
_menu->addAction(lang(lng_context_cancel_download), [=] {
cancelContextDownload(document);
})->setEnabled(true);
});
} else {
if (document->isGifv()) {
if (!cAutoPlayGif()) {
_menu->addAction(lang(lng_context_open_gif), [=] {
openContextGif(itemId);
})->setEnabled(true);
});
}
}
if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] {
showContextInFolder(document);
})->setEnabled(true);
});
}
_menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}));
}
}
}
}
if (msg && !_contextMenuLink && (view->hasVisibleText() || mediaHasTextForCopy)) {
if (msg && !link && (view->hasVisibleText() || mediaHasTextForCopy)) {
_menu->addAction(lang(lng_context_copy_text), [=] {
copyContextText(itemId);
})->setEnabled(true);
});
}
}
}
auto linkCopyToClipboardText = _contextMenuLink ? _contextMenuLink->copyToClipboardContextItemText() : QString();
if (!linkCopyToClipboardText.isEmpty()) {
_menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true);
const auto actionText = link
? link->copyToClipboardContextItemText()
: QString();
if (!actionText.isEmpty()) {
_menu->addAction(
actionText,
[text = link->copyToClipboardText()] {
QApplication::clipboard()->setText(text);
});
}
}
@ -1079,13 +1086,7 @@ void InnerWidget::copyContextImage(PhotoData *photo) {
}
void InnerWidget::copySelectedText() {
setToClipboard(getSelectedText());
}
void InnerWidget::copyContextUrl() {
if (_contextMenuLink) {
_contextMenuLink->copyToClipboard();
}
SetClipboardWithEntities(getSelectedText());
}
void InnerWidget::showStickerPackInfo(not_null<DocumentData*> document) {
@ -1121,19 +1122,11 @@ void InnerWidget::openContextGif(FullMsgId itemId) {
void InnerWidget::copyContextText(FullMsgId itemId) {
if (const auto item = App::histItemById(itemId)) {
if (const auto view = viewForItem(item)) {
setToClipboard(view->selectedText(FullSelection));
SetClipboardWithEntities(view->selectedText(FullSelection));
}
}
}
void InnerWidget::setToClipboard(
const TextWithEntities &forClipboard,
QClipboard::Mode mode) {
if (auto data = MimeDataFromTextWithEntities(forClipboard)) {
QApplication::clipboard()->setMimeData(data.release(), mode);
}
}
void InnerWidget::suggestRestrictUser(not_null<UserData*> user) {
Expects(_menu != nullptr);
@ -1379,7 +1372,9 @@ void InnerWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton but
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
if (_selectedItem && _selectedText.from != _selectedText.to) {
setToClipboard(_selectedItem->selectedText(_selectedText), QClipboard::Selection);
SetClipboardWithEntities(
_selectedItem->selectedText(_selectedText),
QClipboard::Selection);
}
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
}

View File

@ -131,14 +131,12 @@ private:
void saveDocumentToFile(DocumentData *document);
void copyContextImage(PhotoData *photo);
void showStickerPackInfo(not_null<DocumentData*> document);
void copyContextUrl();
void cancelContextDownload(not_null<DocumentData*> document);
void showContextInFolder(not_null<DocumentData*> document);
void openContextGif(FullMsgId itemId);
void copyContextText(FullMsgId itemId);
void copySelectedText();
TextWithEntities getSelectedText() const;
void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard);
void suggestRestrictUser(not_null<UserData*> user);
void restrictUser(not_null<UserData*> user, const MTPChannelBannedRights &oldRights, const MTPChannelBannedRights &newRights);
void restrictUserDone(not_null<UserData*> user, const MTPChannelBannedRights &rights);
@ -242,8 +240,6 @@ private:
QPoint _trippleClickPoint;
base::Timer _trippleClickTimer;
ClickHandlerPtr _contextMenuLink;
FilterValue _filter;
QString _searchQuery;
std::vector<not_null<UserData*>> _admins;

View File

@ -17,9 +17,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/popup_menu.h"
#include "boxes/confirm_box.h"
#include "window/window_controller.h"
#include "data/data_feed_messages.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "storage/storage_feed_messages.h"
#include "styles/style_widgets.h"
#include "styles/style_history.h"

View File

@ -1258,7 +1258,7 @@ void HistoryInner::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton bu
if (!_selected.empty() && _selected.cbegin()->second != FullSelection) {
const auto [item, selection] = *_selected.cbegin();
if (const auto view = item->mainView()) {
setToClipboard(
SetClipboardWithEntities(
view->selectedText(selection),
QClipboard::Selection);
}
@ -1386,9 +1386,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
};
_contextMenuLink = ClickHandler::getActive();
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.get());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get());
const auto link = ClickHandler::getActive();
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(link.get());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(link.get());
auto lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideoFile() : false;
auto lnkIsVoice = lnkDocument ? lnkDocument->document()->isVoiceMessage() : false;
auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false;
@ -1396,42 +1396,42 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto item = _dragStateItem;
const auto itemId = item ? item->fullId() : FullMsgId();
if (isUponSelected > 0) {
_menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
_menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText()));
}
addItemActions(item);
if (lnkPhoto) {
const auto photo = lnkPhoto->photo();
_menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] {
savePhotoToFile(photo);
}))->setEnabled(true);
}));
_menu->addAction(lang(lng_context_copy_image), [=] {
copyContextImage(photo);
})->setEnabled(true);
});
} else {
auto document = lnkDocument->document();
if (document->loading()) {
_menu->addAction(lang(lng_context_cancel_download), [=] {
cancelContextDownload(document);
})->setEnabled(true);
});
} else {
if (document->loaded() && document->isGifv()) {
if (!cAutoPlayGif()) {
_menu->addAction(lang(lng_context_open_gif), [=] {
openContextGif(itemId);
})->setEnabled(true);
});
}
_menu->addAction(lang(lng_context_save_gif), [=] {
saveContextGif(itemId);
})->setEnabled(true);
});
}
if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] {
showContextInFolder(document);
})->setEnabled(true);
});
}
_menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsVoice ? lng_context_save_audio : (lnkIsAudio ? lng_context_save_audio_file : lng_context_save_file))), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] {
saveDocumentToFile(document);
}))->setEnabled(true);
}));
}
}
if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) {
@ -1455,7 +1455,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (item->allowsForward()) {
_menu->addAction(lang(lng_context_forward_msg), [=] {
forwardItem(itemId);
})->setEnabled(true);
});
}
if (item->canDelete()) {
_menu->addAction(lang(lng_context_delete_msg), [=] {
@ -1472,7 +1472,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_widget->updateTopBarSelection();
}
}
})->setEnabled(true);
});
}
}
} else { // maybe cursor on some text history item?
@ -1498,7 +1498,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto msg = dynamic_cast<HistoryMessage*>(item);
if (isUponSelected > 0) {
_menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText()))->setEnabled(true);
_menu->addAction(lang((isUponSelected > 1) ? lng_context_copy_selected_items : lng_context_copy_selected), this, SLOT(copySelectedText()));
addItemActions(item);
} else {
addItemActions(item);
@ -1521,55 +1521,58 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
_menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}));
}
} else if (media->type() == MediaTypeGif && !_contextMenuLink) {
} else if (media->type() == MediaTypeGif && !link) {
if (auto document = media->getDocument()) {
if (document->loading()) {
_menu->addAction(lang(lng_context_cancel_download), [=] {
cancelContextDownload(document);
})->setEnabled(true);
});
} else {
if (document->isGifv()) {
if (!cAutoPlayGif()) {
_menu->addAction(lang(lng_context_open_gif), [=] {
openContextGif(itemId);
})->setEnabled(true);
});
}
_menu->addAction(lang(lng_context_save_gif), [=] {
saveContextGif(itemId);
})->setEnabled(true);
});
}
if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] {
showContextInFolder(document);
})->setEnabled(true);
});
}
_menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}));
}
}
}
}
if (msg && view && !_contextMenuLink && (view->hasVisibleText() || mediaHasTextForCopy)) {
if (msg && view && !link && (view->hasVisibleText() || mediaHasTextForCopy)) {
_menu->addAction(lang(lng_context_copy_text), [=] {
copyContextText(itemId);
})->setEnabled(true);
});
}
}
}
auto linkCopyToClipboardText = _contextMenuLink ? _contextMenuLink->copyToClipboardContextItemText() : QString();
if (!linkCopyToClipboardText.isEmpty()) {
_menu->addAction(linkCopyToClipboardText, this, SLOT(copyContextUrl()))->setEnabled(true);
}
if (linkCopyToClipboardText.isEmpty()) {
if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) {
_menu->addAction(lang(item->history()->peer->isMegagroup() ? lng_context_copy_link : lng_context_copy_post_link), [=] {
_widget->copyPostLink(itemId);
const auto actionText = link
? link->copyToClipboardContextItemText()
: QString();
if (!actionText.isEmpty()) {
_menu->addAction(
actionText,
[text = link->copyToClipboardText()] {
QApplication::clipboard()->setText(text);
});
}
} else if (item && item->hasDirectLink() && isUponSelected != 2 && isUponSelected != -2) {
_menu->addAction(lang(item->history()->peer->isMegagroup() ? lng_context_copy_link : lng_context_copy_post_link), [=] {
_widget->copyPostLink(itemId);
});
}
if (isUponSelected > 1) {
if (selectedState.count > 0 && selectedState.count == selectedState.canForwardCount) {
@ -1586,7 +1589,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (canForward) {
_menu->addAction(lang(lng_context_forward_msg), [=] {
forwardAsGroup(itemId);
})->setEnabled(true);
});
}
if (canDelete) {
@ -1604,7 +1607,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_widget->updateTopBarSelection();
}
}
})->setEnabled(true);
});
}
} else {
if (App::mousedItem()
@ -1619,7 +1622,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_widget->updateTopBarSelection();
}
}
})->setEnabled(true);
});
}
}
}
@ -1633,13 +1636,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
void HistoryInner::copySelectedText() {
setToClipboard(getSelectedText());
}
void HistoryInner::copyContextUrl() {
if (_contextMenuLink) {
_contextMenuLink->copyToClipboard();
}
SetClipboardWithEntities(getSelectedText());
}
void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
@ -1714,17 +1711,11 @@ void HistoryInner::copyContextText(FullMsgId itemId) {
if (const auto item = App::histItemById(itemId)) {
if (const auto view = item->mainView()) {
// #TODO check for a group
setToClipboard(view->selectedText(FullSelection));
SetClipboardWithEntities(view->selectedText(FullSelection));
}
}
}
void HistoryInner::setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode) {
if (auto data = MimeDataFromTextWithEntities(forClipboard)) {
QApplication::clipboard()->setMimeData(data.release(), mode);
}
}
void HistoryInner::resizeEvent(QResizeEvent *e) {
onUpdateSelected();
}
@ -1821,12 +1812,14 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
} else if (e == QKeySequence::Copy && !_selected.empty()) {
copySelectedText();
#ifdef Q_OS_MAC
} else if (e->key() == Qt::Key_E && e->modifiers().testFlag(Qt::ControlModifier)) {
setToClipboard(getSelectedText(), QClipboard::FindBuffer);
} else if (e->key() == Qt::Key_E
&& e->modifiers().testFlag(Qt::ControlModifier)) {
SetClipboardWithEntities(getSelectedText(), QClipboard::FindBuffer);
#endif // Q_OS_MAC
} else if (e == QKeySequence::Delete) {
auto selectedState = getSelectionState();
if (selectedState.count > 0 && selectedState.canDeleteCount == selectedState.count) {
if (selectedState.count > 0
&& selectedState.canDeleteCount == selectedState.count) {
_widget->confirmDeleteSelectedItems();
}
} else {

View File

@ -116,7 +116,6 @@ public slots:
void onUpdateSelected();
void onParentGeometryChanged();
void copyContextUrl();
void copySelectedText();
void onTouchSelect();
@ -222,8 +221,6 @@ private:
not_null<const SelectedItems*> selected,
not_null<Element*> view) const;
void setToClipboard(const TextWithEntities &forClipboard, QClipboard::Mode mode = QClipboard::Clipboard);
void toggleScrollDateShown();
void repaintScrollDateCallback();
bool displayScrollDate() const;
@ -311,8 +308,6 @@ private:
QPoint _trippleClickPoint;
QTimer _trippleClickTimer;
ClickHandlerPtr _contextMenuLink;
Element *_dragSelFrom = nullptr;
Element *_dragSelTo = nullptr;
bool _dragSelecting = false;

View File

@ -297,15 +297,13 @@ ReplyMarkupClickHandler::ReplyMarkupClickHandler(
}
// Copy to clipboard support.
void ReplyMarkupClickHandler::copyToClipboard() const {
QString ReplyMarkupClickHandler::copyToClipboardText() const {
if (auto button = getButton()) {
if (button->type == HistoryMessageMarkupButton::Type::Url) {
auto url = QString::fromUtf8(button->data);
if (!url.isEmpty()) {
QApplication::clipboard()->setText(url);
}
return QString::fromUtf8(button->data);
}
}
return QString();
}
QString ReplyMarkupClickHandler::copyToClipboardContextItemText() const {

View File

@ -184,7 +184,7 @@ public:
}
// Copy to clipboard support.
void copyToClipboard() const override;
QString copyToClipboardText() const override;
QString copyToClipboardContextItemText() const override;
// Finds the corresponding button in the items markup struct.

View File

@ -18,6 +18,10 @@ constexpr auto kMaxHttpRedirects = 5;
} // namespace
QString LocationClickHandler::copyToClipboardText() const {
return _text;
}
QString LocationClickHandler::copyToClipboardContextItemText() const {
return lang(lng_context_copy_link);
}

View File

@ -85,11 +85,7 @@ public:
return _text;
}
void copyToClipboard() const override {
if (!_text.isEmpty()) {
QApplication::clipboard()->setText(_text);
}
}
QString copyToClipboardText() const override;
QString copyToClipboardContextItemText() const override;
private:

View File

@ -0,0 +1,241 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "history/view/history_view_context_menu.h"
#include "history/view/history_view_list_widget.h"
#include "history/history_item.h"
#include "history/history_media_types.h"
#include "ui/widgets/popup_menu.h"
#include "chat_helpers/message_field.h"
#include "data/data_photo.h"
#include "data/data_document.h"
#include "data/data_media_types.h"
#include "core/file_utilities.h"
#include "window/window_peer_menu.h"
#include "lang/lang_keys.h"
#include "messenger.h"
#include "mainwidget.h"
#include "auth_session.h"
namespace HistoryView {
namespace {
void AddToggleGroupingAction(
not_null<Ui::PopupMenu*> menu,
not_null<PeerData*> peer) {
if (const auto channel = peer->asChannel()) {
const auto grouped = (channel->feed() != nullptr);
menu->addAction(
lang(grouped ? lng_feed_ungroup : lng_feed_group),
[=] { Window::ToggleChannelGrouping(channel, !grouped); });
}
}
void SavePhotoToFile(not_null<PhotoData*> photo) {
if (!photo->date || !photo->loaded()) {
return;
}
FileDialog::GetWritePath(
lang(lng_save_photo),
qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter(),
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
base::lambda_guarded(&Auth(), [=](const QString &result) {
if (!result.isEmpty()) {
photo->full->pix().toImage().save(result, "JPG");
}
}));
}
void CopyImage(not_null<PhotoData*> photo) {
if (!photo->date || !photo->loaded()) {
return;
}
QApplication::clipboard()->setPixmap(photo->full->pix());
}
void AddPhotoActions(
not_null<Ui::PopupMenu*> menu,
not_null<PhotoData*> photo) {
menu->addAction(
lang(lng_context_save_image),
App::LambdaDelayed(
st::defaultDropdownMenu.menu.ripple.hideDuration,
&Auth(),
[=] { SavePhotoToFile(photo); }));
menu->addAction(lang(lng_context_copy_image), [=] {
CopyImage(photo);
});
}
void OpenGif(FullMsgId itemId) {
if (const auto item = App::histItemById(itemId)) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
Messenger::Instance().showDocument(document, item);
}
}
}
}
void ShowInFolder(not_null<DocumentData*> document) {
const auto filepath = document->filepath(
DocumentData::FilePathResolveChecked);
if (!filepath.isEmpty()) {
File::ShowInFolder(filepath);
}
}
void AddSaveDocumentAction(
not_null<Ui::PopupMenu*> menu,
not_null<DocumentData*> document) {
menu->addAction(
lang(document->isVideoFile()
? lng_context_save_video
: (document->isVoiceMessage()
? lng_context_save_audio
: (document->isAudioFile()
? lng_context_save_audio_file
: (document->sticker()
? lng_context_save_image
: lng_context_save_file)))),
App::LambdaDelayed(
st::defaultDropdownMenu.menu.ripple.hideDuration,
&Auth(),
[=] { DocumentSaveClickHandler::doSave(document, true); }));
}
void AddDocumentActions(
not_null<Ui::PopupMenu*> menu,
not_null<DocumentData*> document,
FullMsgId contextId) {
if (document->loading()) {
menu->addAction(lang(lng_context_cancel_download), [=] {
document->cancel();
});
return;
}
if (document->loaded() && document->isGifv()) {
if (!cAutoPlayGif()) {
menu->addAction(lang(lng_context_open_gif), [=] {
OpenGif(contextId);
});
}
}
if (!document->filepath(
DocumentData::FilePathResolveChecked).isEmpty()) {
menu->addAction(
lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld)
? lng_context_show_in_finder
: lng_context_show_in_folder),
[=] { ShowInFolder(document); });
}
AddSaveDocumentAction(menu, document);
}
void ShowStickerPackInfo(not_null<DocumentData*> document) {
if (const auto sticker = document->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
App::main()->stickersBox(sticker->set);
}
}
}
} // namespace
base::unique_qptr<Ui::PopupMenu> FillContextMenu(
not_null<ListWidget*> list,
const ContextMenuRequest &request) {
auto result = base::make_unique_q<Ui::PopupMenu>(nullptr);
const auto link = request.link;
const auto view = request.view;
const auto item = view ? view->data().get() : nullptr;
const auto itemId = item ? item->fullId() : FullMsgId();
const auto rawLink = link.get();
const auto linkPhoto = dynamic_cast<PhotoClickHandler*>(rawLink);
const auto linkDocument = dynamic_cast<DocumentClickHandler*>(rawLink);
const auto linkPeer = dynamic_cast<PeerClickHandler*>(rawLink);
const auto photo = linkPhoto ? linkPhoto->photo().get() : nullptr;
const auto document = linkDocument
? linkDocument->document().get()
: nullptr;
const auto isVideoLink = document ? document->isVideoFile() : false;
const auto isVoiceLink = document ? document->isVoiceMessage() : false;
const auto isAudioLink = document ? document->isAudioFile() : false;
const auto hasSelection = !request.selectedItems.empty()
|| !request.selectedText.text.isEmpty();
if (request.overSelection) {
result->addAction(lang(lng_context_copy_selected), [=] {
SetClipboardWithEntities(list->getSelectedText());
});
}
if (linkPhoto) {
AddPhotoActions(result, photo);
} else if (linkDocument) {
AddDocumentActions(result, document, itemId);
} else if (linkPeer) {
if (list->delegate()->listContext() == Context::Feed) {
AddToggleGroupingAction(result, linkPeer->peer());
}
} else { // maybe cursor on some text history item?
bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg());
bool canForward = item && item->allowsForward();
const auto msg = item->toHistoryMessage();
if (!request.overSelection) {
if (item && !hasSelection) {
auto mediaHasTextForCopy = false;
if (auto media = view->media()) {
mediaHasTextForCopy = media->hasTextForCopy();
if (media->type() == MediaTypeWebPage
&& static_cast<HistoryWebPage*>(media)->attach()) {
media = static_cast<HistoryWebPage*>(media)->attach();
}
if (media->type() == MediaTypeSticker) {
if (auto document = media->getDocument()) {
if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) {
result->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] {
ShowStickerPackInfo(document);
});
}
result->addAction(
lang(lng_context_save_image),
App::LambdaDelayed(
st::defaultDropdownMenu.menu.ripple.hideDuration,
list,
[=] { DocumentSaveClickHandler::doSave(document, true); }));
}
}
}
if (!link && (view->hasVisibleText() || mediaHasTextForCopy)) {
result->addAction(lang(lng_context_copy_text), [=] {
SetClipboardWithEntities(list->getItemText(itemId));
});
}
}
}
const auto actionText = link
? link->copyToClipboardContextItemText()
: QString();
if (!actionText.isEmpty()) {
result->addAction(
actionText,
[text = link->copyToClipboardText()] {
QApplication::clipboard()->setText(text);
});
}
}
return result;
}
} // namespace HistoryView

View File

@ -0,0 +1,34 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "base/unique_qptr.h"
namespace Ui {
class PopupMenu;
} // namespace Ui
namespace HistoryView {
class ListWidget;
class Element;
struct ContextMenuRequest {
ClickHandlerPtr link;
Element *view = nullptr;
MessageIdsList selectedItems;
TextWithEntities selectedText;
bool overView = false;
bool overSelection = false;
};
base::unique_qptr<Ui::PopupMenu> FillContextMenu(
not_null<ListWidget*> list,
const ContextMenuRequest &request);
} // namespace

View File

@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_media_types.h"
#include "history/history_message.h"
#include "history/history_item_components.h"
#include "history/view/history_view_context_menu.h"
#include "history/view/history_view_element.h"
#include "history/view/history_view_message.h"
#include "history/view/history_view_service_message.h"
@ -23,7 +24,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_peer_menu.h"
#include "auth_session.h"
#include "ui/widgets/popup_menu.h"
#include "core/file_utilities.h"
#include "core/tl_help.h"
#include "base/overload.h"
#include "lang/lang_keys.h"
@ -273,6 +273,10 @@ ListWidget::ListWidget(
});
}
not_null<ListDelegate*> ListWidget::delegate() const {
return _delegate;
}
void ListWidget::refreshViewer() {
_viewerLifetime.destroy();
_delegate->listSource(
@ -758,10 +762,11 @@ void ListWidget::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape || e->key() == Qt::Key_Back) {
_delegate->listCloseRequest();
} else if (e == QKeySequence::Copy && _selectedItem != nullptr) {
copySelectedText();
SetClipboardWithEntities(getSelectedText());
#ifdef Q_OS_MAC
} else if (e->key() == Qt::Key_E && e->modifiers().testFlag(Qt::ControlModifier)) {
setToClipboard(getSelectedText(), QClipboard::FindBuffer);
} else if (e->key() == Qt::Key_E
&& e->modifiers().testFlag(Qt::ControlModifier)) {
SetClipboardWithEntities(getSelectedText(), QClipboard::FindBuffer);
#endif // Q_OS_MAC
} else {
e->ignore();
@ -800,247 +805,50 @@ void ListWidget::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
mouseActionUpdate(e->globalPos());
}
// -1 - has selection, but no over, 0 - no selection, 1 - over text
auto isUponSelected = 0;
auto hasSelected = 0;
if (_selectedItem) {
isUponSelected = -1;
auto selFrom = _selectedText.from;
auto selTo = _selectedText.to;
hasSelected = (selTo > selFrom) ? 1 : 0;
if (App::mousedItem() && App::mousedItem() == App::hoveredItem()) {
auto mousePos = mapPointToItem(
mapFromGlobal(_mousePosition),
App::mousedItem());
HistoryStateRequest request;
request.flags |= Text::StateRequest::Flag::LookupSymbol;
auto dragState = App::mousedItem()->getState(mousePos, request);
if (dragState.cursor == HistoryInTextCursorState && dragState.symbol >= selFrom && dragState.symbol < selTo) {
isUponSelected = 1;
}
ContextMenuRequest request;
request.link = ClickHandler::getActive();
request.view = App::mousedItem();
request.overView = (request.view == App::hoveredItem());
request.selectedText = getSelectedText();
if (_selectedItem
&& _selectedItem == request.view
&& request.overView) {
const auto mousePos = mapPointToItem(
mapFromGlobal(_mousePosition),
_selectedItem);
HistoryStateRequest stateRequest;
stateRequest.flags |= Text::StateRequest::Flag::LookupSymbol;
const auto dragState = _selectedItem->getState(
mousePos,
stateRequest);
if (dragState.cursor == HistoryInTextCursorState
&& base::in_range(
dragState.symbol,
_selectedText.from,
_selectedText.to)) {
request.overSelection = true;
}
}
if (showFromTouch && hasSelected && isUponSelected < hasSelected) {
isUponSelected = hasSelected;
if (showFromTouch) {
request.overSelection = true;
}
_menu = base::make_unique_q<Ui::PopupMenu>(nullptr);
_contextMenuLink = ClickHandler::getActive();
auto view = App::hoveredItem()
? App::hoveredItem()
: App::hoveredLinkItem();
auto lnkPhoto = dynamic_cast<PhotoClickHandler*>(_contextMenuLink.get());
auto lnkDocument = dynamic_cast<DocumentClickHandler*>(_contextMenuLink.get());
auto lnkPeer = dynamic_cast<PeerClickHandler*>(_contextMenuLink.get());
auto lnkIsVideo = lnkDocument ? lnkDocument->document()->isVideoFile() : false;
auto lnkIsVoice = lnkDocument ? lnkDocument->document()->isVoiceMessage() : false;
auto lnkIsAudio = lnkDocument ? lnkDocument->document()->isAudioFile() : false;
if (lnkPhoto || lnkDocument) {
if (isUponSelected > 0) {
_menu->addAction(lang(lng_context_copy_selected), [=] {
copySelectedText();
})->setEnabled(true);
}
if (lnkPhoto) {
const auto photo = lnkPhoto->photo();
_menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] {
savePhotoToFile(photo);
}))->setEnabled(true);
_menu->addAction(lang(lng_context_copy_image), [=] {
copyContextImage(photo);
})->setEnabled(true);
} else {
auto document = lnkDocument->document();
if (document->loading()) {
_menu->addAction(lang(lng_context_cancel_download), [=] {
cancelContextDownload(document);
})->setEnabled(true);
} else {
if (document->loaded() && document->isGifv()) {
if (!cAutoPlayGif()) {
const auto itemId = view
? view->data()->fullId()
: FullMsgId();
_menu->addAction(lang(lng_context_open_gif), [=] {
openContextGif(itemId);
})->setEnabled(true);
}
}
if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] {
showContextInFolder(document);
})->setEnabled(true);
}
_menu->addAction(lang(lnkIsVideo ? lng_context_save_video : (lnkIsVoice ? lng_context_save_audio : (lnkIsAudio ? lng_context_save_audio_file : lng_context_save_file))), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}
}
} else if (lnkPeer) { // suggest to block
// #TODO suggest restrict peer
if (const auto channel = lnkPeer->peer()->asChannel()) {
const auto grouped = (channel->feed() != nullptr);
_menu->addAction(
lang(grouped ? lng_feed_ungroup : lng_feed_group),
[=] { Window::ToggleChannelGrouping(channel, !grouped); });
}
} else { // maybe cursor on some text history item?
const auto item = view ? view->data().get() : nullptr;
const auto itemId = item ? item->fullId() : FullMsgId();
bool canDelete = item && item->canDelete() && (item->id > 0 || !item->serviceMsg());
bool canForward = item && item->allowsForward();
auto msg = dynamic_cast<HistoryMessage*>(item);
if (isUponSelected > 0) {
_menu->addAction(lang(lng_context_copy_selected), [this] { copySelectedText(); })->setEnabled(true);
} else {
if (item && !isUponSelected) {
auto mediaHasTextForCopy = false;
if (auto media = view->media()) {
mediaHasTextForCopy = media->hasTextForCopy();
if (media->type() == MediaTypeWebPage && static_cast<HistoryWebPage*>(media)->attach()) {
media = static_cast<HistoryWebPage*>(media)->attach();
}
if (media->type() == MediaTypeSticker) {
if (auto document = media->getDocument()) {
if (document->sticker() && document->sticker()->set.type() != mtpc_inputStickerSetEmpty) {
_menu->addAction(lang(document->sticker()->setInstalled() ? lng_context_pack_info : lng_context_pack_add), [=] {
showStickerPackInfo(document);
});
}
_menu->addAction(lang(lng_context_save_image), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}
} else if (media->type() == MediaTypeGif && !_contextMenuLink) {
if (auto document = media->getDocument()) {
if (document->loading()) {
_menu->addAction(lang(lng_context_cancel_download), [=] {
cancelContextDownload(document);
})->setEnabled(true);
} else {
if (document->isGifv()) {
if (!cAutoPlayGif()) {
_menu->addAction(lang(lng_context_open_gif), [=] {
openContextGif(itemId);
})->setEnabled(true);
}
}
if (!document->filepath(DocumentData::FilePathResolveChecked).isEmpty()) {
_menu->addAction(lang((cPlatform() == dbipMac || cPlatform() == dbipMacOld) ? lng_context_show_in_finder : lng_context_show_in_folder), [=] {
showContextInFolder(document);
})->setEnabled(true);
}
_menu->addAction(lang(lng_context_save_file), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [this, document] {
saveDocumentToFile(document);
}))->setEnabled(true);
}
}
}
}
if (!_contextMenuLink && (view->hasVisibleText() || mediaHasTextForCopy)) {
_menu->addAction(lang(lng_context_copy_text), [=] {
copyContextText(itemId);
})->setEnabled(true);
}
}
}
auto linkCopyToClipboardText = _contextMenuLink ? _contextMenuLink->copyToClipboardContextItemText() : QString();
if (!linkCopyToClipboardText.isEmpty()) {
_menu->addAction(linkCopyToClipboardText, [this] { copyContextUrl(); })->setEnabled(true);
}
}
if (_menu->actions().isEmpty()) {
_menu = nullptr;
} else {
_menu = FillContextMenu(this, request);
if (_menu && !_menu->actions().isEmpty()) {
_menu->popup(e->globalPos());
e->accept();
} else if (_menu) {
_menu = nullptr;
}
}
void ListWidget::savePhotoToFile(PhotoData *photo) {
if (!photo || !photo->date || !photo->loaded()) return;
auto filter = qsl("JPEG Image (*.jpg);;") + FileDialog::AllFilesFilter();
FileDialog::GetWritePath(
lang(lng_save_photo),
filter,
filedialogDefaultName(qsl("photo"), qsl(".jpg")),
base::lambda_guarded(this, [this, photo](const QString &result) {
if (!result.isEmpty()) {
photo->full->pix().toImage().save(result, "JPG");
}
}));
}
void ListWidget::saveDocumentToFile(DocumentData *document) {
DocumentSaveClickHandler::doSave(document, true);
}
void ListWidget::copyContextImage(PhotoData *photo) {
if (!photo || !photo->date || !photo->loaded()) return;
QApplication::clipboard()->setPixmap(photo->full->pix());
}
void ListWidget::copySelectedText() {
setToClipboard(getSelectedText());
}
void ListWidget::copyContextUrl() {
if (_contextMenuLink) {
_contextMenuLink->copyToClipboard();
}
}
void ListWidget::showStickerPackInfo(not_null<DocumentData*> document) {
if (auto sticker = document->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
App::main()->stickersBox(sticker->set);
}
}
}
void ListWidget::cancelContextDownload(not_null<DocumentData*> document) {
document->cancel();
}
void ListWidget::showContextInFolder(not_null<DocumentData*> document) {
const auto filepath = document->filepath(
DocumentData::FilePathResolveChecked);
if (!filepath.isEmpty()) {
File::ShowInFolder(filepath);
}
}
void ListWidget::openContextGif(FullMsgId itemId) {
if (const auto item = App::histItemById(itemId)) {
if (auto media = item->media()) {
if (auto document = media->document()) {
Messenger::Instance().showDocument(document, item);
}
}
}
}
void ListWidget::copyContextText(FullMsgId itemId) {
TextWithEntities ListWidget::getItemText(FullMsgId itemId) const {
if (const auto item = App::histItemById(itemId)) {
if (const auto view = viewForItem(item)) {
setToClipboard(view->selectedText(FullSelection));
return view->selectedText(FullSelection);
}
}
}
void ListWidget::setToClipboard(
const TextWithEntities &forClipboard,
QClipboard::Mode mode) {
if (auto data = MimeDataFromTextWithEntities(forClipboard)) {
QApplication::clipboard()->setMimeData(data.release(), mode);
}
return TextWithEntities();
}
void ListWidget::mousePressEvent(QMouseEvent *e) {
@ -1207,7 +1015,9 @@ void ListWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton butt
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
if (_selectedItem && _selectedText.from != _selectedText.to) {
setToClipboard(_selectedItem->selectedText(_selectedText), QClipboard::Selection);
SetClipboardWithEntities(
_selectedItem->selectedText(_selectedText),
QClipboard::Selection);
}
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
}

View File

@ -86,6 +86,8 @@ public:
not_null<Window::Controller*> controller,
not_null<ListDelegate*> delegate);
not_null<ListDelegate*> delegate() const;
// Set the correct scroll position after being resized.
void restoreScrollPosition();
@ -97,6 +99,9 @@ public:
void saveState(not_null<ListMemento*> memento);
void restoreState(not_null<ListMemento*> memento);
TextWithEntities getSelectedText() const;
TextWithEntities getItemText(FullMsgId itemId) const;
// AbstractTooltipShower interface
QString tooltipText() const override;
QPoint tooltipPos() const override;
@ -171,20 +176,7 @@ private:
QPoint mapPointToItem(QPoint point, const Element *view) const;
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
void savePhotoToFile(PhotoData *photo);
void saveDocumentToFile(DocumentData *document);
void copyContextImage(PhotoData *photo);
void showStickerPackInfo(not_null<DocumentData*> document);
void copyContextUrl();
void cancelContextDownload(not_null<DocumentData*> document);
void showContextInFolder(not_null<DocumentData*> document);
void openContextGif(FullMsgId itemId);
void copyContextText(FullMsgId itemId);
void copySelectedText();
TextWithEntities getSelectedText() const;
void setToClipboard(
const TextWithEntities &forClipboard,
QClipboard::Mode mode = QClipboard::Clipboard);
not_null<Element*> findItemByY(int y) const;
Element *strictFindItemByY(int y) const;
@ -277,8 +269,6 @@ private:
QPoint _trippleClickPoint;
base::Timer _trippleClickTimer;
ClickHandlerPtr _contextMenuLink;
rpl::lifetime _viewerLifetime;
};

View File

@ -1283,13 +1283,12 @@ void ListWidget::showContextMenu(
}
}
} else if (link) {
auto linkCopyToClipboardText
= link->copyToClipboardContextItemText();
if (!linkCopyToClipboardText.isEmpty()) {
const auto actionText = link->copyToClipboardContextItemText();
if (!actionText.isEmpty()) {
_contextMenu->addAction(
linkCopyToClipboardText,
[link] {
link->copyToClipboard();
actionText,
[text = link->copyToClipboardText()] {
QApplication::clipboard()->setText(text);
});
}
}
@ -2006,7 +2005,7 @@ void ListWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton butt
#if defined Q_OS_LINUX32 || defined Q_OS_LINUX64
//if (hasSelectedText()) { // #TODO linux clipboard
// setToClipboard(_selected.cbegin()->first->selectedText(_selected.cbegin()->second), QClipboard::Selection);
// SetClipboardWithEntities(_selected.cbegin()->first->selectedText(_selected.cbegin()->second), QClipboard::Selection);
//}
#endif // Q_OS_LINUX32 || Q_OS_LINUX64
}

View File

@ -153,14 +153,14 @@ void MainWindow::firstShow() {
: lng_enable_notifications_from_tray);
if (isLinux) {
trayIconMenu->addAction(lang(lng_open_from_tray), this, SLOT(showFromTray()))->setEnabled(true);
trayIconMenu->addAction(lang(lng_minimize_to_tray), this, SLOT(minimizeToTray()))->setEnabled(true);
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()))->setEnabled(true);
trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray()))->setEnabled(true);
trayIconMenu->addAction(lang(lng_open_from_tray), this, SLOT(showFromTray()));
trayIconMenu->addAction(lang(lng_minimize_to_tray), this, SLOT(minimizeToTray()));
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()));
trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray()));
} else {
trayIconMenu->addAction(lang(lng_minimize_to_tray), this, SLOT(minimizeToTray()))->setEnabled(true);
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()))->setEnabled(true);
trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray()))->setEnabled(true);
trayIconMenu->addAction(lang(lng_minimize_to_tray), this, SLOT(minimizeToTray()));
trayIconMenu->addAction(notificationActionText, this, SLOT(toggleDisplayNotifyFromTray()));
trayIconMenu->addAction(lang(lng_quit_from_tray), this, SLOT(quitFromTray()));
}
Global::RefWorkMode().setForced(Global::WorkMode().value(), true);

View File

@ -2836,7 +2836,7 @@ void MediaView::contextMenuEvent(QContextMenuEvent *e) {
_menu = new Ui::PopupMenu(nullptr, st::mediaviewPopupMenu);
updateActions();
for_const (auto &action, _actions) {
_menu->addAction(action.text, this, action.member)->setEnabled(true);
_menu->addAction(action.text, this, action.member);
}
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
_menu->popup(e->globalPos());

View File

@ -53,8 +53,8 @@ struct TextSelection {
constexpr bool empty() const {
return from == to;
}
uint16 from : 16;
uint16 to : 16;
uint16 from;
uint16 to;
};
inline bool operator==(TextSelection a, TextSelection b) {
return a.from == b.from && a.to == b.to;

View File

@ -536,19 +536,23 @@ void FlatLabel::showContextMenu(QContextMenuEvent *e, ContextMenuReason reason)
_contextMenu = new Ui::PopupMenu(nullptr);
_contextMenuClickHandler = ClickHandler::getActive();
if (fullSelection && !_contextCopyText.isEmpty()) {
_contextMenu->addAction(_contextCopyText, this, SLOT(onCopyContextText()))->setEnabled(true);
_contextMenu->addAction(_contextCopyText, this, SLOT(onCopyContextText()));
} else if (uponSelection && !fullSelection) {
_contextMenu->addAction(lang(lng_context_copy_selected), this, SLOT(onCopySelectedText()))->setEnabled(true);
_contextMenu->addAction(lang(lng_context_copy_selected), this, SLOT(onCopySelectedText()));
} else if (!hasSelection && !_contextCopyText.isEmpty()) {
_contextMenu->addAction(_contextCopyText, this, SLOT(onCopyContextText()))->setEnabled(true);
_contextMenu->addAction(_contextCopyText, this, SLOT(onCopyContextText()));
}
QString linkCopyToClipboardText = _contextMenuClickHandler ? _contextMenuClickHandler->copyToClipboardContextItemText() : QString();
if (!linkCopyToClipboardText.isEmpty()) {
_contextMenu->addAction(linkCopyToClipboardText, this, SLOT(onCopyContextUrl()))->setEnabled(true);
if (const auto link = ClickHandler::getActive()) {
const auto actionText = link->copyToClipboardContextItemText();
if (!actionText.isEmpty()) {
_contextMenu->addAction(
actionText,
[text = link->copyToClipboardText()] {
QApplication::clipboard()->setText(text);
});
}
}
if (_contextMenu->actions().isEmpty()) {
@ -572,12 +576,6 @@ void FlatLabel::onCopyContextText() {
QApplication::clipboard()->setText(_text.originalText({ 0, 0xFFFF }, _contextExpandLinksMode));
}
void FlatLabel::onCopyContextUrl() {
if (_contextMenuClickHandler) {
_contextMenuClickHandler->copyToClipboard();
}
}
void FlatLabel::onTouchSelect() {
_touchSelect = true;
dragActionStart(_touchPos, Qt::LeftButton);

View File

@ -142,7 +142,6 @@ protected:
private slots:
void onCopySelectedText();
void onCopyContextText();
void onCopyContextUrl();
void onTouchSelect();
void onContextMenuDestroy(QObject *obj);
@ -201,7 +200,6 @@ private:
QTimer _trippleClickTimer;
Ui::PopupMenu *_contextMenu = nullptr;
ClickHandlerPtr _contextMenuClickHandler;
QString _contextCopyText;
ExpandLinksMode _contextExpandLinksMode = ExpandLinksAll;

View File

@ -229,6 +229,8 @@
<(src_loc)/history/admin_log/history_admin_log_section.h
<(src_loc)/history/feed/history_feed_section.cpp
<(src_loc)/history/feed/history_feed_section.h
<(src_loc)/history/view/history_view_context_menu.cpp
<(src_loc)/history/view/history_view_context_menu.h
<(src_loc)/history/view/history_view_cursor_state.cpp
<(src_loc)/history/view/history_view_cursor_state.h
<(src_loc)/history/view/history_view_element.cpp