2019-11-26 14:19:29 +01:00
#include "RemovableDriveManager.hpp"
#include <iostream>
2019-11-27 11:33:36 +01:00
#include "boost/nowide/convert.hpp"
2019-11-26 14:19:29 +01:00
2019-11-26 15:52:18 +01:00
#if _WIN32
#include <windows.h>
#include <tchar.h>
2019-11-27 11:33:36 +01:00
#include <winioctl.h>
2019-11-27 13:30:45 +01:00
#include <shlwapi.h>
2019-12-05 14:07:02 +01:00
2019-12-06 16:51:04 +01:00
#include <Dbt.h>
GUID WceusbshGUID = { 0x25dbce51 , 0x6c8f , 0x4a72 ,
0x8a , 0x6d , 0xb5 , 0x4c , 0x2b , 0x4f , 0xc8 , 0x35 };
2019-12-05 14:07:02 +01:00
2019-11-26 15:52:18 +01:00
#else
//linux includes
#include <errno.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <glob.h>
2019-11-28 16:35:22 +01:00
#include <pwd.h>
2019-12-19 17:05:23 +01:00
#include <boost/filesystem.hpp>
2020-01-06 11:32:17 +01:00
#include <boost/filesystem/convenience.hpp>
2019-11-26 15:52:18 +01:00
#endif
2019-11-26 14:19:29 +01:00
namespace Slic3r {
2019-12-03 10:09:53 +01:00
namespace GUI {
2019-11-26 15:52:18 +01:00
#if _WIN32
2020-01-22 17:05:26 +01:00
/* currently not used, left for possible future use
2019-12-06 16:51:04 +01:00
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
2020-01-22 17:05:26 +01:00
*/
2019-11-27 11:33:36 +01:00
void RemovableDriveManager :: search_for_drives ()
2019-11-26 14:19:29 +01:00
{
2019-11-27 11:33:36 +01:00
m_current_drives . clear ();
2019-12-13 11:52:08 +01:00
//get logical drives flags by letter in alphabetical order
2019-11-27 14:30:10 +01:00
DWORD drives_mask = GetLogicalDrives ();
2019-11-26 14:19:29 +01:00
for ( size_t i = 0 ; i < 26 ; i ++ )
{
2019-11-27 14:30:10 +01:00
if ( drives_mask & ( 1 << i ))
2019-11-26 14:19:29 +01:00
{
std :: string path ( 1 ,( char )( 'A' + i ));
path += ":" ;
2019-11-27 14:30:10 +01:00
UINT drive_type = GetDriveTypeA ( path . c_str ());
2019-12-13 11:52:08 +01:00
// DRIVE_REMOVABLE on W are sd cards and usb thumbnails (not usb harddrives)
2019-11-27 14:30:10 +01:00
if ( drive_type == DRIVE_REMOVABLE )
2019-11-26 14:19:29 +01:00
{
// get name of drive
2020-01-22 17:05:26 +01:00
std :: wstring wpath = boost :: nowide :: widen ( path );
2019-11-27 14:30:10 +01:00
std :: wstring volume_name ;
volume_name . resize ( 1024 );
std :: wstring file_system_name ;
file_system_name . resize ( 1024 );
LPWSTR lp_volume_name_buffer = new wchar_t ;
BOOL error = GetVolumeInformationW ( wpath . c_str (), & volume_name [ 0 ], sizeof ( volume_name ), NULL , NULL , NULL , & file_system_name [ 0 ], sizeof ( file_system_name ));
2019-11-26 14:19:29 +01:00
if ( error != 0 )
{
2019-12-13 18:02:25 +01:00
volume_name . erase ( std :: find ( volume_name . begin (), volume_name . end (), '\0' ), volume_name . end ());
2019-11-27 14:30:10 +01:00
if ( file_system_name != L "" )
2019-11-26 14:19:29 +01:00
{
2019-11-27 14:30:10 +01:00
ULARGE_INTEGER free_space ;
GetDiskFreeSpaceExA ( path . c_str (), & free_space , NULL , NULL );
if ( free_space . QuadPart > 0 )
2019-11-26 14:19:29 +01:00
{
2019-12-03 10:55:38 +01:00
path += " \\ " ;
2019-11-27 14:30:10 +01:00
m_current_drives . push_back ( DriveData ( boost :: nowide :: narrow ( volume_name ), path ));
2019-11-26 14:19:29 +01:00
}
}
}
}
}
}
}
2019-11-27 11:33:36 +01:00
void RemovableDriveManager :: eject_drive ( const std :: string & path )
2019-11-26 14:19:29 +01:00
{
2019-11-27 11:33:36 +01:00
if ( m_current_drives . empty ())
2019-11-26 14:19:29 +01:00
return ;
2019-11-27 11:33:36 +01:00
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
2019-11-26 14:19:29 +01:00
{
if (( * it ). path == path )
{
2019-12-13 11:52:08 +01:00
// get handle to device
2019-11-27 11:33:36 +01:00
std :: string mpath = " \\\\ . \\ " + path ;
2019-12-03 10:55:38 +01:00
mpath = mpath . substr ( 0 , mpath . size () - 1 );
2019-11-27 11:33:36 +01:00
HANDLE handle = CreateFileA ( mpath . c_str (), GENERIC_READ | GENERIC_WRITE , FILE_SHARE_READ | FILE_SHARE_WRITE , nullptr , OPEN_EXISTING , 0 , nullptr );
if ( handle == INVALID_HANDLE_VALUE )
{
std :: cerr << "Ejecting " << mpath << " failed " << GetLastError () << " \n " ;
return ;
}
DWORD deviceControlRetVal ( 0 );
2019-12-13 11:52:08 +01:00
//these 3 commands should eject device safely but they dont, the device does disappear from file explorer but the "device was safely remove" notification doesnt trigger.
//sd cards does trigger WM_DEVICECHANGE messege, usb drives dont
2019-12-11 17:02:12 +01:00
DeviceIoControl ( handle , FSCTL_LOCK_VOLUME , nullptr , 0 , nullptr , 0 , & deviceControlRetVal , nullptr );
DeviceIoControl ( handle , FSCTL_DISMOUNT_VOLUME , nullptr , 0 , nullptr , 0 , & deviceControlRetVal , nullptr );
2019-12-13 11:52:08 +01:00
// some implemenatations also calls IOCTL_STORAGE_MEDIA_REMOVAL here but it returns error to me
2019-11-27 11:33:36 +01:00
BOOL error = DeviceIoControl ( handle , IOCTL_STORAGE_EJECT_MEDIA , nullptr , 0 , nullptr , 0 , & deviceControlRetVal , nullptr );
2019-11-27 14:30:10 +01:00
if ( error == 0 )
{
2019-12-11 17:02:12 +01:00
CloseHandle ( handle );
2019-11-27 11:33:36 +01:00
std :: cerr << "Ejecting " << mpath << " failed " << deviceControlRetVal << " " << GetLastError () << " \n " ;
2019-12-03 10:09:53 +01:00
return ;
2019-11-27 14:30:10 +01:00
}
2019-12-11 17:02:12 +01:00
CloseHandle ( handle );
2019-12-16 13:53:12 +01:00
m_did_eject = true ;
2019-11-27 11:33:36 +01:00
m_current_drives . erase ( it );
2020-01-21 10:23:50 +01:00
m_ejected_path = m_last_save_path ;
m_ejected_name = m_last_save_name ;
2019-11-26 14:19:29 +01:00
break ;
}
}
}
2019-11-27 14:30:10 +01:00
bool RemovableDriveManager :: is_path_on_removable_drive ( const std :: string & path )
{
if ( m_current_drives . empty ())
return false ;
2019-12-19 11:47:02 +01:00
std :: size_t found = path . find_last_of ( " \\ " );
std :: string new_path = path . substr ( 0 , found );
int letter = PathGetDriveNumberA ( new_path . c_str ());
2019-11-27 14:30:10 +01:00
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
{
char drive = ( * it ). path [ 0 ];
if ( drive == ( 'A' + letter ))
return true ;
}
return false ;
}
2019-12-05 14:07:02 +01:00
std :: string RemovableDriveManager :: get_drive_from_path ( const std :: string & path )
{
2019-12-19 11:47:02 +01:00
std :: size_t found = path . find_last_of ( " \\ " );
std :: string new_path = path . substr ( 0 , found );
int letter = PathGetDriveNumberA ( new_path . c_str ());
2019-12-05 14:07:02 +01:00
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
{
char drive = ( * it ). path [ 0 ];
if ( drive == ( 'A' + letter ))
return ( * it ). path ;
}
return "" ;
}
2019-11-28 13:38:08 +01:00
void RemovableDriveManager :: register_window ()
{
2019-12-12 14:56:30 +01:00
//creates new unvisible window that is recieving callbacks from system
2019-12-13 11:52:08 +01:00
// structure to register
2020-01-22 17:05:26 +01:00
/* currently not used, left for possible future use
2019-11-28 13:38:08 +01:00
WNDCLASSEX wndClass;
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wndClass.hInstance = reinterpret_cast<HINSTANCE>(GetModuleHandle(0));
2019-12-13 11:52:08 +01:00
wndClass.lpfnWndProc = reinterpret_cast<WNDPROC>(WinProcCallback);//this is callback
2019-11-28 13:38:08 +01:00
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hIcon = LoadIcon(0, IDI_APPLICATION);
wndClass.hbrBackground = CreateSolidBrush(RGB(192, 192, 192));
wndClass.hCursor = LoadCursor(0, IDC_ARROW);
2019-12-05 14:07:02 +01:00
wndClass.lpszClassName = L"PrusaSlicer_aux_class";
2019-11-28 13:38:08 +01:00
wndClass.lpszMenuName = NULL;
wndClass.hIconSm = wndClass.hIcon;
2019-12-06 16:51:04 +01:00
if(!RegisterClassEx(&wndClass))
{
DWORD err = GetLastError();
return;
}
2019-12-05 14:07:02 +01:00
HWND hWnd = CreateWindowEx(
2019-12-06 16:51:04 +01:00
WS_EX_NOACTIVATE,
2019-12-05 14:07:02 +01:00
L"PrusaSlicer_aux_class",
L"PrusaSlicer_aux_wnd",
2019-12-06 16:51:04 +01:00
WS_DISABLED, // style
2019-12-05 14:07:02 +01:00
CW_USEDEFAULT, 0,
640, 480,
NULL, NULL,
2019-12-06 16:51:04 +01:00
GetModuleHandle(NULL),
2019-12-05 14:07:02 +01:00
NULL);
2019-12-06 16:51:04 +01:00
if(hWnd == NULL)
{
DWORD err = GetLastError();
}
//ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
2020-01-22 17:05:26 +01:00
*/
2019-11-28 13:38:08 +01:00
}
2020-01-22 17:05:26 +01:00
/* currently not used, left for possible future use
2019-12-05 14:07:02 +01:00
INT_PTR WINAPI WinProcCallback(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
2019-12-13 11:52:08 +01:00
// here we need to catch messeges about device removal
// problem is that when ejecting usb (how is it implemented above) there is no messege dispached. Only after physical removal of the device.
//uncomment register_window() in init() to register and comment update() in GUI_App.cpp (only for windows!) to stop recieving periodical updates
2020-01-22 17:05:26 +01:00
2019-12-05 14:07:02 +01:00
LRESULT lRet = 1;
static HDEVNOTIFY hDeviceNotify;
2019-12-06 16:51:04 +01:00
2019-12-05 14:07:02 +01:00
switch (message)
{
case WM_CREATE:
DEV_BROADCAST_DEVICEINTERFACE NotificationFilter;
ZeroMemory(&NotificationFilter, sizeof(NotificationFilter));
NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid = WceusbshGUID;
2019-12-12 14:56:30 +01:00
hDeviceNotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
2019-12-05 14:07:02 +01:00
break;
2019-12-11 17:02:12 +01:00
2019-12-05 14:07:02 +01:00
case WM_DEVICECHANGE:
{
2019-12-13 11:52:08 +01:00
// here is the important
2019-12-06 16:51:04 +01:00
if(wParam == DBT_DEVICEREMOVECOMPLETE)
2019-12-05 14:07:02 +01:00
{
2019-12-11 14:53:28 +01:00
- RemovableDriveManager::get_instance().update(0, true);
2019-12-05 14:07:02 +01:00
}
}
break;
2019-12-11 17:02:12 +01:00
2019-12-05 14:07:02 +01:00
default:
// Send all other messages on to the default windows handler.
lRet = DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return lRet;
2020-01-22 17:05:26 +01:00
2019-12-05 14:07:02 +01:00
}
2020-01-22 17:05:26 +01:00
*/
2019-11-26 15:52:18 +01:00
#else
2019-11-27 11:33:36 +01:00
void RemovableDriveManager :: search_for_drives ()
2019-11-26 15:52:18 +01:00
{
2019-12-11 17:39:34 +01:00
m_current_drives . clear ();
2019-12-09 15:33:10 +01:00
#if __APPLE__
2019-12-13 11:52:08 +01:00
// if on macos obj-c class will enumerate
2019-12-10 14:10:47 +01:00
if ( m_rdmmm )
{
m_rdmmm -> list_devices ();
}
#else
2019-12-11 17:39:34 +01:00
2019-11-26 15:52:18 +01:00
//search /media/* folder
2019-11-28 16:35:22 +01:00
search_path ( "/media/*" , "/media" );
2019-11-26 15:52:18 +01:00
2020-01-06 11:59:24 +01:00
//search_path("/Volumes/*", "/Volumes");
2019-11-28 16:35:22 +01:00
std :: string path ( std :: getenv ( "USER" ));
std :: string pp ( path );
2019-11-26 15:52:18 +01:00
2019-11-28 16:35:22 +01:00
{
//search /media/USERNAME/* folder
pp = "/media/" + pp ;
path = "/media/" + path + "/*" ;
search_path ( path , pp );
2019-11-26 15:52:18 +01:00
2019-11-28 16:35:22 +01:00
//search /run/media/USERNAME/* folder
path = "/run" + path ;
pp = "/run" + pp ;
search_path ( path , pp );
2019-11-26 15:52:18 +01:00
2019-11-28 16:35:22 +01:00
}
2019-12-10 14:10:47 +01:00
#endif
2019-11-26 15:52:18 +01:00
}
2019-11-28 16:35:22 +01:00
void RemovableDriveManager :: search_path ( const std :: string & path , const std :: string & parent_path )
2019-11-26 15:52:18 +01:00
{
glob_t globbuf ;
globbuf . gl_offs = 2 ;
int error = glob ( path . c_str (), GLOB_TILDE , NULL , & globbuf );
2019-11-28 16:35:22 +01:00
if ( error == 0 )
2019-11-26 15:52:18 +01:00
{
2019-11-27 14:30:10 +01:00
for ( size_t i = 0 ; i < globbuf . gl_pathc ; i ++ )
2019-11-26 15:52:18 +01:00
{
2019-12-10 14:41:49 +01:00
inspect_file ( globbuf . gl_pathv [ i ], parent_path );
2019-11-26 15:52:18 +01:00
}
2019-11-28 16:35:22 +01:00
} else
{
//if error - path probably doesnt exists so function just exits
//std::cout<<"glob error "<< error<< "\n";
2019-11-26 15:52:18 +01:00
}
2019-11-27 14:30:10 +01:00
2019-11-26 15:52:18 +01:00
globfree ( & globbuf );
}
2019-12-10 14:10:47 +01:00
void RemovableDriveManager :: inspect_file ( const std :: string & path , const std :: string & parent_path )
{
2019-12-13 11:52:08 +01:00
//confirms if the file is removable drive and adds it to vector
2019-12-10 14:10:47 +01:00
//if not same file system - could be removable drive
2019-12-10 14:41:49 +01:00
if ( ! compare_filesystem_id ( path , parent_path ))
2019-12-10 14:10:47 +01:00
{
2019-12-19 16:27:48 +01:00
//free space
2019-12-19 17:05:23 +01:00
boost :: filesystem :: space_info si = boost :: filesystem :: space ( path );
if ( si . available != 0 )
2019-12-10 14:10:47 +01:00
{
2019-12-19 16:27:48 +01:00
//user id
struct stat buf ;
stat ( path . c_str (), & buf );
uid_t uid = buf . st_uid ;
std :: string username ( std :: getenv ( "USER" ));
struct passwd * pw = getpwuid ( uid );
2020-01-06 11:32:17 +01:00
if ( pw != 0 && pw -> pw_name == username )
m_current_drives . push_back ( DriveData ( boost :: filesystem :: basename ( boost :: filesystem :: path ( path )), path ));
2019-12-10 14:10:47 +01:00
}
2019-12-19 16:27:48 +01:00
2019-12-10 14:10:47 +01:00
}
}
2019-11-28 16:35:22 +01:00
bool RemovableDriveManager :: compare_filesystem_id ( const std :: string & path_a , const std :: string & path_b )
{
struct stat buf ;
stat ( path_a . c_str () , & buf );
dev_t id_a = buf . st_dev ;
stat ( path_b . c_str () , & buf );
dev_t id_b = buf . st_dev ;
return id_a == id_b ;
}
2019-11-27 11:33:36 +01:00
void RemovableDriveManager :: eject_drive ( const std :: string & path )
2019-11-26 15:52:18 +01:00
{
2019-11-27 11:33:36 +01:00
if ( m_current_drives . empty ())
2019-11-26 15:52:18 +01:00
return ;
2019-11-27 11:33:36 +01:00
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
2019-11-26 15:52:18 +01:00
{
if (( * it ). path == path )
{
2019-12-04 13:10:08 +01:00
std :: string correct_path ( path );
for ( size_t i = 0 ; i < correct_path . size (); ++ i )
{
if ( correct_path [ i ] == ' ' )
{
2019-12-04 13:18:08 +01:00
correct_path = correct_path . insert ( i , 1 , '\\' );
2019-12-04 13:13:18 +01:00
i ++ ;
2019-12-04 13:10:08 +01:00
}
}
2020-01-21 13:06:10 +01:00
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
2019-12-13 11:52:08 +01:00
// there is no usable command in c++ so terminal command is used instead
// but neither triggers "succesful safe removal messege"
2019-12-04 13:30:25 +01:00
std :: string command = "" ;
#if __APPLE__
2019-12-17 13:08:17 +01:00
//m_rdmmm->eject_device(path);
2019-12-04 13:30:25 +01:00
command = "diskutil unmount " ;
#else
command = "umount " ;
#endif
2019-12-04 13:18:08 +01:00
command += correct_path ;
2019-12-03 10:09:53 +01:00
int err = system ( command . c_str ());
if ( err )
2019-11-26 15:52:18 +01:00
{
2019-12-03 10:09:53 +01:00
std :: cerr << "Ejecting failed \n " ;
return ;
2019-11-26 15:52:18 +01:00
}
2019-12-17 13:08:17 +01:00
2019-12-16 13:53:12 +01:00
m_did_eject = true ;
2019-11-27 11:33:36 +01:00
m_current_drives . erase ( it );
2020-01-21 10:23:50 +01:00
m_ejected_path = m_last_save_path ;
m_ejected_name = m_last_save_name ;
2019-11-26 15:52:18 +01:00
break ;
}
}
}
2019-11-27 14:30:10 +01:00
bool RemovableDriveManager :: is_path_on_removable_drive ( const std :: string & path )
{
if ( m_current_drives . empty ())
return false ;
2019-12-18 15:40:48 +01:00
std :: size_t found = path . find_last_of ( "/" );
2020-01-21 13:06:10 +01:00
std :: string new_path = found == path . size () - 1 ? path . substr ( 0 , found ) : path ;
2019-11-27 14:30:10 +01:00
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
{
2019-12-18 15:40:48 +01:00
if ( compare_filesystem_id ( new_path , ( * it ). path ))
2019-11-27 14:30:10 +01:00
return true ;
}
return false ;
}
2020-01-22 17:05:26 +01:00
std :: string RemovableDriveManager :: get_drive_from_path ( const std :: string & path )
2019-12-05 14:07:02 +01:00
{
2019-12-19 11:47:02 +01:00
std :: size_t found = path . find_last_of ( "/" );
2020-01-21 13:06:10 +01:00
std :: string new_path = found == path . size () - 1 ? path . substr ( 0 , found ) : path ;
2020-02-05 16:04:05 +01:00
// trim the filename
found = new_path . find_last_of ( "/" );
new_path = new_path . substr ( 0 , found );
2019-12-05 14:07:02 +01:00
//check if same filesystem
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
{
2019-12-19 11:47:02 +01:00
if ( compare_filesystem_id ( new_path , ( * it ). path ))
2019-12-05 14:07:02 +01:00
return ( * it ). path ;
}
return "" ;
}
2019-11-26 15:52:18 +01:00
#endif
2019-12-11 11:00:47 +01:00
RemovableDriveManager :: RemovableDriveManager () :
m_drives_count ( 0 ),
m_last_update ( 0 ),
2019-12-13 18:02:25 +01:00
m_last_save_path ( "" ),
m_last_save_name ( "" ),
2019-12-16 17:15:27 +01:00
m_last_save_path_verified ( false ),
2019-12-16 13:53:12 +01:00
m_is_writing ( false ),
2020-01-03 10:33:44 +01:00
m_did_eject ( false ),
2020-01-21 10:23:50 +01:00
m_plater_ready_to_slice ( true ),
m_ejected_path ( "" ),
m_ejected_name ( "" )
2019-12-11 11:00:47 +01:00
#if __APPLE__
2019-12-11 12:28:51 +01:00
, m_rdmmm ( new RDMMMWrapper ())
2019-12-11 11:00:47 +01:00
#endif
{}
2019-12-16 13:53:12 +01:00
RemovableDriveManager ::~ RemovableDriveManager ()
{
#if __APPLE__
delete m_rdmmm ;
#endif
}
2019-12-06 16:51:04 +01:00
void RemovableDriveManager :: init ()
{
2019-12-11 14:53:28 +01:00
//add_callback([](void) { RemovableDriveManager::get_instance().print(); });
2019-12-06 16:51:04 +01:00
#if _WIN32
2019-12-12 10:48:33 +01:00
//register_window();
2019-12-10 11:17:12 +01:00
#elif __APPLE__
2019-12-11 11:00:47 +01:00
m_rdmmm -> register_window ();
2019-12-06 16:51:04 +01:00
#endif
2019-12-16 14:06:25 +01:00
update ( 0 , true );
2019-12-06 16:51:04 +01:00
}
2019-12-12 14:56:30 +01:00
bool RemovableDriveManager :: update ( const long time , const bool check )
2019-11-26 15:52:18 +01:00
{
2019-11-27 15:47:37 +01:00
if ( time != 0 ) //time = 0 is forced update
{
2019-12-04 15:27:33 +01:00
long diff = m_last_update - time ;
2019-11-27 15:47:37 +01:00
if ( diff <= - 2 )
{
2019-12-04 15:27:33 +01:00
m_last_update = time ;
2019-11-27 15:47:37 +01:00
} else
{
return false ; // return value shouldnt matter if update didnt run
}
}
2019-11-27 11:33:36 +01:00
search_for_drives ();
2019-12-19 14:19:41 +01:00
if ( m_drives_count != m_current_drives . size ())
{
2020-01-21 10:23:50 +01:00
if ( check )
{
check_and_notify ();
}
2019-12-19 14:19:41 +01:00
m_drives_count = m_current_drives . size ();
}
2019-11-27 11:33:36 +01:00
return ! m_current_drives . empty ();
2019-11-26 15:52:18 +01:00
}
2020-01-22 17:05:26 +01:00
bool RemovableDriveManager :: is_drive_mounted ( const std :: string & path ) const
2019-11-26 15:52:18 +01:00
{
2019-11-27 11:33:36 +01:00
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
2019-11-26 15:52:18 +01:00
{
if (( * it ). path == path )
{
return true ;
}
}
return false ;
}
2020-01-22 17:05:26 +01:00
std :: string RemovableDriveManager :: get_drive_path ()
2019-12-11 14:53:28 +01:00
{
if ( m_current_drives . size () == 0 )
{
reset_last_save_path ();
return "" ;
}
2019-12-16 17:15:27 +01:00
if ( m_last_save_path_verified )
2019-12-11 14:53:28 +01:00
return m_last_save_path ;
return m_current_drives . back (). path ;
}
2020-01-22 17:05:26 +01:00
std :: string RemovableDriveManager :: get_last_save_path () const
2019-11-26 14:19:29 +01:00
{
2019-12-16 17:15:27 +01:00
if ( ! m_last_save_path_verified )
return "" ;
2019-12-11 12:28:51 +01:00
return m_last_save_path ;
2019-11-26 14:19:29 +01:00
}
2020-01-22 17:05:26 +01:00
std :: string RemovableDriveManager :: get_last_save_name () const
2019-12-13 18:02:25 +01:00
{
return m_last_save_name ;
}
2020-01-22 17:05:26 +01:00
std :: vector < DriveData > RemovableDriveManager :: get_all_drives () const
2019-11-26 14:19:29 +01:00
{
2019-11-27 11:33:36 +01:00
return m_current_drives ;
2019-11-26 14:19:29 +01:00
}
2019-11-28 13:38:08 +01:00
void RemovableDriveManager :: check_and_notify ()
{
2020-01-03 10:33:44 +01:00
if ( m_drive_count_changed_callback )
{
m_drive_count_changed_callback ( m_plater_ready_to_slice );
}
2020-01-22 17:05:26 +01:00
if ( m_callbacks . size () != 0 && m_drives_count > m_current_drives . size () && ! is_drive_mounted ( m_last_save_path ))
2019-11-28 13:38:08 +01:00
{
2019-12-19 14:19:41 +01:00
for ( auto it = m_callbacks . begin (); it != m_callbacks . end (); ++ it )
2019-11-28 13:38:08 +01:00
{
2019-12-19 14:19:41 +01:00
( * it )();
2019-11-28 13:38:08 +01:00
}
}
}
2020-01-02 16:30:28 +01:00
void RemovableDriveManager :: add_remove_callback ( std :: function < void () > callback )
2019-11-28 13:38:08 +01:00
{
m_callbacks . push_back ( callback );
}
2020-01-03 10:33:44 +01:00
void RemovableDriveManager :: erase_callbacks ()
2019-12-06 13:21:44 +01:00
{
m_callbacks . clear ();
}
2020-01-03 10:33:44 +01:00
void RemovableDriveManager :: set_drive_count_changed_callback ( std :: function < void ( const bool ) > callback )
{
m_drive_count_changed_callback = callback ;
}
void RemovableDriveManager :: set_plater_ready_to_slice ( bool b )
{
m_plater_ready_to_slice = b ;
}
2019-12-05 14:07:02 +01:00
void RemovableDriveManager :: set_last_save_path ( const std :: string & path )
{
2020-01-21 10:23:50 +01:00
if ( m_last_save_path_verified ) // if old path is on drive
{
if ( get_drive_from_path ( path ) != "" ) //and new is too, rewrite the path
{
m_last_save_path_verified = false ;
m_last_save_path = path ;
} //else do nothing
} else
{
m_last_save_path = path ;
}
2019-12-16 17:15:27 +01:00
}
void RemovableDriveManager :: verify_last_save_path ()
{
std :: string last_drive = get_drive_from_path ( m_last_save_path );
if ( last_drive != "" )
2019-12-05 14:07:02 +01:00
{
2019-12-16 17:15:27 +01:00
m_last_save_path_verified = true ;
2019-12-05 14:07:02 +01:00
m_last_save_path = last_drive ;
2019-12-13 18:02:25 +01:00
m_last_save_name = get_drive_name ( last_drive );
2019-12-19 14:19:41 +01:00
} else
{
reset_last_save_path ();
2019-12-05 14:07:02 +01:00
}
}
2020-01-22 17:05:26 +01:00
std :: string RemovableDriveManager :: get_drive_name ( const std :: string & path ) const
2019-12-13 18:02:25 +01:00
{
if ( m_current_drives . size () == 0 )
return "" ;
for ( auto it = m_current_drives . begin (); it != m_current_drives . end (); ++ it )
{
if (( * it ). path == path )
{
return ( * it ). name ;
}
}
return "" ;
}
2020-01-22 17:05:26 +01:00
bool RemovableDriveManager :: is_last_drive_removed ()
2019-12-05 14:07:02 +01:00
{
2019-12-16 17:15:27 +01:00
if ( ! m_last_save_path_verified )
2019-12-05 14:07:02 +01:00
{
return true ;
}
2019-12-11 12:28:51 +01:00
bool r = ! is_drive_mounted ( m_last_save_path );
2020-01-21 13:06:10 +01:00
if ( r )
{
reset_last_save_path ();
}
2019-12-11 12:28:51 +01:00
return r ;
2019-12-05 14:07:02 +01:00
}
2019-12-05 16:22:54 +01:00
bool RemovableDriveManager :: is_last_drive_removed_with_update ( const long time )
{
2019-12-11 12:28:51 +01:00
update ( time , false );
2019-12-05 16:22:54 +01:00
return is_last_drive_removed ();
}
2019-12-05 14:07:02 +01:00
void RemovableDriveManager :: reset_last_save_path ()
{
2019-12-16 17:15:27 +01:00
m_last_save_path_verified = false ;
2019-12-05 14:07:02 +01:00
m_last_save_path = "" ;
2019-12-13 18:02:25 +01:00
m_last_save_name = "" ;
}
void RemovableDriveManager :: set_is_writing ( const bool b )
{
m_is_writing = b ;
2019-12-16 13:53:12 +01:00
if ( b )
{
m_did_eject = false ;
}
2019-12-13 18:02:25 +01:00
}
2020-01-22 17:05:26 +01:00
bool RemovableDriveManager :: get_is_writing () const
2019-12-13 18:02:25 +01:00
{
return m_is_writing ;
2019-12-05 14:07:02 +01:00
}
2020-01-22 17:05:26 +01:00
bool RemovableDriveManager :: get_did_eject () const
2019-12-16 13:53:12 +01:00
{
return m_did_eject ;
}
2020-01-22 17:05:26 +01:00
void RemovableDriveManager :: set_did_eject ( const bool b )
2019-12-18 10:08:17 +01:00
{
m_did_eject = b ;
}
2020-01-22 17:05:26 +01:00
size_t RemovableDriveManager :: get_drives_count () const
2020-01-02 16:30:28 +01:00
{
return m_current_drives . size ();
}
2020-01-22 17:05:26 +01:00
std :: string RemovableDriveManager :: get_ejected_path () const
2020-01-21 10:23:50 +01:00
{
return m_ejected_path ;
}
2020-01-22 17:05:26 +01:00
std :: string RemovableDriveManager :: get_ejected_name () const
2020-01-21 10:23:50 +01:00
{
return m_ejected_name ;
}
2019-12-12 14:56:30 +01:00
}} //namespace Slicer::Gui