1 /*
2 This file is part of Telegram Desktop,
3 the official desktop application for the Telegram messaging service.
4 
5 For license and copyright information please follow this link:
6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
7 */
8 #pragma once
9 
10 #include "history/view/history_view_element.h"
11 #include "history/admin_log/history_admin_log_item.h"
12 #include "history/admin_log/history_admin_log_section.h"
13 #include "ui/rp_widget.h"
14 #include "ui/effects/animations.h"
15 #include "ui/widgets/tooltip.h"
16 #include "mtproto/sender.h"
17 #include "base/timer.h"
18 
19 struct ChatRestrictionsInfo;
20 
21 namespace Data {
22 class CloudImageView;
23 } // namespace Data
24 
25 namespace Main {
26 class Session;
27 } // namespace Main
28 
29 namespace HistoryView {
30 class Element;
31 struct TextState;
32 struct StateRequest;
33 enum class CursorState : char;
34 enum class PointState : char;
35 } // namespace HistoryView
36 
37 namespace Ui {
38 class PopupMenu;
39 class ChatStyle;
40 } // namespace Ui
41 
42 namespace Window {
43 class SessionController;
44 } // namespace Window
45 
46 namespace AdminLog {
47 
48 class SectionMemento;
49 
50 class InnerWidget final
51 	: public Ui::RpWidget
52 	, public Ui::AbstractTooltipShower
53 	, public HistoryView::ElementDelegate
54 	, private base::Subscriber {
55 public:
56 	InnerWidget(
57 		QWidget *parent,
58 		not_null<Window::SessionController*> controller,
59 		not_null<ChannelData*> channel);
60 
61 	[[nodiscard]] Main::Session &session() const;
theme()62 	[[nodiscard]] not_null<Ui::ChatTheme*> theme() const {
63 		return _theme.get();
64 	}
65 
66 	[[nodiscard]] rpl::producer<> showSearchSignal() const;
67 	[[nodiscard]] rpl::producer<int> scrollToSignal() const;
68 	[[nodiscard]] rpl::producer<> cancelSignal() const;
69 
channel()70 	[[nodiscard]] not_null<ChannelData*> channel() const {
71 		return _channel;
72 	}
73 
74 	// Set the correct scroll position after being resized.
75 	void restoreScrollPosition();
76 
resizeToWidth(int newWidth,int minHeight)77 	void resizeToWidth(int newWidth, int minHeight) {
78 		_minHeight = minHeight;
79 		return TWidget::resizeToWidth(newWidth);
80 	}
81 
82 	void saveState(not_null<SectionMemento*> memento);
83 	void restoreState(not_null<SectionMemento*> memento);
84 
85 	// Empty "flags" means all events.
86 	void applyFilter(FilterValue &&value);
87 	void applySearch(const QString &query);
88 	void showFilter(Fn<void(FilterValue &&filter)> callback);
89 
90 	// Ui::AbstractTooltipShower interface.
91 	QString tooltipText() const override;
92 	QPoint tooltipPos() const override;
93 	bool tooltipWindowActive() const override;
94 
95 	// HistoryView::ElementDelegate interface.
96 	HistoryView::Context elementContext() override;
97 	std::unique_ptr<HistoryView::Element> elementCreate(
98 		not_null<HistoryMessage*> message,
99 		HistoryView::Element *replacing = nullptr) override;
100 	std::unique_ptr<HistoryView::Element> elementCreate(
101 		not_null<HistoryService*> message,
102 		HistoryView::Element *replacing = nullptr) override;
103 	bool elementUnderCursor(
104 		not_null<const HistoryView::Element*> view) override;
105 	crl::time elementHighlightTime(
106 		not_null<const HistoryItem*> item) override;
107 	bool elementInSelectionMode() override;
108 	bool elementIntersectsRange(
109 		not_null<const HistoryView::Element*> view,
110 		int from,
111 		int till) override;
112 	void elementStartStickerLoop(
113 		not_null<const HistoryView::Element*> view) override;
114 	void elementShowPollResults(
115 		not_null<PollData*> poll,
116 		FullMsgId context) override;
117 	void elementOpenPhoto(
118 		not_null<PhotoData*> photo,
119 		FullMsgId context) override;
120 	void elementOpenDocument(
121 		not_null<DocumentData*> document,
122 		FullMsgId context,
123 		bool showInMediaView = false) override;
124 	void elementCancelUpload(const FullMsgId &context) override;
125 	void elementShowTooltip(
126 		const TextWithEntities &text,
127 		Fn<void()> hiddenCallback) override;
128 	bool elementIsGifPaused() override;
129 	bool elementHideReply(
130 		not_null<const HistoryView::Element*> view) override;
131 	bool elementShownUnread(
132 		not_null<const HistoryView::Element*> view) override;
133 	void elementSendBotCommand(
134 		const QString &command,
135 		const FullMsgId &context) override;
136 	void elementHandleViaClick(not_null<UserData*> bot) override;
137 	bool elementIsChatWide() override;
138 	not_null<Ui::PathShiftGradient*> elementPathShiftGradient() override;
139 	void elementReplyTo(const FullMsgId &to) override;
140 	void elementStartInteraction(
141 		not_null<const HistoryView::Element*> view) override;
142 
143 	~InnerWidget();
144 
145 protected:
146 	void visibleTopBottomUpdated(
147 		int visibleTop,
148 		int visibleBottom) override;
149 
150 	void paintEvent(QPaintEvent *e) override;
151 	void keyPressEvent(QKeyEvent *e) override;
152 	void mousePressEvent(QMouseEvent *e) override;
153 	void mouseMoveEvent(QMouseEvent *e) override;
154 	void mouseReleaseEvent(QMouseEvent *e) override;
155 	void mouseDoubleClickEvent(QMouseEvent *e) override;
156 	void enterEventHook(QEnterEvent *e) override;
157 	void leaveEventHook(QEvent *e) override;
158 	void contextMenuEvent(QContextMenuEvent *e) override;
159 
160 	// Resizes content and counts natural widget height for the desired width.
161 	int resizeGetHeight(int newWidth) override;
162 
163 private:
164 	using Element = HistoryView::Element;
165 	enum class Direction {
166 		Up,
167 		Down,
168 	};
169 	enum class MouseAction {
170 		None,
171 		PrepareDrag,
172 		Dragging,
173 		Selecting,
174 	};
175 	enum class EnumItemsDirection {
176 		TopToBottom,
177 		BottomToTop,
178 	};
179 	using TextState = HistoryView::TextState;
180 	using CursorState = HistoryView::CursorState;
181 	using PointState = HistoryView::PointState;
182 	using StateRequest = HistoryView::StateRequest;
183 
184 	void mouseActionStart(const QPoint &screenPos, Qt::MouseButton button);
185 	void mouseActionUpdate(const QPoint &screenPos);
186 	void mouseActionFinish(const QPoint &screenPos, Qt::MouseButton button);
187 	void mouseActionCancel();
188 	void updateSelected();
189 	void performDrag();
190 	int itemTop(not_null<const Element*> view) const;
191 	void repaintItem(const Element *view);
192 	void refreshItem(not_null<const Element*> view);
193 	void resizeItem(not_null<Element*> view);
194 	QPoint mapPointToItem(QPoint point, const Element *view) const;
195 
196 	void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
197 	void savePhotoToFile(not_null<PhotoData*> photo);
198 	void saveDocumentToFile(not_null<DocumentData*> document);
199 	void copyContextImage(not_null<PhotoData*> photo);
200 	void showStickerPackInfo(not_null<DocumentData*> document);
201 	void cancelContextDownload(not_null<DocumentData*> document);
202 	void showContextInFolder(not_null<DocumentData*> document);
203 	void openContextGif(FullMsgId itemId);
204 	void copyContextText(FullMsgId itemId);
205 	void copySelectedText();
206 	TextForMimeData getSelectedText() const;
207 	void suggestRestrictUser(not_null<UserData*> user);
208 	void restrictUser(not_null<UserData*> user, ChatRestrictionsInfo oldRights, ChatRestrictionsInfo newRights);
209 	void restrictUserDone(not_null<UserData*> user, ChatRestrictionsInfo rights);
210 
211 	void requestAdmins();
212 	void checkPreloadMore();
213 	void updateVisibleTopItem();
214 	void preloadMore(Direction direction);
215 	void itemsAdded(Direction direction, int addedCount);
216 	void updateSize();
217 	void updateMinMaxIds();
218 	void updateEmptyText();
219 	void paintEmpty(Painter &p, not_null<const Ui::ChatStyle*> st);
220 	void clearAfterFilterChange();
221 	void clearAndRequestLog();
222 	void addEvents(Direction direction, const QVector<MTPChannelAdminLogEvent> &events);
223 	Element *viewForItem(const HistoryItem *item);
224 
225 	void toggleScrollDateShown();
226 	void repaintScrollDateCallback();
227 	bool displayScrollDate() const;
228 	void scrollDateHide();
229 	void scrollDateCheck();
230 	void scrollDateHideByTimer();
231 
232 	// This function finds all history items that are displayed and calls template method
233 	// for each found message (in given direction) in the passed history with passed top offset.
234 	//
235 	// Method has "bool (*Method)(not_null<Element*> view, int itemtop, int itembottom)" signature
236 	// if it returns false the enumeration stops immidiately.
237 	template <EnumItemsDirection direction, typename Method>
238 	void enumerateItems(Method method);
239 
240 	// This function finds all userpics on the left that are displayed and calls template method
241 	// for each found userpic (from the top to the bottom) using enumerateItems() method.
242 	//
243 	// Method has "bool (*Method)(not_null<Element*> view, int userpicTop)" signature
244 	// if it returns false the enumeration stops immediately.
245 	template <typename Method>
246 	void enumerateUserpics(Method method);
247 
248 	// This function finds all date elements that are displayed and calls template method
249 	// for each found date element (from the bottom to the top) using enumerateItems() method.
250 	//
251 	// Method has "bool (*Method)(not_null<HistoryItem*> item, int itemtop, int dateTop)" signature
252 	// if it returns false the enumeration stops immediately.
253 	template <typename Method>
254 	void enumerateDates(Method method);
255 
256 	const not_null<Window::SessionController*> _controller;
257 	const not_null<ChannelData*> _channel;
258 	const not_null<History*> _history;
259 	MTP::Sender _api;
260 
261 	const std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
262 	std::shared_ptr<Ui::ChatTheme> _theme;
263 
264 	std::vector<OwnedItem> _items;
265 	std::set<uint64> _eventIds;
266 	std::map<not_null<const HistoryItem*>, not_null<Element*>> _itemsByData;
267 	base::flat_map<not_null<const HistoryItem*>, TimeId> _itemDates;
268 	base::flat_set<FullMsgId> _animatedStickersPlayed;
269 	base::flat_map<
270 		not_null<PeerData*>,
271 		std::shared_ptr<Data::CloudImageView>> _userpics, _userpicsCache;
272 	int _itemsTop = 0;
273 	int _itemsWidth = 0;
274 	int _itemsHeight = 0;
275 
276 	int _minHeight = 0;
277 	int _visibleTop = 0;
278 	int _visibleBottom = 0;
279 	Element *_visibleTopItem = nullptr;
280 	int _visibleTopFromItem = 0;
281 
282 	bool _scrollDateShown = false;
283 	Ui::Animations::Simple _scrollDateOpacity;
284 	SingleQueuedInvokation _scrollDateCheck;
285 	base::Timer _scrollDateHideTimer;
286 	Element *_scrollDateLastItem = nullptr;
287 	int _scrollDateLastItemTop = 0;
288 
289 	// Up - max, Down - min.
290 	uint64 _maxId = 0;
291 	uint64 _minId = 0;
292 	mtpRequestId _preloadUpRequestId = 0;
293 	mtpRequestId _preloadDownRequestId = 0;
294 
295 	// Don't load anything until the memento was read.
296 	bool _upLoaded = true;
297 	bool _downLoaded = true;
298 	bool _filterChanged = false;
299 	Ui::Text::String _emptyText;
300 
301 	MouseAction _mouseAction = MouseAction::None;
302 	TextSelectType _mouseSelectType = TextSelectType::Letters;
303 	QPoint _dragStartPosition;
304 	QPoint _mousePosition;
305 	Element *_mouseActionItem = nullptr;
306 	CursorState _mouseCursorState = CursorState();
307 	uint16 _mouseTextSymbol = 0;
308 	bool _pressWasInactive = false;
309 
310 	Element *_selectedItem = nullptr;
311 	TextSelection _selectedText;
312 	bool _wasSelectedText = false; // was some text selected in current drag action
313 	Qt::CursorShape _cursor = style::cur_default;
314 
315 	base::unique_qptr<Ui::PopupMenu> _menu;
316 
317 	QPoint _trippleClickPoint;
318 	base::Timer _trippleClickTimer;
319 
320 	FilterValue _filter;
321 	QString _searchQuery;
322 	std::vector<not_null<UserData*>> _admins;
323 	std::vector<not_null<UserData*>> _adminsCanEdit;
324 	Fn<void(FilterValue &&filter)> _showFilterCallback;
325 
326 	rpl::event_stream<> _showSearchSignal;
327 	rpl::event_stream<int> _scrollToSignal;
328 	rpl::event_stream<> _cancelSignal;
329 
330 };
331 
332 } // namespace AdminLog
333