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