2015-09-25 21:37:19 +02:00
|
|
|
// File: ffiledialog.cpp
|
|
|
|
// Provides: class FFileDialog
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
#include "ffiledialog.h"
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
static bool sortByName (const dir_entry &lhs, const dir_entry &rhs)
|
|
|
|
{
|
|
|
|
// lhs < rhs
|
|
|
|
return bool(strcasecmp(lhs.name, rhs.name) < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
static bool sortDirFirst (const dir_entry &lhs, const dir_entry &rhs)
|
|
|
|
{
|
|
|
|
// sort directories first
|
|
|
|
if ( lhs.type == DT_DIR && rhs.type != DT_DIR )
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// class FFileDialog
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// constructors and destructor
|
|
|
|
//----------------------------------------------------------------------
|
2015-09-22 04:18:20 +02:00
|
|
|
FFileDialog::FFileDialog(FWidget* parent)
|
|
|
|
: FDialog(parent)
|
|
|
|
, directory_stream(0)
|
|
|
|
, dir_entries()
|
|
|
|
, directory()
|
|
|
|
, filter_pattern()
|
|
|
|
, filebrowser()
|
|
|
|
, filename()
|
|
|
|
, hidden()
|
|
|
|
, cancel()
|
|
|
|
, open()
|
|
|
|
, dlg_type(FFileDialog::Open)
|
|
|
|
, show_hidden(false)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2015-09-22 04:18:20 +02:00
|
|
|
FFileDialog::FFileDialog (const FFileDialog& fdlg)
|
2016-07-03 20:08:39 +02:00
|
|
|
: FDialog(fdlg.getParentWidget())
|
2015-09-22 04:18:20 +02:00
|
|
|
, directory_stream(0)
|
|
|
|
, dir_entries()
|
|
|
|
, directory(fdlg.directory)
|
|
|
|
, filter_pattern(fdlg.filter_pattern)
|
|
|
|
, filebrowser()
|
|
|
|
, filename()
|
|
|
|
, hidden()
|
|
|
|
, cancel()
|
|
|
|
, open()
|
|
|
|
, dlg_type(fdlg.dlg_type)
|
|
|
|
, show_hidden(fdlg.show_hidden)
|
|
|
|
{
|
|
|
|
if ( directory )
|
|
|
|
setPath(directory);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-09-22 04:18:20 +02:00
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FFileDialog::FFileDialog ( const FString& dirname
|
|
|
|
, const FString& filter
|
|
|
|
, DialogType type
|
|
|
|
, FWidget* parent )
|
|
|
|
: FDialog(parent)
|
|
|
|
, directory_stream(0)
|
|
|
|
, dir_entries()
|
|
|
|
, directory()
|
|
|
|
, filter_pattern(filter)
|
|
|
|
, filebrowser()
|
|
|
|
, filename()
|
|
|
|
, hidden()
|
|
|
|
, cancel()
|
|
|
|
, open()
|
|
|
|
, dlg_type(type)
|
|
|
|
, show_hidden(false)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
|
|
|
if ( dirname )
|
|
|
|
setPath(dirname);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FFileDialog::~FFileDialog() // destructor
|
|
|
|
{
|
|
|
|
delete open;
|
|
|
|
delete cancel;
|
|
|
|
delete hidden;
|
|
|
|
delete filebrowser;
|
|
|
|
delete filename;
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// private methods of FFileDialog
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::init()
|
|
|
|
{
|
|
|
|
int x, y;
|
|
|
|
height = 15;
|
2016-07-09 00:01:59 +02:00
|
|
|
width = 42;
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( width < 15 )
|
|
|
|
width = 15;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( width < 20 )
|
|
|
|
width = 20;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2016-07-03 20:08:39 +02:00
|
|
|
x = 1 + int((getParentWidget()->getWidth()-width)/2);
|
|
|
|
y = 1 + int((getParentWidget()->getHeight()-height)/3);
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
if ( dlg_type == FFileDialog::Save )
|
|
|
|
FDialog::setText("Save file");
|
|
|
|
else
|
|
|
|
FDialog::setText("Open file");
|
|
|
|
|
|
|
|
filename = new FLineEdit(this);
|
|
|
|
filename->setLabelText("File&name:");
|
|
|
|
filename->setText(filter_pattern);
|
|
|
|
filename->setGeometry(11, 1, 28, 1);
|
|
|
|
filename->setShadow();
|
|
|
|
filename->setFocus();
|
|
|
|
|
|
|
|
filebrowser = new FListBox(this);
|
|
|
|
filebrowser->setGeometry(2, 3, 38, 6);
|
|
|
|
printPath(directory);
|
|
|
|
|
|
|
|
hidden = new FCheckBox("&hidden files", this);
|
|
|
|
hidden->setGeometry(2, 10, 16, 1);
|
|
|
|
|
|
|
|
cancel = new FButton("&Cancel", this);
|
|
|
|
cancel->setGeometry(19, 10, 9, 1);
|
|
|
|
cancel->setShadow();
|
|
|
|
|
|
|
|
if ( dlg_type == FFileDialog::Save )
|
|
|
|
open = new FButton("&Save",this);
|
|
|
|
else
|
|
|
|
open = new FButton("&Open",this);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
open->setGeometry(30, 10, 9, 1);
|
|
|
|
open->setShadow();
|
|
|
|
setGeometry (x, y, width, height);
|
|
|
|
|
|
|
|
filename->addCallback
|
|
|
|
(
|
|
|
|
"activate",
|
2015-09-24 19:01:27 +02:00
|
|
|
_METHOD_CALLBACK (this, &FFileDialog::cb_processActivate)
|
2015-05-23 13:35:12 +02:00
|
|
|
);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
filebrowser->addCallback
|
|
|
|
(
|
|
|
|
"row-changed",
|
2015-09-24 19:01:27 +02:00
|
|
|
_METHOD_CALLBACK (this, &FFileDialog::cb_processRowChanged)
|
2015-05-23 13:35:12 +02:00
|
|
|
);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
filebrowser->addCallback
|
|
|
|
(
|
|
|
|
"clicked",
|
2015-09-24 19:01:27 +02:00
|
|
|
_METHOD_CALLBACK (this, &FFileDialog::cb_processClicked)
|
2015-05-23 13:35:12 +02:00
|
|
|
);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
hidden->addCallback
|
|
|
|
(
|
|
|
|
"toggled",
|
2015-09-24 19:01:27 +02:00
|
|
|
_METHOD_CALLBACK (this, &FFileDialog::cb_processShowHidden)
|
2015-05-23 13:35:12 +02:00
|
|
|
);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
cancel->addCallback
|
|
|
|
(
|
|
|
|
"clicked",
|
2015-09-24 19:01:27 +02:00
|
|
|
_METHOD_CALLBACK (this, &FFileDialog::cb_processCancel)
|
2015-05-23 13:35:12 +02:00
|
|
|
);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
open->addCallback
|
|
|
|
(
|
|
|
|
"clicked",
|
2015-09-24 19:01:27 +02:00
|
|
|
_METHOD_CALLBACK (this, &FFileDialog::cb_processOpen)
|
2015-05-23 13:35:12 +02:00
|
|
|
);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
setModal();
|
|
|
|
setTransparentShadow();
|
|
|
|
readDir();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
char* FFileDialog::getHomeDir()
|
|
|
|
{
|
|
|
|
struct passwd* pwd;
|
|
|
|
pwd = getpwuid( geteuid() );
|
|
|
|
|
2015-11-05 23:25:21 +01:00
|
|
|
if ( ! pwd )
|
2015-05-23 13:35:12 +02:00
|
|
|
return const_cast<char*>("");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pwd = getpwnam(pwd->pw_name);
|
|
|
|
|
2015-11-05 23:25:21 +01:00
|
|
|
if ( ! pwd )
|
2015-05-23 13:35:12 +02:00
|
|
|
return const_cast<char*>("");
|
|
|
|
else
|
|
|
|
return pwd->pw_dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2015-09-22 04:18:20 +02:00
|
|
|
inline bool FFileDialog::pattern_match ( const char* pattern
|
|
|
|
, const char* fname )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2015-09-30 22:39:02 +02:00
|
|
|
char search[128] = {};
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( show_hidden && fname[0] == '.' && fname[1] != '\0' ) // hidden files
|
|
|
|
{
|
|
|
|
search[0] = '.';
|
|
|
|
search[1] = '\0';
|
|
|
|
strncat(search, pattern, sizeof(search) - strlen(search) - 1);
|
|
|
|
}
|
|
|
|
else
|
2015-09-30 22:39:02 +02:00
|
|
|
strncpy(search, pattern, sizeof(search) - 1);
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
if ( fnmatch (search, fname, FNM_PERIOD) == 0 )
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::clear()
|
|
|
|
{
|
|
|
|
std::vector<dir_entry>::const_iterator iter, end;
|
|
|
|
|
|
|
|
if ( dir_entries.empty() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// delete all directory entries;
|
|
|
|
iter = dir_entries.begin();
|
|
|
|
end = dir_entries.end();
|
|
|
|
|
|
|
|
while ( iter != end )
|
|
|
|
{
|
|
|
|
free ((*iter).name);
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
dir_entries.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int FFileDialog::numOfDirs()
|
|
|
|
{
|
|
|
|
int n = 0;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! dir_entries.empty() )
|
|
|
|
{
|
|
|
|
std::vector<dir_entry>::const_iterator iter, end;
|
|
|
|
iter = dir_entries.begin();
|
|
|
|
end = dir_entries.end();
|
|
|
|
|
|
|
|
while ( iter != end )
|
|
|
|
{
|
|
|
|
if ( (*iter).type == DT_DIR && strcmp((*iter).name, ".") != 0 )
|
|
|
|
n++;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int FFileDialog::changeDir (const FString& dirname)
|
|
|
|
{
|
|
|
|
FString lastdir = directory;
|
|
|
|
FString newdir = dirname;
|
|
|
|
|
|
|
|
if ( newdir.includes('~') )
|
|
|
|
newdir = newdir.replace('~', getHomeDir());
|
|
|
|
|
|
|
|
if ( newdir[0] == '/' )
|
|
|
|
setPath(newdir);
|
|
|
|
else
|
|
|
|
setPath(directory + newdir);
|
|
|
|
|
|
|
|
switch ( readDir() )
|
|
|
|
{
|
|
|
|
case -1:
|
|
|
|
setPath(lastdir);
|
|
|
|
return -1;
|
2015-09-20 05:44:50 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
case -2:
|
|
|
|
setPath(lastdir);
|
|
|
|
readDir();
|
|
|
|
return -2;
|
2015-09-20 05:44:50 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
case 0:
|
|
|
|
if ( newdir == FString("..") )
|
|
|
|
{
|
|
|
|
if ( lastdir == FString('/') )
|
|
|
|
filename->setText('/');
|
|
|
|
else if ( ! dir_entries.empty() )
|
|
|
|
{
|
|
|
|
int i = 1;
|
|
|
|
std::vector<dir_entry>::const_iterator iter, end;
|
|
|
|
const char* baseName = basename(const_cast<char*>(lastdir.c_str()));
|
|
|
|
iter = dir_entries.begin();
|
|
|
|
end = dir_entries.end();
|
|
|
|
|
|
|
|
while ( iter != end )
|
|
|
|
{
|
|
|
|
if ( strcmp((*iter).name, baseName) == 0 )
|
|
|
|
{
|
|
|
|
filebrowser->setCurrentItem(i);
|
|
|
|
filename->setText(FString(baseName) + '/');
|
|
|
|
break;
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
i++;
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FString firstname = dir_entries[0].name;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( dir_entries[0].type == DT_DIR )
|
|
|
|
filename->setText(firstname + '/');
|
|
|
|
else
|
|
|
|
filename->setText(firstname);
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
printPath(directory);
|
|
|
|
filename->redraw();
|
|
|
|
filebrowser->redraw();
|
2015-09-20 05:44:50 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::printPath (const FString& txt)
|
|
|
|
{
|
2015-09-20 05:44:50 +02:00
|
|
|
FString path = txt;
|
2015-05-23 13:35:12 +02:00
|
|
|
uInt max_width = uInt(filebrowser->getWidth()) - 4;
|
|
|
|
|
2015-09-20 05:44:50 +02:00
|
|
|
if ( path.getLength() > max_width )
|
|
|
|
filebrowser->setText(".." + path.right(max_width-2));
|
2015-05-23 13:35:12 +02:00
|
|
|
else
|
2015-09-20 05:44:50 +02:00
|
|
|
filebrowser->setText(path);
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::cb_processActivate (FWidget*, void*)
|
|
|
|
{
|
|
|
|
if ( filename->getText().includes('*')
|
|
|
|
|| filename->getText().includes('?') )
|
|
|
|
{
|
|
|
|
setFilter(filename->getText());
|
|
|
|
readDir();
|
|
|
|
filebrowser->redraw();
|
|
|
|
}
|
|
|
|
else if ( filename->getText().getLength() == 0 )
|
|
|
|
{
|
|
|
|
setFilter("*");
|
|
|
|
readDir();
|
|
|
|
filebrowser->redraw();
|
|
|
|
}
|
|
|
|
else if ( filename->getText().trim() == FString("..")
|
|
|
|
|| filename->getText().includes('/')
|
|
|
|
|| filename->getText().includes('~') )
|
|
|
|
{
|
|
|
|
changeDir(filename->getText().trim());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bool found = false;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! dir_entries.empty() )
|
|
|
|
{
|
|
|
|
std::vector<dir_entry>::const_iterator iter, end;
|
|
|
|
FString input = filename->getText().trim();
|
|
|
|
iter = dir_entries.begin();
|
|
|
|
end = dir_entries.end();
|
|
|
|
|
|
|
|
while ( iter != end )
|
|
|
|
{
|
|
|
|
if ( strcmp((*iter).name, input) == 0 && (*iter).type == DT_DIR )
|
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
changeDir(input);
|
|
|
|
break;
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! found )
|
|
|
|
done (FDialog::Accept);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::cb_processRowChanged (FWidget*, void*)
|
|
|
|
{
|
|
|
|
int n = filebrowser->currentItem();
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( n == 0 )
|
|
|
|
return;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
FString name = dir_entries[uLong(n-1)].name;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( dir_entries[uLong(n-1)].type == DT_DIR )
|
|
|
|
filename->setText( name + '/' );
|
|
|
|
else
|
|
|
|
filename->setText( name );
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
filename->redraw();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::cb_processClicked (FWidget*, void*)
|
|
|
|
{
|
|
|
|
uLong n = uLong(filebrowser->currentItem() - 1);
|
|
|
|
|
|
|
|
if ( dir_entries[n].type == DT_DIR )
|
|
|
|
changeDir(dir_entries[n].name);
|
|
|
|
else
|
|
|
|
done (FDialog::Accept);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::cb_processCancel (FWidget*, void*)
|
|
|
|
{
|
|
|
|
done (FDialog::Reject);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::cb_processOpen (FWidget*, void*)
|
|
|
|
{
|
|
|
|
done (FDialog::Accept);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::cb_processShowHidden (FWidget*, void*)
|
|
|
|
{
|
|
|
|
setShowHiddenFiles(not show_hidden);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// protected methods of FFileDialog
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::adjustSize()
|
|
|
|
{
|
|
|
|
int X, Y;
|
|
|
|
int max_height = getRootWidget()->getClientHeight();
|
|
|
|
int max_width = getRootWidget()->getClientWidth();
|
|
|
|
int h = max_height - 6;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( h < 15 ) // minimum
|
|
|
|
h = 15;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( h > 30 ) // maximum
|
|
|
|
h = 30;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
setHeight (h, false);
|
|
|
|
X = 1 + int((max_width-width)/2);
|
|
|
|
Y = 1 + int((max_height-height)/3);
|
|
|
|
setX(X, false);
|
|
|
|
setY(Y, false);
|
|
|
|
filebrowser->setHeight(h-8, false);
|
|
|
|
hidden->setY(h-4, false);
|
|
|
|
cancel->setY(h-4, false);
|
|
|
|
open->setY(h-4, false);
|
|
|
|
FDialog::adjustSize();
|
|
|
|
printPath(directory);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// public methods of FFileDialog
|
2015-09-22 04:18:20 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FFileDialog& FFileDialog::operator = (const FFileDialog& fdlg)
|
|
|
|
{
|
|
|
|
if ( &fdlg == this )
|
|
|
|
return *this;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete open;
|
|
|
|
delete cancel;
|
|
|
|
delete hidden;
|
|
|
|
delete filebrowser;
|
|
|
|
delete filename;
|
|
|
|
clear();
|
2016-07-03 20:08:39 +02:00
|
|
|
fdlg.getParentWidget()->addChild (this);
|
2015-09-22 04:18:20 +02:00
|
|
|
directory = fdlg.directory;
|
|
|
|
filter_pattern = fdlg.filter_pattern;
|
|
|
|
dlg_type = fdlg.dlg_type;
|
|
|
|
show_hidden = fdlg.show_hidden;
|
|
|
|
|
|
|
|
if ( directory )
|
|
|
|
setPath(directory);
|
|
|
|
|
2016-07-09 00:01:59 +02:00
|
|
|
init();
|
2015-09-22 04:18:20 +02:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
2015-09-20 05:44:50 +02:00
|
|
|
void FFileDialog::onKeyPress (FKeyEvent* ev)
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
|
|
|
if ( ! isEnabled() )
|
|
|
|
return;
|
|
|
|
|
2015-09-20 05:44:50 +02:00
|
|
|
FDialog::onKeyPress (ev);
|
2015-05-23 13:35:12 +02:00
|
|
|
|
|
|
|
if ( ! filebrowser->hasFocus() )
|
|
|
|
return;
|
|
|
|
|
2015-09-20 05:44:50 +02:00
|
|
|
int key = ev->key();
|
2015-05-23 13:35:12 +02:00
|
|
|
switch ( key )
|
|
|
|
{
|
|
|
|
case fc::Fkey_erase:
|
|
|
|
case fc::Fkey_backspace:
|
|
|
|
changeDir("..");
|
2015-09-20 05:44:50 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2015-05-23 13:35:12 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::setPath (const FString& dir)
|
|
|
|
{
|
|
|
|
const char* dirname = dir.c_str();
|
|
|
|
char resolved_path[MAXPATHLEN];
|
|
|
|
FString r_dir;
|
|
|
|
struct stat sb;
|
|
|
|
|
2015-10-01 03:48:58 +02:00
|
|
|
if ( stat(dirname, &sb) != 0 )
|
|
|
|
{
|
|
|
|
directory = '/';
|
|
|
|
return;
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( S_ISLNK(sb.st_mode) )
|
|
|
|
{
|
2015-10-01 03:48:58 +02:00
|
|
|
if ( lstat(dirname, &sb) != 0 )
|
|
|
|
{
|
|
|
|
directory = '/';
|
|
|
|
return;
|
|
|
|
}
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! S_ISDIR(sb.st_mode) )
|
|
|
|
{
|
|
|
|
directory = '/';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( realpath(dir.c_str(), resolved_path) != 0 )
|
|
|
|
r_dir = resolved_path;
|
|
|
|
else
|
|
|
|
r_dir = dir;
|
|
|
|
|
|
|
|
if ( r_dir[r_dir.getLength()-1] != '/' )
|
|
|
|
directory = r_dir + "/";
|
|
|
|
else
|
|
|
|
directory = r_dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FFileDialog::setFilter (const FString& filter)
|
|
|
|
{
|
|
|
|
filter_pattern = filter;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
const FString FFileDialog::getSelectedFile() const
|
|
|
|
{
|
|
|
|
uLong n = uLong(filebrowser->currentItem() - 1);
|
|
|
|
|
|
|
|
if ( dir_entries[n].type == DT_DIR )
|
|
|
|
return FString("");
|
|
|
|
else
|
|
|
|
return FString(dir_entries[n].name);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int FFileDialog::readDir()
|
|
|
|
{
|
2016-07-09 00:01:59 +02:00
|
|
|
int start, dir_num;
|
2015-05-23 13:35:12 +02:00
|
|
|
const char* dir = directory.c_str();
|
|
|
|
const char* filter = filter_pattern.c_str();
|
|
|
|
errno = 0;
|
|
|
|
directory_stream = opendir(dir);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! directory_stream )
|
|
|
|
{
|
|
|
|
FMessageBox::error (this, "Can't open directory\n" + directory);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
clear();
|
|
|
|
|
|
|
|
while ( true )
|
|
|
|
{
|
|
|
|
errno = 0;
|
|
|
|
struct dirent* next = readdir (directory_stream);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( next )
|
|
|
|
{
|
|
|
|
if ( next->d_name[0] == '.' && next->d_name[1] == '\0' )
|
|
|
|
continue;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! show_hidden
|
|
|
|
&& next->d_name[0] == '.'
|
|
|
|
&& next->d_name[1] != '\0'
|
|
|
|
&& next->d_name[1] != '.' )
|
2016-07-09 00:01:59 +02:00
|
|
|
{
|
2015-05-23 13:35:12 +02:00
|
|
|
continue;
|
2016-07-09 00:01:59 +02:00
|
|
|
}
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( dir[0] == '/' && dir[1] == '\0' && strcmp(next->d_name, "..") == 0 )
|
|
|
|
continue;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
dir_entry entry;
|
|
|
|
entry.name = strdup(next->d_name);
|
|
|
|
entry.type = next->d_type;
|
|
|
|
|
|
|
|
if ( next->d_type == DT_LNK ) // symbolic link
|
|
|
|
{
|
2015-09-30 22:39:02 +02:00
|
|
|
char resolved_path[MAXPATHLEN] = {};
|
|
|
|
char symLink[MAXPATHLEN] = {};
|
|
|
|
strncpy(symLink, dir, sizeof(symLink) - 1);
|
2015-05-23 13:35:12 +02:00
|
|
|
strncat(symLink, next->d_name, sizeof(symLink) - strlen(symLink) - 1);
|
|
|
|
|
|
|
|
if ( realpath(symLink, resolved_path) != 0 ) // follow link
|
|
|
|
{
|
|
|
|
struct stat sb;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-10-01 03:48:58 +02:00
|
|
|
if ( lstat(resolved_path, &sb) == 0 )
|
|
|
|
{
|
|
|
|
if ( S_ISDIR(sb.st_mode) )
|
|
|
|
entry.type = DT_DIR;
|
|
|
|
}
|
2015-05-23 13:35:12 +02:00
|
|
|
}
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( entry.type == DT_DIR )
|
|
|
|
dir_entries.push_back (entry);
|
|
|
|
else if ( pattern_match(filter, entry.name) )
|
|
|
|
dir_entries.push_back (entry);
|
|
|
|
else
|
|
|
|
free(entry.name);
|
|
|
|
}
|
|
|
|
else if (errno != 0)
|
|
|
|
{
|
|
|
|
FMessageBox::error (this, "Reading directory\n" + directory);
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( errno != EOVERFLOW )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
} // end while
|
|
|
|
|
|
|
|
if ( closedir (directory_stream) != 0 )
|
|
|
|
{
|
|
|
|
FMessageBox::error (this, "Closing directory\n" + directory);
|
|
|
|
return -2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( strcmp((*dir_entries.begin()).name, "..") == 0 )
|
|
|
|
start=1;
|
|
|
|
else
|
|
|
|
start=0;
|
|
|
|
|
2016-07-09 00:01:59 +02:00
|
|
|
dir_num = numOfDirs();
|
2015-05-23 13:35:12 +02:00
|
|
|
// directories first
|
|
|
|
std::sort(dir_entries.begin()+start, dir_entries.end(), sortDirFirst);
|
|
|
|
// sort directories by name
|
|
|
|
std::sort(dir_entries.begin()+start, dir_entries.begin()+dir_num, sortByName);
|
|
|
|
// sort files by name
|
|
|
|
std::sort(dir_entries.begin()+dir_num, dir_entries.end(), sortByName);
|
|
|
|
// fill list with directory entries
|
|
|
|
filebrowser->clear();
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( ! dir_entries.empty() )
|
|
|
|
{
|
|
|
|
std::vector<dir_entry>::const_iterator iter, end;
|
|
|
|
iter = dir_entries.begin();
|
|
|
|
end = dir_entries.end();
|
|
|
|
|
|
|
|
while ( iter != end )
|
|
|
|
{
|
|
|
|
if ( (*iter).type == DT_DIR )
|
|
|
|
filebrowser->insert(FString((*iter).name), fc::SquareBrackets);
|
|
|
|
else
|
|
|
|
filebrowser->insert(FString((*iter).name));
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FFileDialog::setShowHiddenFiles (bool on)
|
|
|
|
{
|
|
|
|
if ( on == show_hidden )
|
|
|
|
return show_hidden;
|
|
|
|
|
|
|
|
show_hidden = on;
|
|
|
|
readDir();
|
|
|
|
filebrowser->redraw();
|
|
|
|
return show_hidden;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2015-09-22 04:18:20 +02:00
|
|
|
FString FFileDialog::fileOpenChooser ( FWidget* parent
|
|
|
|
, const FString& dirname
|
|
|
|
, const FString& filter )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2016-07-09 00:01:59 +02:00
|
|
|
FFileDialog* fileopen;
|
2015-05-23 13:35:12 +02:00
|
|
|
FString ret;
|
|
|
|
FString path = dirname;
|
|
|
|
FString file_filter = filter;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( path.isNull() )
|
|
|
|
path = getHomeDir();
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( file_filter.isNull() )
|
|
|
|
file_filter = FString("*");
|
2016-07-09 00:01:59 +02:00
|
|
|
|
|
|
|
fileopen = new FFileDialog ( path
|
|
|
|
, file_filter
|
|
|
|
, FFileDialog::Open
|
|
|
|
, parent );
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( fileopen->exec() == FDialog::Accept )
|
|
|
|
ret = fileopen->getPath() + fileopen->getSelectedFile();
|
|
|
|
else
|
|
|
|
ret = FString();
|
2015-09-22 04:18:20 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
delete fileopen;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2015-09-22 04:18:20 +02:00
|
|
|
FString FFileDialog::fileSaveChooser ( FWidget* parent
|
|
|
|
, const FString& dirname
|
|
|
|
, const FString& filter )
|
2015-05-23 13:35:12 +02:00
|
|
|
{
|
2016-07-09 00:01:59 +02:00
|
|
|
FFileDialog* fileopen;
|
2015-05-23 13:35:12 +02:00
|
|
|
FString ret;
|
|
|
|
FString path = dirname;
|
|
|
|
FString file_filter = filter;
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( path.isNull() )
|
|
|
|
path = getHomeDir();
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( file_filter.isNull() )
|
|
|
|
file_filter = FString("*");
|
2016-07-09 00:01:59 +02:00
|
|
|
|
|
|
|
fileopen = new FFileDialog ( path
|
|
|
|
, file_filter
|
|
|
|
, FFileDialog::Save
|
|
|
|
, parent );
|
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
if ( fileopen->exec() == FDialog::Accept )
|
|
|
|
ret = fileopen->getPath() + fileopen->getSelectedFile();
|
|
|
|
else
|
|
|
|
ret = FString();
|
2016-07-09 00:01:59 +02:00
|
|
|
|
2015-05-23 13:35:12 +02:00
|
|
|
delete fileopen;
|
|
|
|
return ret;
|
|
|
|
}
|