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: GuiFileInfoList.cpp 1455 2020-12-23 10:17:53Z mastroddi $
21 //
22 //////////////////////////////////////////////////////////////////////
23 
24 #include "BeeUtils.h"
25 #include "GuiFileInfoList.h"
26 #include "FileShare.h"
27 #include "Settings.h"
28 #include "User.h"
29 
30 
GuiFileInfoList()31 GuiFileInfoList::GuiFileInfoList()
32  : QObject( 0 ), mp_tree( 0 ), m_selectedFileInfoList(), m_isLocal( true )
33 {
34 }
35 
initTree(QTreeWidget * tree_widget,bool is_local)36 void GuiFileInfoList::initTree( QTreeWidget* tree_widget, bool is_local )
37 {
38   m_isLocal = is_local;
39   mp_tree = tree_widget;
40   mp_tree->setColumnCount( 3 );
41 
42   QStringList labels;
43   labels << tr( "Shared folders and files" ) << tr( "Size" ) << tr( "Status" );
44   mp_tree->setHeaderLabels( labels );
45 
46   mp_tree->sortItems( GuiFileInfoItem::ColumnFile, Qt::AscendingOrder );
47 
48   mp_tree->setAlternatingRowColors( true );
49   mp_tree->setRootIsDecorated( true );
50   mp_tree->setContextMenuPolicy( Qt::CustomContextMenu );
51   mp_tree->setSelectionMode( QAbstractItemView::ExtendedSelection );
52 
53   QHeaderView* hv = mp_tree->header();
54 #if QT_VERSION >= 0x050000
55   hv->setSectionResizeMode( GuiFileInfoItem::ColumnFile, QHeaderView::Stretch );
56   hv->setSectionResizeMode( GuiFileInfoItem::ColumnSize, QHeaderView::ResizeToContents );
57   hv->setSectionResizeMode( GuiFileInfoItem::ColumnStatus, QHeaderView::ResizeToContents );
58 #else
59   hv->setResizeMode( GuiFileInfoItem::ColumnFile, QHeaderView::Stretch );
60   hv->setResizeMode( GuiFileInfoItem::ColumnSize, QHeaderView::ResizeToContents );
61   hv->setResizeMode( GuiFileInfoItem::ColumnStatus, QHeaderView::ResizeToContents );
62 #endif
63 }
64 
clearTree()65 void GuiFileInfoList::clearTree()
66 {
67   if( mp_tree->topLevelItemCount() > 0 )
68     mp_tree->clear();
69   m_selectedFileInfoList.clear();
70 }
71 
clearTreeSelection()72 void GuiFileInfoList::clearTreeSelection()
73 {
74   mp_tree->clearSelection();
75   m_selectedFileInfoList.clear();
76 }
77 
userItem(VNumber user_id)78 GuiFileInfoItem* GuiFileInfoList::userItem( VNumber user_id )
79 {
80   GuiFileInfoItem* item;
81   QTreeWidgetItemIterator it( mp_tree );
82   while( *it )
83   {
84     item = (GuiFileInfoItem*)(*it);
85     if( item->isObjectUser() && item->userId() == user_id )
86     {
87       return item;
88     }
89     ++it;
90   }
91   return 0;
92 }
93 
createUserItem(const User & u)94 GuiFileInfoItem* GuiFileInfoList::createUserItem( const User& u )
95 {
96   GuiFileInfoItem* item = new GuiFileInfoItem( mp_tree );
97   item->initUser( u.id(), Bee::userNameToShow( u, false ) );
98   return item;
99 }
100 
folderItem(VNumber user_id,const QString & folder_name)101 GuiFileInfoItem* GuiFileInfoList::folderItem( VNumber user_id, const QString& folder_name )
102 {
103   GuiFileInfoItem* item;
104   QTreeWidgetItemIterator it( mp_tree );
105   while( *it )
106   {
107     item = (GuiFileInfoItem*)(*it);
108     if( item->isObjectFolder() && item->userId() == user_id && item->folder() == folder_name )
109     {
110       return item;
111     }
112     ++it;
113   }
114   return 0;
115 }
116 
createSubFolderItem(GuiFileInfoItem * parent_item,VNumber user_id,const QString & subfolder_name,const QString & subfolder_path)117 GuiFileInfoItem* GuiFileInfoList::createSubFolderItem( GuiFileInfoItem* parent_item, VNumber user_id,
118                                                        const QString& subfolder_name, const QString& subfolder_path )
119 {
120   GuiFileInfoItem* item;
121   if( parent_item )
122     item = new GuiFileInfoItem( parent_item );
123   else
124     item = new GuiFileInfoItem( mp_tree );
125 
126   item->initFolder( user_id, subfolder_name, subfolder_path );
127 
128   return item;
129 }
130 
createFolderItem(const User & u,const QString & folder_name)131 GuiFileInfoItem* GuiFileInfoList::createFolderItem( const User& u, const QString& folder_name )
132 {
133   GuiFileInfoItem* parent_item = 0;
134   GuiFileInfoItem* item = 0;
135   if( !u.isLocal() )
136   {
137     parent_item = userItem( u.id() );
138     if( !parent_item )
139       parent_item = createUserItem( u );
140   }
141 
142   QStringList folder_list_path = folder_name.split( Bee::nativeFolderSeparator(), QString::SkipEmptyParts );
143 
144   if( !folder_list_path.isEmpty() )
145   {
146     QString subfolder_path = "";
147     foreach( QString fn, folder_list_path )
148     {
149       if( subfolder_path.isEmpty() )
150         subfolder_path = fn;
151       else
152         subfolder_path = subfolder_path + Bee::nativeFolderSeparator() + fn;
153       item = folderItem( u.id(), subfolder_path );
154       if( !item )
155         item = createSubFolderItem( parent_item, u.id(), fn, subfolder_path );
156       parent_item = item;
157     }
158   }
159   else
160     item = parent_item;
161 
162   return item;
163 }
164 
fileItem(VNumber user_id,VNumber file_info_id)165 GuiFileInfoItem* GuiFileInfoList::fileItem( VNumber user_id, VNumber file_info_id )
166 {
167   GuiFileInfoItem* item;
168   QTreeWidgetItemIterator it( mp_tree );
169   while( *it )
170   {
171     item = (GuiFileInfoItem*)(*it);
172     if( item->isObjectFile() && item->userId() == user_id && item->fileInfoId() == file_info_id )
173       return item;
174     ++it;
175   }
176   return 0;
177 }
178 
createFileItem(const User & u,const FileInfo & file_info)179 GuiFileInfoItem* GuiFileInfoList::createFileItem( const User& u, const FileInfo& file_info )
180 {
181   GuiFileInfoItem* parent_item = 0;
182   if( file_info.shareFolder().isEmpty() )
183   {
184     if( !u.isLocal() )
185     {
186       parent_item = userItem( u.id() );
187       if( !parent_item )
188         parent_item = createUserItem( u );
189     }
190   }
191   else
192   {
193     parent_item = folderItem( u.id(), file_info.shareFolder() );
194     if( !parent_item )
195       parent_item = createFolderItem( u, file_info.shareFolder() );
196   }
197 
198   GuiFileInfoItem* item;
199   if( parent_item )
200     item = new GuiFileInfoItem( parent_item );
201   else
202     item = new GuiFileInfoItem( mp_tree );
203 
204   item->initFile( u.id(), file_info );
205   return item;
206 }
207 
addFileInfoToList(VNumber user_id,const FileInfo & fi)208 void GuiFileInfoList::addFileInfoToList( VNumber user_id, const FileInfo& fi )
209 {
210   SharedFileInfo sfi( user_id, fi );
211   if( !m_selectedFileInfoList.contains( sfi ) )
212     m_selectedFileInfoList.append( sfi );
213 }
214 
addItemToFileInfoList(GuiFileInfoItem * fi_item)215 void GuiFileInfoList::addItemToFileInfoList( GuiFileInfoItem* fi_item )
216 {
217   if( !fi_item->isObjectFile() )
218     return;
219 
220   FileInfo fi = m_isLocal ? FileShare::instance().localFileInfo( fi_item->fileInfoId() ) : FileShare::instance().networkFileInfo( fi_item->userId(), fi_item->fileInfoId() );
221   if( !fi.isValid() )
222   {
223 #ifdef BEEBEEP_DEBUG
224     qWarning() << "Unable to add an invalid file info in list:" << fi_item->text( GuiFileInfoItem::ColumnFile );
225 #endif
226     return;
227   }
228 
229   addFileInfoToList( fi_item->userId(), fi );
230 }
231 
parseItem(QTreeWidgetItem * tw_item)232 void GuiFileInfoList::parseItem( QTreeWidgetItem* tw_item )
233 {
234   if( m_selectedFileInfoList.size() > Settings::instance().maxQueuedDownloads() )
235     return;
236 
237   GuiFileInfoItem* item = (GuiFileInfoItem*)(tw_item);
238 
239   if( item->isObjectFile() )
240   {
241     addItemToFileInfoList( item );
242   }
243   else if( item->isObjectFolder()  )
244   {
245     if( item->childCount() > 0 )
246     {
247       for( int i=0; i < item->childCount(); i++ )
248       {
249         parseItem( item->child( i ) );
250         QApplication::processEvents(); // we don't want to block socket operations
251         if( m_selectedFileInfoList.size() > Settings::instance().maxQueuedDownloads() )
252           return;
253       }
254     }
255   }
256   else if( item->isObjectUser() )
257   {
258     QList<FileInfo> user_file_info_list = m_isLocal ? FileShare::instance().fileSharedFromLocalUser() : FileShare::instance().fileSharedFromUser( item->userId() );
259     foreach( FileInfo fi, user_file_info_list )
260     {
261       addFileInfoToList( item->userId(), fi );
262       if( selectedFileInfoList().size() > Settings::instance().maxQueuedDownloads() )
263         return;
264     }
265   }
266   else
267     qWarning() << "Invalid GuiFileInfoItem object found";
268 }
269 
parseSelectedItems()270 int GuiFileInfoList::parseSelectedItems()
271 {
272   m_selectedFileInfoList.clear();
273   QList<QTreeWidgetItem*> selected_items = mp_tree->selectedItems();
274   if( selected_items.isEmpty() )
275     return 0;
276 
277   mp_tree->setUpdatesEnabled( false );
278   QApplication::setOverrideCursor( Qt::WaitCursor );
279   QApplication::processEvents();
280   foreach( QTreeWidgetItem* item, selected_items )
281   {
282     parseItem( item );
283     QApplication::processEvents(); // we don't want to block socket operations;
284   }
285 
286   QApplication::restoreOverrideCursor();
287   mp_tree->setUpdatesEnabled( true );
288 
289   return m_selectedFileInfoList.size();
290 }
291 
countFileItems() const292 int GuiFileInfoList::countFileItems() const
293 {
294   int count_file_items = 0;
295   GuiFileInfoItem* item;
296   QTreeWidgetItemIterator it( mp_tree );
297   while( *it )
298   {
299     item = (GuiFileInfoItem*)(*it);
300     if( item->isObjectFile() )
301       count_file_items++;
302     ++it;
303   }
304   return count_file_items;
305 }
306