/* This file is part of Telegram Desktop, the official desktop version of Telegram messaging app, see https://telegram.org Telegram Desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. In addition, as a special exception, the copyright holders give permission to link the code of portions of this program with the OpenSSL library. Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #include "history/history_item.h" #include "lang/lang_keys.h" #include "mainwidget.h" #include "history/history_service_layout.h" #include "history/history_media_types.h" #include "history/history_media_grouped.h" #include "history/history_message.h" #include "media/media_clip_reader.h" #include "styles/style_dialogs.h" #include "styles/style_history.h" #include "ui/effects/ripple_animation.h" #include "storage/file_upload.h" #include "storage/storage_facade.h" #include "storage/storage_shared_media.h" #include "auth_session.h" #include "media/media_audio.h" #include "messenger.h" #include "mainwindow.h" #include "window/window_controller.h" namespace { // a new message from the same sender is attached to previous within 15 minutes constexpr int kAttachMessageToPreviousSecondsDelta = 900; } // namespace HistoryTextState::HistoryTextState(not_null item) : itemId(item->fullId()) { } HistoryTextState::HistoryTextState( not_null item, const Text::StateResult &state) : itemId(item->fullId()) , cursor(state.uponSymbol ? HistoryInTextCursorState : HistoryDefaultCursorState) , link(state.link) , afterSymbol(state.afterSymbol) , symbol(state.symbol) { } HistoryTextState::HistoryTextState( not_null item, ClickHandlerPtr link) : itemId(item->fullId()) , link(link) { } ReplyMarkupClickHandler::ReplyMarkupClickHandler( int row, int column, FullMsgId context) : _itemId(context) , _row(row) , _column(column) { } // Copy to clipboard support. void ReplyMarkupClickHandler::copyToClipboard() const { if (auto button = getButton()) { if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) { auto url = QString::fromUtf8(button->data); if (!url.isEmpty()) { QApplication::clipboard()->setText(url); } } } } QString ReplyMarkupClickHandler::copyToClipboardContextItemText() const { if (auto button = getButton()) { if (button->type == HistoryMessageReplyMarkup::Button::Type::Url) { return lang(lng_context_copy_link); } } return QString(); } // Finds the corresponding button in the items markup struct. // If the button is not found it returns nullptr. // Note: it is possible that we will point to the different button // than the one was used when constructing the handler, but not a big deal. const HistoryMessageReplyMarkup::Button *ReplyMarkupClickHandler::getButton() const { if (auto item = App::histItemById(_itemId)) { if (auto markup = item->Get()) { if (_row < markup->rows.size()) { auto &row = markup->rows[_row]; if (_column < row.size()) { return &row[_column]; } } } } return nullptr; } void ReplyMarkupClickHandler::onClickImpl() const { if (auto item = App::histItemById(_itemId)) { App::activateBotCommand(item, _row, _column); } } // Returns the full text of the corresponding button. QString ReplyMarkupClickHandler::buttonText() const { if (auto button = getButton()) { return button->text; } return QString(); } ReplyKeyboard::Button::Button() = default; ReplyKeyboard::Button::Button(Button &&other) = default; ReplyKeyboard::Button &ReplyKeyboard::Button::operator=( Button &&other) = default; ReplyKeyboard::Button::~Button() = default; ReplyKeyboard::ReplyKeyboard( not_null item, std::unique_ptr