mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Move message context menu to a separate module.
This commit is contained in:
parent
65df137610
commit
fe1a90bd39
24 changed files with 472 additions and 406 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
241
Telegram/SourceFiles/history/view/history_view_context_menu.cpp
Normal file
241
Telegram/SourceFiles/history/view/history_view_context_menu.cpp
Normal 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
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue