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