1 //////////////////////////////////////////////////////////////////////
2 //
3 // BeeBEEP Copyright (C) 2010-2021 Marco Mastroddi
4 //
5 // BeeBEEP is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation, either version 3 of the License,
8 // or (at your option) any later version.
9 //
10 // BeeBEEP is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with BeeBEEP. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // Author: Marco Mastroddi <marco.mastroddi(AT)gmail.com>
19 //
20 // $Id: GuiChatList.cpp 1468 2021-01-05 13:15:58Z mastroddi $
21 //
22 //////////////////////////////////////////////////////////////////////
23
24 #include "GuiChatList.h"
25 #include "GuiConfig.h"
26 #include "ChatManager.h"
27 #include "IconManager.h"
28 #include "Settings.h"
29 #include "UserManager.h"
30
31
GuiChatList(QWidget * parent)32 GuiChatList::GuiChatList( QWidget* parent )
33 : QWidget( parent )
34 {
35 setObjectName( "GuiChatList" );
36 setupUi( this );
37
38 mp_menuContext = new QMenu( parent );
39 mp_menuSettings = new QMenu( parent );
40
41 mp_twChatList->setColumnCount( 1 );
42 mp_twChatList->setRootIsDecorated( false );
43 mp_twChatList->setSortingEnabled( true );
44 mp_twChatList->setIconSize( Settings::instance().avatarIconSize() );
45 mp_twChatList->setContextMenuPolicy( Qt::CustomContextMenu );
46 mp_twChatList->setMouseTracking( true );
47 mp_twChatList->setHeaderHidden( true );
48 mp_twChatList->setObjectName( "GuiCustomList" );
49
50 m_chatSelected = ID_INVALID;
51 m_blockShowChatRequest = false;
52 m_filter = "";
53
54 #if QT_VERSION >= 0x040700
55 mp_leFilter->setPlaceholderText( tr( "Search chat" ) );
56 #endif
57 mp_pbClearFilter->setIcon( IconManager::instance().icon( "clear.png" ) );
58
59 setContextMenuPolicy( Qt::CustomContextMenu );
60 connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( showChatMenu( const QPoint& ) ) );
61 connect( mp_twChatList, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( showChatMenu( const QPoint& ) ) );
62 connect( mp_twChatList, SIGNAL( itemClicked( QTreeWidgetItem*, int ) ), this, SLOT( chatClicked( QTreeWidgetItem*, int ) ), Qt::QueuedConnection );
63 connect( mp_leFilter, SIGNAL( textChanged( const QString& ) ), this, SLOT( filterText( const QString& ) ) );
64 connect( mp_pbClearFilter, SIGNAL( clicked() ), this, SLOT( clearFilter() ) );
65 connect( mp_pbSettings, SIGNAL( clicked() ), this, SLOT( showMenuSettings() ) );
66 }
67
updateChats()68 void GuiChatList::updateChats()
69 {
70 mp_twChatList->clearSelection();
71 mp_twChatList->clear();
72 mp_twChatList->setIconSize( Settings::instance().avatarIconSize() );
73 foreach( Chat c, ChatManager::instance().constChatList() )
74 updateChat( c );
75 }
76
itemFromChatId(VNumber chat_id)77 GuiChatItem* GuiChatList::itemFromChatId( VNumber chat_id )
78 {
79 GuiChatItem* item;
80 QTreeWidgetItemIterator it( mp_twChatList );
81 while( *it )
82 {
83 item = dynamic_cast<GuiChatItem*>( *it );
84 if( item->chatId() == chat_id )
85 return item;
86 ++it;
87 }
88 return Q_NULLPTR;
89 }
90
updateChat(const Chat & c)91 void GuiChatList::updateChat( const Chat& c )
92 {
93 if( !c.isValid() )
94 return;
95
96 GuiChatItem* item = itemFromChatId( c.id() );
97 if( !item )
98 {
99 item = new GuiChatItem( mp_twChatList );
100 item->setChatId( c.id() );
101 }
102 item->updateItem( c );
103
104 bool hide_item = false;
105
106 if( !c.isDefault() && Settings::instance().hideEmptyChatsInList() )
107 hide_item = ChatManager::instance().isChatEmpty( c, true );
108
109 if( !hide_item && !m_filter.isEmpty() )
110 {
111 if( c.isDefault() )
112 hide_item = !GuiChatItem::defaultChatName().contains( m_filter, Qt::CaseInsensitive );
113 else
114 hide_item = !c.name().contains( m_filter, Qt::CaseInsensitive );
115 }
116
117 item->setHidden( hide_item );
118 }
119
updateUser(const User & u)120 void GuiChatList::updateUser( const User& u )
121 {
122 QList<Chat> chat_list = ChatManager::instance().chatsWithUser( u.id() );
123 foreach( Chat c, chat_list )
124 updateChat( c );
125 }
126
chatClicked(QTreeWidgetItem * item,int)127 void GuiChatList::chatClicked( QTreeWidgetItem* item, int )
128 {
129 if( m_blockShowChatRequest )
130 {
131 m_blockShowChatRequest = false;
132 return;
133 }
134
135 if( !item )
136 return;
137
138 mp_twChatList->clearSelection();
139 GuiChatItem* user_item = dynamic_cast<GuiChatItem*>( item );
140 emit chatSelected( user_item->chatId() );
141 }
142
showChatMenu(const QPoint & p)143 void GuiChatList::showChatMenu( const QPoint& p )
144 {
145 mp_menuContext->clear();
146 QAction* act;
147
148 QTreeWidgetItem* item = mp_twChatList->itemAt( p );
149 if( !item )
150 {
151 bool create_chat_is_enabled = true;
152 if( UserManager::instance().userList().toList().size() < 2 )
153 {
154 mp_menuContext->addAction( IconManager::instance().icon( "info.png" ), tr( "Please wait for two or more users" ) );
155 create_chat_is_enabled = false;
156 mp_menuContext->addSeparator();
157 }
158
159
160 act = mp_menuContext->addAction( IconManager::instance().icon( "message-create.png" ), tr( "Write a message" ), this, SIGNAL( createNewMessageRequest() ) );
161 act->setEnabled( !Settings::instance().disableCreateMessage() );
162 act = mp_menuContext->addAction( IconManager::instance().icon( "group-create.png" ), tr( "Create new group chat" ), this, SIGNAL( createNewChatRequest() ) );
163 act->setEnabled( create_chat_is_enabled );
164 }
165 else
166 {
167 GuiChatItem* chat_item = dynamic_cast<GuiChatItem*>( item );
168 m_chatSelected = chat_item->chatId();
169 Chat c = ChatManager::instance().chat( m_chatSelected );
170 if( !c.isValid() )
171 {
172 mp_twChatList->clearSelection();
173 qWarning() << "ChatListView is unable to find chat id" << m_chatSelected << " and item is hidden";
174 item->setHidden( true );
175 return;
176 }
177 act = mp_menuContext->addAction( IconManager::instance().icon( "chat.png" ), tr( "Show" ), this, SLOT( openChatSelected() ) );
178 mp_menuContext->setDefaultAction( act );
179 mp_menuContext->addSeparator();
180 act = mp_menuContext->addAction( IconManager::instance().icon( "clear.png" ), tr( "Clear" ), this, SLOT( clearChatSelected() ) );
181 act->setToolTip( tr( "Clear all chat messages" ) );
182 act->setDisabled( ChatManager::instance().isChatEmpty( c, true ) );
183 if( c.isGroup() )
184 {
185 mp_menuContext->addSeparator();
186 mp_menuContext->addAction( IconManager::instance().icon( "group-edit.png" ), tr( "Edit" ), this, SLOT( editChatSelected() ) );
187 }
188 m_blockShowChatRequest = true;
189 }
190
191 mp_menuContext->addSeparator();
192 mp_menuContext->addAction( IconManager::instance().icon( "background-color.png" ), tr( "Change background color" ) + QString("..."), this, SLOT( selectBackgroundColor() ) );
193 mp_menuContext->addSeparator();
194 act = mp_menuContext->addAction( tr( "Hide empty chats" ), this, SIGNAL( hideEmptyChatsRequest() ) );
195 act->setCheckable( true );
196 act->setChecked( Settings::instance().hideEmptyChatsInList() );
197 mp_menuContext->exec( QCursor::pos() );
198 mp_twChatList->clearSelection();
199 }
200
openChatSelected()201 void GuiChatList::openChatSelected()
202 {
203 emit chatSelected( m_chatSelected );
204 }
205
clearChatSelected()206 void GuiChatList::clearChatSelected()
207 {
208 emit chatToClear( m_chatSelected );
209 }
210
editChatSelected()211 void GuiChatList::editChatSelected()
212 {
213 emit chatToEdit( m_chatSelected );
214 }
215
onTickEvent(int ticks)216 void GuiChatList::onTickEvent( int ticks )
217 {
218 GuiChatItem* item;
219 QTreeWidgetItemIterator it( mp_twChatList );
220 while( *it )
221 {
222 item = dynamic_cast<GuiChatItem*>( *it );
223 item->onTickEvent( ticks );
224 ++it;
225 }
226 }
227
filterText(const QString & txt)228 void GuiChatList::filterText( const QString& txt )
229 {
230 QString new_filter = txt.trimmed().toLower();
231 if( m_filter == new_filter )
232 return;
233
234 m_filter = new_filter;
235 updateChats();
236 }
237
clearFilter()238 void GuiChatList::clearFilter()
239 {
240 mp_leFilter->setText( "" );
241 mp_leFilter->setFocus();
242 }
243
selectBackgroundColor()244 void GuiChatList::selectBackgroundColor()
245 {
246 QColor c = Bee::selectColor( this, Settings::instance().chatListBackgroundColor() );
247 if( c.isValid() )
248 {
249 Settings::instance().setChatListBackgroundColor( c.name() );
250 updateBackground();
251 }
252 }
253
updateBackground()254 void GuiChatList::updateBackground()
255 {
256 QString w_stylesheet = Settings::instance().guiCustomListStyleSheet( Settings::instance().chatListBackgroundColor(),
257 IconManager::instance().iconPath( "chat-list.png" ) );
258 mp_twChatList->setStyleSheet( w_stylesheet );
259 }
260
showMenuSettings()261 void GuiChatList::showMenuSettings()
262 {
263 bool create_chat_is_enabled = UserManager::instance().userList().toList().size() >= 2;
264 QAction* act;
265 mp_menuSettings->clear();
266 act = mp_menuSettings->addAction( IconManager::instance().icon( "message-create.png" ), tr( "Write a message" ), this, SIGNAL( createNewMessageRequest() ) );
267 act->setEnabled( !Settings::instance().disableCreateMessage() );
268 act = mp_menuSettings->addAction( IconManager::instance().icon( "group-create.png" ), tr( "Create new group chat" ), this, SIGNAL( createNewChatRequest() ) );
269 act->setEnabled( create_chat_is_enabled );
270 mp_menuSettings->addSeparator();
271 mp_menuSettings->addAction( IconManager::instance().icon( "background-color.png" ), tr( "Change background color" ) + QString("..."), this, SLOT( selectBackgroundColor() ) );
272 mp_menuSettings->addSeparator();
273 act = mp_menuSettings->addAction( tr( "Hide empty chats" ), this, SIGNAL( hideEmptyChatsRequest() ) );
274 act->setCheckable( true );
275 act->setChecked( Settings::instance().hideEmptyChatsInList() );
276 mp_menuSettings->exec( QCursor::pos() );
277 }
278