From aabf13669025f2eb026bd09df911220f916251db Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Tue, 4 Aug 2015 18:01:47 +0300
Subject: [PATCH] search in conversation, clear history and delete conversation
 for all chats

---
 Telegram/Resources/lang.strings           |   7 ++
 Telegram/SourceFiles/app.cpp              |   9 --
 Telegram/SourceFiles/app.h                |   1 -
 Telegram/SourceFiles/dialogswidget.cpp    | 118 +++++++++++++++++++---
 Telegram/SourceFiles/dialogswidget.h      |  12 +++
 Telegram/SourceFiles/gui/flattextarea.cpp |   2 +
 Telegram/SourceFiles/history.cpp          |  10 +-
 Telegram/SourceFiles/historywidget.cpp    |   2 +
 Telegram/SourceFiles/mainwidget.cpp       |  47 +++++----
 Telegram/SourceFiles/mainwidget.h         |   6 +-
 Telegram/SourceFiles/profilewidget.cpp    |  59 +++++++++--
 Telegram/SourceFiles/profilewidget.h      |   7 +-
 12 files changed, 225 insertions(+), 55 deletions(-)

diff --git a/Telegram/Resources/lang.strings b/Telegram/Resources/lang.strings
index 115bf77c5..1eb67ca5f 100644
--- a/Telegram/Resources/lang.strings
+++ b/Telegram/Resources/lang.strings
@@ -158,6 +158,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 "lng_no_contacts" = "You have no contacts";
 "lng_contacts_loading" = "Loading..";
 "lng_contacts_not_found" = "No contacts found";
+"lng_dlg_search_chat" = "Search in this chat";
+"lng_dlg_search_for_messages" = "Search for messages";
 
 "lng_settings_save" = "Save";
 "lng_settings_upload" = "Set Profile Photo";
@@ -339,6 +341,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 "lng_topbar_info" = "Info";
 "lng_profile_about_section" = "About";
 "lng_profile_settings_section" = "Settings";
+"lng_profile_actions_section" = "Actions";
 "lng_profile_bot_settings" = "Settings";
 "lng_profile_bot_help" = "Help";
 "lng_profile_participants_section" = "Members";
@@ -348,6 +351,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 "lng_profile_edit_contact" = "Edit";
 "lng_profile_enable_notifications" = "Notifications";
 "lng_profile_clear_history" = "Clear history";
+"lng_profile_delete_conversation" = "Delete conversation";
+"lng_profile_clear_and_exit" = "Delete and exit";
+"lng_profile_search_messages" = "Search for messages";
 "lng_profile_send_message" = "Send Message";
 "lng_profile_share_contact" = "Share Contact";
 "lng_profile_invite_to_group" = "Add to Group";
@@ -382,6 +388,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
 
 "lng_sure_delete_contact" = "Are you sure, you want to delete {contact} from your contact list?";
 "lng_sure_delete_history" = "Are you sure, you want to delete all message history with {contact}?\n\nThis action cannot be undone.";
+"lng_sure_delete_group_history" = "Are you sure, you want to delete all message history in «{group}»?\n\nThis action cannot be undone.";
 
 "lng_sure_delete_and_exit" = "Are you sure, you want to delete all message history and leave «{group}»?\n\nThis action cannot be undone.";
 
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index a5b5659a2..120fae069 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -1752,15 +1752,6 @@ namespace App {
 		}
 	}
 
-	/* // don't delete history without deleting its' peerdata
-	void deleteHistory(const PeerId &peer) {
-		Histories::iterator i = ::histories.find(peer);
-		if (i != ::histories.end()) {
-			::histories.typing.remove(i.value());
-			::histories.erase(i);
-		}
-	}
-/**/
 	void historyRegRandom(uint64 randomId, MsgId itemId) {
 		randomData.insert(randomId, itemId);
 	}
diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h
index 5a91cba2a..c1befed22 100644
--- a/Telegram/SourceFiles/app.h
+++ b/Telegram/SourceFiles/app.h
@@ -183,7 +183,6 @@ namespace App {
 	void historyClearItems();
 	void historyRegReply(HistoryReply *reply, HistoryItem *to);
 	void historyUnregReply(HistoryReply *reply, HistoryItem *to);
-//	void deleteHistory(const PeerId &peer);
 
 	void historyRegRandom(uint64 randomId, MsgId itemId);
 	void historyUnregRandom(uint64 randomId);
diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp
index 89ba6f814..427f87d3f 100644
--- a/Telegram/SourceFiles/dialogswidget.cpp
+++ b/Telegram/SourceFiles/dialogswidget.cpp
@@ -42,12 +42,16 @@ peopleSel(-1),
 _lastSearchId(0),
 _state(DefaultState),
 _addContactLnk(this, lang(lng_add_contact_button)),
-_overDelete(false) {
+_cancelSearchInPeer(this, st::btnCancelSearch),
+_overDelete(false),
+_searchInPeer(0) {
 	connect(main, SIGNAL(dialogToTop(const History::DialogLinks&)), this, SLOT(onDialogToTop(const History::DialogLinks&)));
 	connect(main, SIGNAL(peerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)), this, SLOT(onPeerNameChanged(PeerData*,const PeerData::Names&,const PeerData::NameFirstChars&)));
 	connect(main, SIGNAL(peerPhotoChanged(PeerData*)), this, SLOT(onPeerPhotoChanged(PeerData*)));
 	connect(main, SIGNAL(dialogRowReplaced(DialogRow*,DialogRow*)), this, SLOT(onDialogRowReplaced(DialogRow*,DialogRow*)));
 	connect(&_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
+	connect(&_cancelSearchInPeer, SIGNAL(clicked()), this, SIGNAL(cancelSearchInPeer()));
+	_cancelSearchInPeer.hide();
 	refresh(false);
 }
 
@@ -60,7 +64,9 @@ int32 DialogsListWidget::peopleOffset() const {
 }
 
 int32 DialogsListWidget::searchedOffset() const {
-	return peopleOffset() + (peopleResults.isEmpty() ? 0 : ((peopleResults.size() * st::dlgHeight) + st::searchedBarHeight));
+	int32 result = peopleOffset() + (peopleResults.isEmpty() ? 0 : ((peopleResults.size() * st::dlgHeight) + st::searchedBarHeight));
+	if (_searchInPeer) result += st::dlgHeight;
+	return result;
 }
 
 void DialogsListWidget::paintEvent(QPaintEvent *e) {
@@ -181,6 +187,18 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) {
 			}
 		}
 
+		if (_searchInPeer) {
+			searchInPeerPaint(p, width());
+			p.translate(0, st::dlgHeight);
+			if (_state == FilteredState && searchResults.isEmpty()) {
+				p.fillRect(0, 0, width(), st::searchedBarHeight, st::searchedBarBG->b);
+				p.setFont(st::searchedBarFont->f);
+				p.setPen(st::searchedBarColor->p);
+				p.drawText(QRect(0, 0, width(), st::searchedBarHeight), lang(lng_dlg_search_for_messages), style::al_center);
+				p.translate(0, st::searchedBarHeight);
+			}
+		}
+
 		if (_state == SearchedState || !searchResults.isEmpty()) {
 			QString text = lng_search_found_results(lt_count, searchResults.isEmpty() ? 0 : searchedCount);
 			p.fillRect(0, 0, width(), st::searchedBarHeight, st::searchedBarBG->b);
@@ -252,6 +270,31 @@ void DialogsListWidget::peopleResultPaint(UserData *user, QPainter &p, int32 w,
 	history->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
 }
 
+void DialogsListWidget::searchInPeerPaint(QPainter &p, int32 w) const {
+	QRect fullRect(0, 0, w, st::dlgHeight);
+	p.fillRect(fullRect, st::dlgBG->b);
+
+	p.drawPixmap(st::dlgPaddingHor, st::dlgPaddingVer, _searchInPeer->photo->pix(st::dlgPhotoSize));
+
+	int32 nameleft = st::dlgPaddingHor + st::dlgPhotoSize + st::dlgPhotoPadding;
+	int32 namewidth = w - nameleft - st::dlgPaddingHor * 2 - st::btnCancelSearch.width;
+	QRect rectForName(nameleft, st::dlgPaddingVer + st::dlgNameTop, namewidth, st::msgNameFont->height);
+
+	// draw chat icon
+	if (_searchInPeer->chat) {
+		p.drawPixmap(QPoint(rectForName.left() + st::dlgChatImgLeft, rectForName.top() + st::dlgChatImgTop), App::sprite(), st::dlgChatImg);
+		rectForName.setLeft(rectForName.left() + st::dlgChatImgSkip);
+	}
+
+	QRect tr(nameleft, st::dlgPaddingVer + st::dlgFont->height + st::dlgSep, namewidth, st::dlgFont->height);
+	p.setFont(st::dlgHistFont->f);
+	p.setPen(st::dlgTextColor->p);
+	p.drawText(tr.left(), tr.top() + st::dlgHistFont->ascent, st::dlgHistFont->m.elidedText(lang(lng_dlg_search_chat), Qt::ElideRight, tr.width()));
+
+	p.setPen(st::dlgNameColor->p);
+	App::history(_searchInPeer->id)->nameText.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width());
+}
+
 void DialogsListWidget::activate() {
 }
 
@@ -347,6 +390,7 @@ void DialogsListWidget::mousePressEvent(QMouseEvent *e) {
 
 void DialogsListWidget::resizeEvent(QResizeEvent *e) {
 	_addContactLnk.move((width() - _addContactLnk.width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2);
+	_cancelSearchInPeer.move(width() - st::dlgPaddingHor - st::btnCancelSearch.width, (st::dlgHeight - st::btnCancelSearch.height) / 2);
 }
 
 void DialogsListWidget::onDialogRowReplaced(DialogRow *oldRow, DialogRow *newRow) {
@@ -397,9 +441,6 @@ void DialogsListWidget::removePeer(PeerData *peer) {
 			contactsNoDialogs.addByName(App::history(peer->id));
 		}
 	}
-//	contactsNoDialogs.del(peer);
-//	contacts.del(peer);
-//	App::deleteHistory(peer->id);
 
 	emit App::main()->dialogsUpdated();
 
@@ -539,7 +580,7 @@ void DialogsListWidget::onFilterUpdate(QString newFilter, bool force) {
 		}
 		if (newFilter != filter || force) {
 			filter = newFilter;
-			if (filter.isEmpty()) {
+			if (!_searchInPeer && filter.isEmpty()) {
 				_state = DefaultState;
 				hashtagResults.clear();
 				filterResults.clear();
@@ -551,7 +592,7 @@ void DialogsListWidget::onFilterUpdate(QString newFilter, bool force) {
 
 				_state = FilteredState;
 				filterResults.clear();
-				if (!f.isEmpty()) {
+				if (!_searchInPeer && !f.isEmpty()) {
 					DialogsList *dialogsToFilter = 0, *contactsNoDialogsToFilter = 0;
 					if (dialogs.list.count) {
 						for (fi = fb; fi != fe; ++fi) {
@@ -630,7 +671,7 @@ void DialogsListWidget::onFilterUpdate(QString newFilter, bool force) {
 }
 
 void DialogsListWidget::onHashtagFilterUpdate(QStringRef newFilter) {
-	if (newFilter.isEmpty() || newFilter.at(0) != '#') {
+	if (newFilter.isEmpty() || newFilter.at(0) != '#' || _searchInPeer) {
 		_hashtagFilter = QString();
 		if (!hashtagResults.isEmpty()) {
 			hashtagResults.clear();
@@ -817,7 +858,7 @@ void DialogsListWidget::refresh(bool toTop) {
 	} else {
 		if (!_addContactLnk.isHidden()) _addContactLnk.hide();
 		if (_state == FilteredState) {
-			h = searchedOffset() + (searchResults.count() * st::dlgHeight) + (searchResults.isEmpty() ? 0 : st::searchedBarHeight);
+			h = searchedOffset() + (searchResults.count() * st::dlgHeight) + ((searchResults.isEmpty() && !_searchInPeer) ? 0 : st::searchedBarHeight);
 		} else if (_state == SearchedState) {
 			h = searchedOffset() + (searchResults.count() * st::dlgHeight) + st::searchedBarHeight;
 		}
@@ -866,9 +907,23 @@ bool DialogsListWidget::hasFilteredResults() const {
 	return !filterResults.isEmpty() && hashtagResults.isEmpty();
 }
 
+void DialogsListWidget::searchInPeer(PeerData *peer) {
+	_searchInPeer = peer;
+	if (_searchInPeer) {
+		onHashtagFilterUpdate(QStringRef());
+		_cancelSearchInPeer.show();
+	} else {
+		_cancelSearchInPeer.hide();
+	}
+}
+
 void DialogsListWidget::clearFilter() {
 	if (_state == FilteredState || _state == SearchedState) {
-		_state = DefaultState;
+		if (_searchInPeer) {
+			_state = FilteredState;
+		} else {
+			_state = DefaultState;
+		}
 		hashtagResults.clear();
 		filterResults.clear();
 		peopleResults.clear();
@@ -1390,6 +1445,7 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
 , _cancelSearch(this, st::btnCancelSearch)
 , scroll(this, st::dlgScroll)
 , list(&scroll, parent)
+, _searchInPeer(0)
 , _searchFull(false)
 , _peopleFull(false)
 {
@@ -1401,6 +1457,7 @@ DialogsWidget::DialogsWidget(MainWidget *parent) : QWidget(parent)
 	connect(&list, SIGNAL(searchResultChosen()), this, SLOT(onCancel()));
 	connect(&list, SIGNAL(completeHashtag(QString)), this, SLOT(onCompleteHashtag(QString)));
 	connect(&list, SIGNAL(refreshHashtags()), this, SLOT(onFilterCursorMoved()));
+	connect(&list, SIGNAL(cancelSearchInPeer()), this, SLOT(onCancelSearchInPeer()));
 	connect(&scroll, SIGNAL(geometryChanged()), &list, SLOT(onParentGeometryChanged()));
 	connect(&scroll, SIGNAL(scrolled()), &list, SLOT(onUpdateSelected()));
 	connect(&scroll, SIGNAL(scrolled()), this, SLOT(onListScroll()));
@@ -1496,7 +1553,7 @@ bool DialogsWidget::animStep(float64 ms) {
 }
 
 void DialogsWidget::onCancel() {
-	if (!onCancelSearch() || !App::main()->selectingPeer()) {
+	if (!onCancelSearch() || (!_searchInPeer && !App::main()->selectingPeer())) {
 		emit cancelled();
 	}
 }
@@ -1600,10 +1657,10 @@ bool DialogsWidget::onSearchMessages(bool searchCache) {
 	} else if (_searchQuery != q) {
 		_searchQuery = q;
 		_searchFull = false;
-		_searchRequest = MTP::send(MTPmessages_Search(MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, true), rpcFail(&DialogsWidget::searchFailed));
+		_searchRequest = MTP::send(MTPmessages_Search(_searchInPeer ? _searchInPeer->input : MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, true), rpcFail(&DialogsWidget::searchFailed));
 		_searchQueries.insert(_searchRequest, _searchQuery);
 	}
-	if (q.size() >= MinUsernameLength) {
+	if (!_searchInPeer && q.size() >= MinUsernameLength) {
 		if (searchCache) {
 			PeopleCache::const_iterator i = _peopleCache.constFind(q);
 			if (i != _peopleCache.cend()) {
@@ -1647,7 +1704,7 @@ void DialogsWidget::searchMessages(const QString &query) {
 
 void DialogsWidget::onSearchMore(MsgId minMsgId) {
 	if (!_searchRequest && !_searchFull) {
-		_searchRequest = MTP::send(MTPmessages_Search(MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minMsgId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, !minMsgId), rpcFail(&DialogsWidget::searchFailed));
+		_searchRequest = MTP::send(MTPmessages_Search(_searchInPeer ? _searchInPeer->input : MTP_inputPeerEmpty(), MTP_string(_searchQuery), MTP_inputMessagesFilterEmpty(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minMsgId), MTP_int(SearchPerPage)), rpcDone(&DialogsWidget::searchReceived, !minMsgId), rpcFail(&DialogsWidget::searchFailed));
 		if (!minMsgId) {
 			_searchQueries.insert(_searchRequest, _searchQuery);
 		}
@@ -1877,6 +1934,14 @@ void DialogsWidget::onFilterUpdate(bool force) {
 	}
 }
 
+void DialogsWidget::searchInPeer(PeerData *peer) {
+	onCancelSearch();
+	_searchInPeer = peer;
+	list.searchInPeer(peer);
+	onFilterUpdate(true);
+	list.onFilterUpdate(_filter.text(), true);
+}
+
 void DialogsWidget::onFilterCursorMoved(int from, int to) {
 	if (to < 0) to = _filter.cursorPosition();
 	QString t = _filter.text();
@@ -2035,6 +2100,14 @@ void DialogsWidget::onNewGroup() {
 
 bool DialogsWidget::onCancelSearch() {
 	bool clearing = !_filter.text().isEmpty();
+	if (_searchInPeer && !clearing) {
+		if (!cWideMode()) {
+			App::main()->showPeerHistory(_searchInPeer->id, ShowAtUnreadMsgId);
+		}
+		_searchInPeer = 0;
+		list.searchInPeer(0);
+		clearing = true;
+	}
 	list.clearFilter();
 	_filter.clear();
 	_filter.updatePlaceholder();
@@ -2042,6 +2115,23 @@ bool DialogsWidget::onCancelSearch() {
 	return clearing;
 }
 
+void DialogsWidget::onCancelSearchInPeer() {
+	if (_searchInPeer) {
+		if (!cWideMode()) {
+			App::main()->showPeerHistory(_searchInPeer->id, ShowAtUnreadMsgId);
+		}
+		_searchInPeer = 0;
+		list.searchInPeer(0);
+	}
+	list.clearFilter();
+	_filter.clear();
+	_filter.updatePlaceholder();
+	onFilterUpdate();
+	if (cWideMode()) {
+		emit cancelled();
+	}
+}
+
 void DialogsWidget::onDialogToTopFrom(int movedFrom) {
 	if (scroll.scrollTop() > 0) {
 		if (movedFrom > scroll.scrollTop()) {
diff --git a/Telegram/SourceFiles/dialogswidget.h b/Telegram/SourceFiles/dialogswidget.h
index 922f2a813..ec7c1fa13 100644
--- a/Telegram/SourceFiles/dialogswidget.h
+++ b/Telegram/SourceFiles/dialogswidget.h
@@ -48,6 +48,7 @@ public:
 	void leaveEvent(QEvent *e);
 
 	void peopleResultPaint(UserData *user, QPainter &p, int32 w, bool act, bool sel) const;
+	void searchInPeerPaint(QPainter &p, int32 w) const;
 
 	void selectSkip(int32 direction);
 	void selectSkipPage(int32 pixels, int32 direction);
@@ -93,6 +94,8 @@ public:
 	State state() const;
 	bool hasFilteredResults() const;
 
+	void searchInPeer(PeerData *peer);
+
 	void onFilterUpdate(QString newFilter, bool force = false);
 	void onHashtagFilterUpdate(QStringRef newFilter);
 	void itemRemoved(HistoryItem *item);
@@ -117,6 +120,7 @@ signals:
 	void dialogToTopFrom(int movedFrom);
 	void searchMessages();
 	void searchResultChosen();
+	void cancelSearchInPeer();
 	void completeHashtag(QString tag);
 	void refreshHashtags();
 
@@ -156,9 +160,12 @@ private:
 	void paintDialog(QPainter &p, DialogRow *dialog);
 
 	LinkButton _addContactLnk;
+	IconedButton _cancelSearchInPeer;
 
 	bool _overDelete;
 
+	PeerData *_searchInPeer;
+
 };
 
 class DialogsWidget : public QWidget, public Animated, public RPCSender {
@@ -183,6 +190,8 @@ public:
 	void keyPressEvent(QKeyEvent *e);
 	void paintEvent(QPaintEvent *e);
 
+	void searchInPeer(PeerData *peer);
+
 	void loadDialogs();
 	void createDialogAtTop(History *history, int32 unreadCount);
 	void dlgUpdated(DialogRow *row);
@@ -226,6 +235,7 @@ public slots:
 	void onAddContact();
 	void onNewGroup();
 	bool onCancelSearch();
+	void onCancelSearchInPeer();
 
 	void onFilterCursorMoved(int from = -1, int to = -1);
 	void onCompleteHashtag(QString tag);
@@ -262,6 +272,8 @@ private:
 	anim::ivalue a_coord, a_bgCoord;
 	anim::fvalue a_alpha, a_bgAlpha;
 
+	PeerData *_searchInPeer;
+
 	QTimer _searchTimer;
 	QString _searchQuery, _peopleQuery;
 	bool _searchFull, _peopleFull;
diff --git a/Telegram/SourceFiles/gui/flattextarea.cpp b/Telegram/SourceFiles/gui/flattextarea.cpp
index ca001ec97..741a69901 100644
--- a/Telegram/SourceFiles/gui/flattextarea.cpp
+++ b/Telegram/SourceFiles/gui/flattextarea.cpp
@@ -774,6 +774,8 @@ void FlatTextarea::keyPressEvent(QKeyEvent *e) {
 		} else {
 			emit tabbed();
 		}
+	} else if (e->key() == Qt::Key_Search || e == QKeySequence::Find) {
+		e->ignore();
 	} else {
 		QTextCursor tc(textCursor());
 		if (enter && ctrl) {
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index 1d9e7a74f..2716d1c4d 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -1481,9 +1481,16 @@ void History::clear(bool leaveItems) {
 	if (showFrom) {
 		showFrom = 0;
 	}
+	if (!leaveItems) {
+		lastMsg = 0;
+	}
 	for (int32 i = 0; i < OverviewCount; ++i) {
 		if (!_overview[i].isEmpty() || !_overviewIds[i].isEmpty()) {
-			if (_overviewCount[i] == 0) _overviewCount[i] = _overview[i].size();
+			if (leaveItems) {
+				if (_overviewCount[i] == 0) _overviewCount[i] = _overview[i].size();
+			} else {
+				_overviewCount[i] = -1; // not loaded yet
+			}
 			_overview[i].clear();
 			_overviewIds[i].clear();
 			if (App::wnd() && !App::quiting()) App::wnd()->mediaOverviewUpdated(peer, MediaOverviewType(i));
@@ -1501,7 +1508,6 @@ void History::clear(bool leaveItems) {
 		lastKeyboardInited = false;
 	} else {
 		setUnreadCount(0);
-		lastMsg = 0;
 	}
 	height = 0;
 	oldLoaded = false;
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index 32ce0a65d..2648c6e0e 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -4816,6 +4816,8 @@ void HistoryWidget::keyPressEvent(QKeyEvent *e) {
 			App::main()->peerAfter(_peer, msgid, p, m);
 		}
 		if (p) App::main()->showPeerHistory(p->id, m);
+	} else if (_history && (e->key() == Qt::Key_Search || e == QKeySequence::Find)) {
+		App::main()->searchInPeer(_history->peer);
 	} else {
 		e->ignore();
 	}
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index b56c882b7..47922db5b 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -122,7 +122,7 @@ void TopBarWidget::onDeleteAndExitSure() {
 	if (c) {
 		App::main()->showDialogs();
 		App::wnd()->hideLayer();
-		MTP::send(MTPmessages_DeleteChatUser(MTP_int(p->id & 0xFFFFFFFF), App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistory, p), App::main()->rpcFail(&MainWidget::leaveChatFailed, p));
+		MTP::send(MTPmessages_DeleteChatUser(MTP_int(p->id & 0xFFFFFFFF), App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistoryAfterLeave, p), App::main()->rpcFail(&MainWidget::leaveChatFailed, p));
 	}
 }
 
@@ -738,20 +738,20 @@ bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &error) {
 			showDialogs();
 		}
 		dialogs.removePeer(peer);
-		App::histories().remove(peer->id);
+		App::history(peer->id)->clear();
 		MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 		return true;
 	}
 	return false;
 }
 
-void MainWidget::deleteHistory(PeerData *peer, const MTPUpdates &updates) {
+void MainWidget::deleteHistoryAfterLeave(PeerData *peer, const MTPUpdates &updates) {
 	sentUpdatesReceived(updates);
 	if ((profile && profile->peer() == peer) || (overview && overview->peer() == peer) || _stack.contains(peer) || history.peer() == peer) {
 		showDialogs();
 	}
 	dialogs.removePeer(peer);
-	App::histories().remove(peer->id);
+	App::history(peer->id)->clear();
 	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 }
 
@@ -776,26 +776,23 @@ void MainWidget::deletedContact(UserData *user, const MTPcontacts_Link &result)
 	App::emitPeerUpdated();
 }
 
-void MainWidget::deleteHistoryAndContact(UserData *user, const MTPcontacts_Link &result) {
-	const MTPDcontacts_link &d(result.c_contacts_link());
-	App::feedUsers(MTP_vector<MTPUser>(1, d.vuser), false);
-	App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link, false);
-	App::emitPeerUpdated();
-
-	if ((profile && profile->peer() == user) || (overview && overview->peer() == user) || _stack.contains(user) || history.peer() == user) {
-		showDialogs();
-	}
-	dialogs.removePeer(user);
-	MTP::send(MTPmessages_DeleteHistory(user->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, (PeerData*)user));
+void MainWidget::deleteConversation(PeerData *peer) {
+	dialogs.removePeer(peer);
+	History *h = App::history(peer->id);
+	h->clear();
+	h->newLoaded = h->oldLoaded = true;
+	showDialogs();
+	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 }
 
 void MainWidget::clearHistory(PeerData *peer) {
-	if (!peer->chat && peer->asUser()->contact <= 0) {
-		dialogs.removePeer(peer->asUser());
+	History *h = App::history(peer->id);
+	if (h->lastMsg) {
+//		Local::savePeerPosition(h->peer, h->lastMsg->date);
 	}
-	dialogsToUp();
-	dialogs.update();
-	App::history(peer->id)->clear();
+	h->clear();
+	h->newLoaded = h->oldLoaded = true;
+	showPeerHistory(peer->id, ShowAtUnreadMsgId);
 	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
 }
 
@@ -2530,6 +2527,16 @@ void MainWidget::onPeerShown(PeerData *peer) {
 	if (animating()) _topBar.hide();
 }
 
+void MainWidget::searchInPeer(PeerData *peer) {
+	dialogs.searchInPeer(peer);
+	if (cWideMode()) {
+		dialogs.activate();
+	} else {
+		dialogsToUp();
+		showDialogs();
+	}
+}
+
 void MainWidget::onUpdateNotifySettings() {
 	if (this != App::main()) return;
 	while (!updateNotifySettingPeers.isEmpty()) {
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index c0503be5e..9fec76a31 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -281,11 +281,11 @@ public:
 	DragState getDragState(const QMimeData *mime);
 
 	bool leaveChatFailed(PeerData *peer, const RPCError &e);
-	void deleteHistory(PeerData *peer, const MTPUpdates &updates);
+	void deleteHistoryAfterLeave(PeerData *peer, const MTPUpdates &updates);
 	void deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result);
 	void deleteMessages(const QVector<MTPint> &ids);
 	void deletedContact(UserData *user, const MTPcontacts_Link &result);
-	void deleteHistoryAndContact(UserData *user, const MTPcontacts_Link &result);
+	void deleteConversation(PeerData *peer);
 	void clearHistory(PeerData *peer);
 	void removeContact(UserData *user);
 
@@ -421,6 +421,8 @@ public slots:
 	void onTopBarClick();
 	void onPeerShown(PeerData *peer);
 
+	void searchInPeer(PeerData *peer);
+
 	void onUpdateNotifySettings();
 
 	void onPhotosSelect();
diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp
index 08c460c4b..30743e737 100644
--- a/Telegram/SourceFiles/profilewidget.cpp
+++ b/Telegram/SourceFiles/profilewidget.cpp
@@ -55,7 +55,11 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
 
 	// settings
 	_enableNotifications(this, lang(lng_profile_enable_notifications)),
+
+	// actions
+	_searchInPeer(this, lang(lng_profile_search_messages)),
 	_clearHistory(this, lang(lng_profile_clear_history)),
+	_deleteConversation(this, lang(_peer->chat ? lng_profile_clear_and_exit : lng_profile_delete_conversation)),
 
 	// shared media
 	_allMediaTypes(false),
@@ -96,7 +100,6 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
 
 	// profile
 	_nameText.setText(st::profileNameFont, _nameCache, _textNameOptions);
-
 	connect(&_uploadPhoto, SIGNAL(clicked()), this, SLOT(onUpdatePhoto()));
 	connect(&_addParticipant, SIGNAL(clicked()), this, SLOT(onAddParticipant()));
 	connect(&_sendMessage, SIGNAL(clicked()), this, SLOT(onSendMessage()));
@@ -149,7 +152,11 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
 
 	// settings
 	connect(&_enableNotifications, SIGNAL(clicked()), this, SLOT(onEnableNotifications()));
+
+	// actions
+	connect(&_searchInPeer, SIGNAL(clicked()), this, SLOT(onSearchInPeer()));
 	connect(&_clearHistory, SIGNAL(clicked()), this, SLOT(onClearHistory()));
+	connect(&_deleteConversation, SIGNAL(clicked()), this, SLOT(onDeleteConversation()));
 
 	// shared media
 	connect(&_mediaShowAll, SIGNAL(clicked()), this, SLOT(onMediaShowAll()));
@@ -181,6 +188,10 @@ void ProfileInner::onSendMessage() {
 	App::main()->showPeerHistory(_peer->id, ShowAtUnreadMsgId);
 }
 
+void ProfileInner::onSearchInPeer() {
+	App::main()->searchInPeer(_peer);
+}
+
 void ProfileInner::onEnableNotifications() {
 	App::main()->updateNotifySetting(_peer, _enableNotifications.checked());
 }
@@ -244,17 +255,32 @@ void ProfileInner::onUpdatePhoto() {
 }
 
 void ProfileInner::onClearHistory() {
-	ConfirmBox *box = new ConfirmBox(lng_sure_delete_history(lt_contact, _peer->name));
+	ConfirmBox *box = new ConfirmBox(_peer->chat ? lng_sure_delete_group_history(lt_group, _peer->name) : lng_sure_delete_history(lt_contact, _peer->name));
 	connect(box, SIGNAL(confirmed()), this, SLOT(onClearHistorySure()));
 	App::wnd()->showLayer(box);
 }
 
 void ProfileInner::onClearHistorySure() {
-	App::main()->showDialogs();
 	App::wnd()->hideLayer();
 	App::main()->clearHistory(_peer);
 }
 
+void ProfileInner::onDeleteConversation() {
+	ConfirmBox *box = new ConfirmBox(_peer->chat ? lng_sure_delete_and_exit(lt_group, _peer->name) : lng_sure_delete_history(lt_contact, _peer->name));
+	connect(box, SIGNAL(confirmed()), this, SLOT(onDeleteConversationSure()));
+	App::wnd()->showLayer(box);
+}
+
+void ProfileInner::onDeleteConversationSure() {
+	if (_peer->chat) {
+		App::wnd()->hideLayer();
+		App::main()->showDialogs();
+		MTP::send(MTPmessages_DeleteChatUser(MTP_int(_peer->id & 0xFFFFFFFF), App::self()->inputUser), App::main()->rpcDone(&MainWidget::deleteHistoryAfterLeave, _peer), App::main()->rpcFail(&MainWidget::leaveChatFailed, _peer));
+	} else {
+		App::main()->deleteConversation(_peer);
+	}
+}
+
 void ProfileInner::onAddParticipant() {
 	App::wnd()->showLayer(new ContactsBox(_peerChat));
 }
@@ -569,6 +595,14 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
 
 	top += _enableNotifications.height();
 
+	// actions
+	p.setFont(st::profileHeaderFont->f);
+	p.setPen(st::profileHeaderColor->p);
+	p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lang(lng_profile_actions_section));
+	top += st::profileHeaderSkip;
+
+	top += _searchInPeer.height() + st::setLittleSkip + _clearHistory.height() + st::setLittleSkip + _deleteConversation.height();
+
 	// shared media
 	p.setFont(st::profileHeaderFont->f);
 	p.setPen(st::profileHeaderColor->p);
@@ -855,6 +889,12 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
 	top += st::profileHeaderSkip;
 	_enableNotifications.move(_left, top); top += _enableNotifications.height();
 
+	// actions
+	top += st::profileHeaderSkip;
+	_searchInPeer.move(_left, top);	top += _searchInPeer.height() + st::setLittleSkip;
+	_clearHistory.move(_left, top); top += _clearHistory.height() + st::setLittleSkip;
+	_deleteConversation.move(_left, top); top += _deleteConversation.height();
+
 	// shared media
 	top += st::profileHeaderSkip;
 
@@ -883,7 +923,6 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
 		}
 	}
 	top += st::profileHeaderTop + st::profileHeaderFont->ascent - st::linkFont->ascent;
-	_clearHistory.move(_left, top);
 }
 
 void ProfileInner::contextMenuEvent(QContextMenuEvent *e) {
@@ -970,6 +1009,9 @@ void ProfileInner::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type)
 }
 
 void ProfileInner::showAll() {
+	_searchInPeer.show();
+	_clearHistory.show();
+	_deleteConversation.show();
 	if (_peerChat) {
 		_sendMessage.hide();
 		_shareContact.hide();
@@ -1006,7 +1048,6 @@ void ProfileInner::showAll() {
 			}
 		}
 		_enableNotifications.show();
-		_clearHistory.hide();
 	} else {
 		_uploadPhoto.hide();
 		_cancelPhoto.hide();
@@ -1070,7 +1111,13 @@ void ProfileInner::showAll() {
 	reorderParticipants();
 	int32 h;
 	if (_peerUser) {
-		h = _clearHistory.y() + _clearHistory.height() + st::profileHeaderSkip;
+		h = _mediaShowAll.y() + _mediaShowAll.height() + st::profileHeaderSkip;
+		if (_mediaShowAll.isHidden()) {
+			for (int i = 0; i < OverviewCount; ++i) {
+				if (i == OverviewAudioDocuments) continue;
+				if (!_mediaLinks[i]->isHidden()) h += _mediaLinks[i]->height() + st::setLittleSkip;
+			}
+		}
 	} else {
 		h = _mediaAudios.y() + _mediaAudios.height() + st::profileHeaderSkip;
 		if (!_participants.isEmpty()) {
diff --git a/Telegram/SourceFiles/profilewidget.h b/Telegram/SourceFiles/profilewidget.h
index 7acc3dfe3..94765769d 100644
--- a/Telegram/SourceFiles/profilewidget.h
+++ b/Telegram/SourceFiles/profilewidget.h
@@ -68,10 +68,13 @@ public slots:
 	void onShareContact();
 	void onInviteToGroup();
 	void onSendMessage();
+	void onSearchInPeer();
 	void onEnableNotifications();
 
 	void onClearHistory();
 	void onClearHistorySure();
+	void onDeleteConversation();
+	void onDeleteConversationSure();
 	void onAddParticipant();
 
 	void onUpdatePhoto();
@@ -142,7 +145,9 @@ private:
 
 	// settings
 	FlatCheckbox _enableNotifications;
-	LinkButton _clearHistory;
+
+	// actions
+	LinkButton _searchInPeer, _clearHistory, _deleteConversation;
 
 	// shared media
 	bool _allMediaTypes;