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: GuiShareLocal.cpp 1455 2020-12-23 10:17:53Z mastroddi $
21 //
22 //////////////////////////////////////////////////////////////////////
23 
24 #include "BeeUtils.h"
25 #include "GuiShareLocal.h"
26 #include "FileDialog.h"
27 #include "FileShare.h"
28 #include "IconManager.h"
29 #include "Settings.h"
30 
31 
GuiShareLocal(QWidget * parent)32 GuiShareLocal::GuiShareLocal( QWidget *parent )
33   : QWidget(parent)
34 {
35   setupUi( this );
36   setAcceptDrops( true );
37 
38   QString window_title = QString( "<b>%1</b> (%2)" ).arg( tr( "Share your folders or files" ) ).arg( Settings::instance().enableFileSharing() ? tr( "max <b>%1</b> files" ).arg( Settings::instance().maxFileShared() ) : tr( "disabled" ) );
39   mp_lTitle->setText( window_title );
40 
41   mp_twMyShares->setContextMenuPolicy( Qt::CustomContextMenu );
42   mp_twMyShares->setRootIsDecorated( false );
43   mp_twMyShares->setSortingEnabled( true );
44   mp_twMyShares->setAlternatingRowColors( true );
45   mp_twMyShares->setSortingEnabled( true );
46 
47   QStringList labels;
48   labels << tr( "File" ) << tr( "Size" ) << tr( "Path" );
49   mp_twMyShares->setHeaderLabels( labels );
50 
51   QHeaderView* header_view = mp_twMyShares->header();
52 #if QT_VERSION >= 0x050000
53   header_view->setSectionResizeMode( 0, QHeaderView::ResizeToContents );
54   header_view->setSectionResizeMode( 1, QHeaderView::ResizeToContents );
55   header_view->setSectionResizeMode( 2, QHeaderView::Stretch );
56 #else
57   header_view->setResizeMode( 0, QHeaderView::ResizeToContents );
58   header_view->setResizeMode( 1, QHeaderView::ResizeToContents );
59   header_view->setResizeMode( 2, QHeaderView::Stretch );
60 #endif
61   header_view->setSortIndicator( 2, Qt::AscendingOrder );
62 
63   mp_menuContext = new QMenu( this );
64 
65   connect( mp_twMyShares, SIGNAL( customContextMenuRequested( const QPoint& ) ), this, SLOT( openMySharesMenu( const QPoint& ) ) );
66   connect( mp_twMyShares, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( openItemDoubleClicked( QTreeWidgetItem*, int ) ) );
67 }
68 
setupToolBar(QToolBar * bar)69 void GuiShareLocal::setupToolBar( QToolBar* bar )
70 {
71   mp_labelShareStats = new QLabel( bar );
72   mp_labelShareStats->setObjectName( "GuiLabelLocalShareStats" );
73   mp_labelShareStats->setAlignment( Qt::AlignLeft | Qt::AlignVCenter );
74   bar->addWidget( mp_labelShareStats );
75   bar->addSeparator();
76 
77   mp_actAddFile = bar->addAction( IconManager::instance().icon( "file-add.png" ), tr( "Share a file" ), this, SLOT( addFilePath() ) );
78   mp_actAddFile->setStatusTip( tr( "Add a file to your local share" ) );
79 
80   mp_actAddFolder = bar->addAction( IconManager::instance().icon( "folder-add.png" ), tr( "Share a folder" ), this, SLOT( addFolderPath() ) );
81   mp_actAddFolder->setStatusTip( tr( "Add a folder to your local share" ) );
82 
83   mp_actUpdate = bar->addAction( IconManager::instance().icon( "update.png" ), tr( "Update shares" ), this, SLOT( updateList() ) );
84   mp_actUpdate->setStatusTip( tr( "Update shared folders and files" ) );
85 
86   mp_actRemove = bar->addAction( IconManager::instance().icon( "delete.png" ), tr( "Remove shared path" ), this, SLOT( removePath() ) );
87   mp_actRemove->setStatusTip( tr( "Remove shared path from the list" ) );
88 
89   mp_actClear = bar->addAction( IconManager::instance().icon( "clear.png" ), tr( "Clear all shares" ), this, SLOT( clearAllPaths() ) );
90   mp_actClear->setStatusTip( tr( "Clear all shared paths from the list" ) );
91 
92   showStats( 0, 0 );
93   setActionsEnabled( true );
94 }
95 
showStats(int file_count,FileSizeType total_file_size)96 void GuiShareLocal::showStats( int file_count, FileSizeType total_file_size )
97 {
98   if( Settings::instance().enableFileTransfer() && Settings::instance().enableFileSharing() )
99     mp_labelShareStats->setText( QString( "%1: <b>%2</b> (%3)  " ).arg( tr( "Shared files" ) ).arg( file_count ).arg( Bee::bytesToString( total_file_size ) ) );
100   else
101     mp_labelShareStats->setText( QString( "<b>%1</b>  " ).arg( tr( "File transfer is disabled" ) ) );
102 }
103 
setActionsEnabled(bool enable)104 void GuiShareLocal::setActionsEnabled( bool enable )
105 {
106   mp_actAddFile->setEnabled( enable );
107   mp_actAddFolder->setEnabled( enable );
108   mp_actRemove->setEnabled( enable && mp_twMyShares->topLevelItemCount() > 0 );
109   mp_actUpdate->setEnabled( enable && mp_twMyShares->topLevelItemCount() > 0 );
110   mp_actClear->setEnabled( enable && mp_twMyShares->topLevelItemCount() > 0 );
111   if( enable )
112     setCursor( Qt::ArrowCursor );
113   else
114     setCursor( Qt::WaitCursor );
115 }
116 
addFilePath()117 void GuiShareLocal::addFilePath()
118 {
119   QStringList file_path_list = FileDialog::getOpenFileNames( true, this, tr( "Select a file to share" ),
120                                                      Settings::instance().lastDirectorySelected() );
121   if( file_path_list.isEmpty() )
122     return;
123 
124   Settings::instance().setLastDirectorySelectedFromFile( file_path_list.last() );
125 
126   foreach( QString file_path, file_path_list )
127     addSharePath( file_path );
128 }
129 
addFolderPath()130 void GuiShareLocal::addFolderPath()
131 {
132   QString folder_path = FileDialog::getExistingDirectory( this, tr( "Select a folder to share" ),
133                                                            Settings::instance().lastDirectorySelected() );
134   if( folder_path.isEmpty() )
135     return;
136 
137   Settings::instance().setLastDirectorySelected( Bee::convertToNativeFolderSeparator( folder_path ) );
138 
139   addSharePath( folder_path );
140 }
141 
removePath()142 void GuiShareLocal::removePath()
143 {
144   if( Settings::instance().localShare().isEmpty() )
145     return;
146 
147   QList<QTreeWidgetItem*> item_list = mp_twMyShares->selectedItems();
148   if( item_list.isEmpty() )
149   {
150     QMessageBox::information( this, Settings::instance().programName(), tr( "Please select a shared path." ) );
151     mp_twMyShares->setFocus();
152     return;
153   }
154 
155   QString share_selected = item_list.first()->text( 2 );
156 
157   if( QMessageBox::question( this, Settings::instance().programName(), tr( "Do you want to remove this path:" )
158                              + QString( "\n%1").arg( share_selected ),
159                              tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
160     return;
161 
162   setActionsEnabled( false );
163 
164   emit sharePathRemoved( share_selected );
165 }
166 
clearAllPaths()167 void GuiShareLocal::clearAllPaths()
168 {
169   if( Settings::instance().localShare().isEmpty() )
170     return;
171 
172   if( QMessageBox::question( this, Settings::instance().programName(), tr( "Do you want to remove all shared paths?" ),
173                              tr( "Yes" ), tr( "No" ), QString(), 1, 1 ) != 0 )
174     return;
175 
176   emit removeAllPathsRequest();
177 }
178 
updatePaths()179 void GuiShareLocal::updatePaths()
180 {
181   mp_twMyShares->clear();
182   if( Settings::instance().localShare().isEmpty() )
183     return;
184   QTreeWidgetItem *item;
185   mp_twMyShares->setUpdatesEnabled( false );
186   foreach( QString share_path, Settings::instance().localShare() )
187   {
188     item = new QTreeWidgetItem( mp_twMyShares );
189     item->setText( 0, QString::number( FileShare::instance().local().count( share_path ) ) );
190     item->setData( 0, Qt::UserRole + 1, share_path );
191     item->setText( 1, Bee::bytesToString( FileShare::instance().localSize( share_path ) ) );
192     item->setText( 2, share_path );
193   }
194   mp_twMyShares->setUpdatesEnabled( true );
195 }
196 
updateFileSharedList()197 void GuiShareLocal::updateFileSharedList()
198 {
199   setActionsEnabled( false );
200   updatePaths();
201   int file_count = 0;
202   FileSizeType total_file_size = 0;
203 
204   if( !FileShare::instance().local().isEmpty() )
205   {
206     foreach( FileInfo fi, FileShare::instance().local() )
207     {
208       file_count++;
209       total_file_size += fi.size();
210     }
211   }
212 
213   showStats( file_count, total_file_size );
214   setActionsEnabled( true );
215 }
216 
addSharePath(const QString & sp)217 void GuiShareLocal::addSharePath( const QString& sp )
218 {
219   QString share_path = Bee::convertToNativeFolderSeparator( sp );
220   if( Settings::instance().hasLocalSharePath( share_path ) )
221   {
222     QMessageBox::information( this, Settings::instance().programName(),
223       tr( "%1 is already shared." ).arg( share_path ) );
224     return;
225   }
226 
227   QStringList local_share = Settings::instance().localShare();
228   local_share << share_path;
229   Settings::instance().setLocalShare( local_share );
230 
231   updatePaths();
232 
233   if( !isFileSharingEnabled() )
234     return;
235 
236   setActionsEnabled( false );
237 
238   emit sharePathAdded( share_path );
239 }
240 
openItemDoubleClicked(QTreeWidgetItem * item,int)241 void GuiShareLocal::openItemDoubleClicked( QTreeWidgetItem* item, int )
242 {
243   if( !item )
244     return;
245 
246   QString file_path = item->data( 0, Qt::UserRole + 1 ).toString();
247   if( !file_path.isEmpty() )
248     emit openUrlRequest( QUrl::fromLocalFile( file_path ) );
249 }
250 
updateList()251 void GuiShareLocal::updateList()
252 {
253   if( !isFileSharingEnabled() )
254     return;
255   setActionsEnabled( false );
256   emit updateListRequest();
257 }
258 
isFileSharingEnabled()259 bool GuiShareLocal::isFileSharingEnabled()
260 {
261   if( Settings::instance().enableFileTransfer() && Settings::instance().enableFileSharing() )
262     return true;
263 
264   QMessageBox::information( this, Settings::instance().programName(), tr( "File transfer is disabled. Open the option menu to enable it." ) );
265   return false;
266 }
267 
dragEnterEvent(QDragEnterEvent * event)268 void GuiShareLocal::dragEnterEvent( QDragEnterEvent *event )
269 {
270   if( event->mimeData()->hasUrls() )
271     event->acceptProposedAction();
272 }
273 
dropEvent(QDropEvent * event)274 void GuiShareLocal::dropEvent( QDropEvent *event )
275 {
276   if( event->mimeData()->hasUrls() )
277   {
278     foreach( QUrl url, event->mimeData()->urls() )
279     {
280 #if QT_VERSION >= 0x040800
281       if( url.isLocalFile() )
282 #else
283       if( url.scheme() == QLatin1String( "file" ) )
284 #endif
285         addSharePath( url.toLocalFile() );
286     }
287   }
288 }
289 
openMySharesMenu(const QPoint & p)290 void GuiShareLocal::openMySharesMenu( const QPoint& p )
291 {
292   QTreeWidgetItem* item = mp_twMyShares->itemAt( p );
293 
294   mp_menuContext->clear();
295 
296   if( item )
297   {
298     if( !item->isSelected() )
299       item->setSelected( true );
300     mp_menuContext->addAction( mp_actRemove );
301   }
302   else
303   {
304     mp_menuContext->addAction( mp_actAddFile );
305     mp_menuContext->addAction( mp_actAddFolder );
306   }
307 
308   mp_menuContext->exec( QCursor::pos() );
309 }
310