X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fxforms%2FFormFiledialog.C;h=1c8aec402417cf13c4c52ed5313c3c84a7bed979;hb=37e82a546392d43f787826b85481a11f2a27af15;hp=3e67b753b4e94ff03d59fd5724378a04450415c8;hpb=9c4446b15999f052b1b7f0e830cbea0cfd13f1e6;p=lyx.git diff --git a/src/frontends/xforms/FormFiledialog.C b/src/frontends/xforms/FormFiledialog.C index 3e67b753b4..1c8aec4024 100644 --- a/src/frontends/xforms/FormFiledialog.C +++ b/src/frontends/xforms/FormFiledialog.C @@ -1,43 +1,53 @@ /** * \file FormFiledialog.C - * Copyright 2001 the LyX Team - * Read the file COPYING + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. * * \author unknown * \author John Levon + * + * Full author contact details are available in file CREDITS. */ #include -#include -#include -#include -#include -//#include -#include -#include +#include "FormFiledialog.h" +#include "forms/form_filedialog.h" -using std::map; -using std::max; -using std::sort; +#include "forms_gettext.h" +#include "xforms_helpers.h" + +#include "frontends/Dialogs.h" -#include "frontends/Alert.h" #include "support/FileInfo.h" -#include "support/lyxlib.h" +#include "support/filefilterlist.h" +#include "support/filetools.h" +#include "support/globbing.h" #include "support/lstrings.h" -#include "gettext.h" -#include "frontends/Dialogs.h" +#include "support/lyxlib.h" +#include "support/tostr.h" -#ifdef HAVE_ERRNO_H -#include -#endif +#include "lyx_forms.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +//#ifdef HAVE_ERRNO_H +//#include +//#endif #if HAVE_DIRENT_H # include -# define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen # if HAVE_SYS_NDIR_H # include # endif @@ -49,44 +59,72 @@ using std::sort; # endif #endif -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif +using lyx::support::AbsolutePath; +using lyx::support::AddName; +using lyx::support::ExpandPath; +using lyx::support::FileFilterList; +using lyx::support::FileInfo; +using lyx::support::getcwd; +using lyx::support::GetEnvPath; +using lyx::support::LyXReadLink; +using lyx::support::MakeAbsPath; +using lyx::support::OnlyFilename; +using lyx::support::split; +using lyx::support::subst; +using lyx::support::suffixIs; +using lyx::support::trim; -// FIXME: should be autoconfiscated -#ifdef BROKEN_HEADERS -extern "C" int gettimeofday(struct timeval *, struct timezone *); -#endif - -#ifdef __GNUG__ -#pragma implementation -#endif +using std::max; +using std::sort; +using std::ostringstream; +using std::string; +using std::map; +using std::vector; -#include "support/filetools.h" -#include "FormFiledialog.h" +using namespace lyx::frontend; namespace { +/** Given a string " ", expand each glob in turn. + * Any glob that cannot be expanded is ignored silently. + * Invokes \c convert_brace_glob and \c glob internally, so use only + * on systems supporting the Posix function 'glob'. + * \param mask the string " ". + * \param directory the current working directory from + * which \c glob is invoked. + * \returns a vector of all matching file names. + */ +vector const expand_globs(string const & mask, + string const & directory) +{ + // Split into individual globs and then call 'glob' on each one. + typedef boost::tokenizer > Tokenizer; + boost::char_separator const separator(" "); + + vector matches; + Tokenizer const tokens(mask, separator); + Tokenizer::const_iterator it = tokens.begin(); + Tokenizer::const_iterator const end = tokens.end(); + for (; it != end; ++it) + lyx::support::glob(matches, *it, directory); + + return matches; +} + + // six months, in seconds long const SIX_MONTH_SEC = 6L * 30L * 24L * 60L * 60L; //static long const ONE_HOUR_SEC = 60L * 60L; extern "C" { - + static int C_LyXFileDlg_CancelCB(FL_FORM *fl, void *xev) { return FileDialog::Private::CancelCB(fl, xev); } - + static void C_LyXFileDlg_DoubleClickCB(FL_OBJECT * ob, long data) { @@ -101,9 +139,6 @@ extern "C" { } -} // namespace anon - - // *** User cache class implementation /// User cache class definition class UserCache { @@ -129,19 +164,9 @@ private: void UserCache::add(uid_t ID) const { - string pszNewName; - struct passwd * pEntry; - - // gets user name - if ((pEntry = getpwuid(ID))) - pszNewName = pEntry->pw_name; - else { - pszNewName = tostr(ID); - } - - // adds new node - users[ID] = pszNewName; -} + struct passwd const * entry = getpwuid(ID); + users[ID] = entry ? entry->pw_name : tostr(int(ID)); +} /// Group cache class definition @@ -172,119 +197,117 @@ string const & GroupCache::find(gid_t ID) const void GroupCache::add(gid_t ID) const { - string pszNewName; - struct group * pEntry; - - // gets user name - if ((pEntry = getgrgid(ID))) pszNewName = pEntry->gr_name; - else { - pszNewName = tostr(ID); - } - // adds new node - groups[ID] = pszNewName; + struct group const * entry = getgrgid(ID); + groups[ID] = entry ? entry->gr_name : tostr(int(ID)); } - -namespace { - // local instances UserCache lyxUserCache; GroupCache lyxGroupCache; -} // namespace anon - - // compares two LyXDirEntry objects content (used for sort) -class comp_direntry { +class comp_direntry : public std::binary_function { public: - int operator()(DirEntry const & r1, - DirEntry const & r2) const ; -}; - int comp_direntry::operator()(DirEntry const & r1, - DirEntry const & r2) const { - bool r1d = suffixIs(r1.pszName, '/'); - bool r2d = suffixIs(r2.pszName, '/'); - if (r1d && !r2d) return 1; - if (!r1d && r2d) return 0; - return r1.pszName < r2.pszName; + bool operator()(DirEntry const & r1, DirEntry const & r2) const + { + bool const r1d = suffixIs(r1.name_, '/'); + bool const r2d = suffixIs(r2.name_, '/'); + if (r1d && !r2d) + return true; + if (!r1d && r2d) + return false; + return r1.name_ < r2.name_; } +}; + +} // namespace anon + // *** FileDialog::Private class implementation // static members -FD_form_filedialog * FileDialog::Private::pFileDlgForm = 0; -FileDialog::Private * FileDialog::Private::pCurrentDlg = 0; +FD_filedialog * FileDialog::Private::file_dlg_form_ = 0; +FileDialog::Private * FileDialog::Private::current_dlg_ = 0; +int FileDialog::Private::minw_ = 0; +int FileDialog::Private::minh_ = 0; // Reread: updates dialog list to match class directory void FileDialog::Private::Reread() { // Opens directory - DIR * pDirectory = ::opendir(pszDirectory.c_str()); - if (!pDirectory) { + DIR * dir = ::opendir(directory_.c_str()); + if (!dir) { +// FIXME: re-add ... +#if 0 Alert::err_alert(_("Warning! Couldn't open directory."), - pszDirectory); - pszDirectory = lyx::getcwd(); - pDirectory = ::opendir(pszDirectory.c_str()); + directory_); +#endif + directory_ = getcwd(); + dir = ::opendir(directory_.c_str()); } // Clear the present namelist - direntries.clear(); + dir_entries_.clear(); // Updates display - fl_hide_object(pFileDlgForm->List); - fl_clear_browser(pFileDlgForm->List); - fl_set_input(pFileDlgForm->DirBox, pszDirectory.c_str()); + fl_hide_object(file_dlg_form_->List); + fl_clear_browser(file_dlg_form_->List); + fl_set_input(file_dlg_form_->DirBox, directory_.c_str()); // Splits complete directory name into directories and compute depth - iDepth = 0; + depth_ = 0; string line, Temp; - char szMode[15]; - string File = pszDirectory; - if (File != "/") { + string mode; + string File = directory_; + if (File != "/") File = split(File, Temp, '/'); - } + while (!File.empty() || !Temp.empty()) { - string dline = "@b"+line + Temp + '/'; - fl_add_browser_line(pFileDlgForm->List, dline.c_str()); + string dline = "@b" + line + Temp + '/'; + fl_add_browser_line(file_dlg_form_->List, dline.c_str()); File = split(File, Temp, '/'); line += ' '; - ++iDepth; + ++depth_; } - // Parses all entries of the given subdirectory + vector const glob_matches = expand_globs(mask_, directory_); + time_t curTime = time(0); - rewinddir(pDirectory); - struct dirent * pDirEntry; - while ((pDirEntry = readdir(pDirectory))) { + rewinddir(dir); + while (dirent * entry = readdir(dir)) { bool isLink = false, isDir = false; // If the pattern doesn't start with a dot, skip hidden files - if (!pszMask.empty() && pszMask[0] != '.' && - pDirEntry->d_name[0] == '.') - continue; + if (!mask_.empty() && mask_[0] != '.' && + entry->d_name[0] == '.') + continue; // Gets filename - string fname = pDirEntry->d_name; + string fname = entry->d_name; // Under all circumstances, "." and ".." are not wanted if (fname == "." || fname == "..") continue; // gets file status - File = AddName(pszDirectory, fname); + File = AddName(directory_, fname); - // FIXME: we don't get this file exists/stattable FileInfo fileInfo(File, true); - fileInfo.modeString(szMode); - unsigned int nlink = fileInfo.getNumberOfLinks(); - string user = lyxUserCache.find(fileInfo.getUid()); - string group = lyxGroupCache.find(fileInfo.getGid()); + + // can this really happen? + if (!fileInfo.isOK()) + continue; + + mode = fileInfo.modeString(); + unsigned int const nlink = fileInfo.getNumberOfLinks(); + string const user = lyxUserCache.find(fileInfo.getUid()); + string const group = lyxGroupCache.find(fileInfo.getGid()); time_t modtime = fileInfo.getModificationTime(); string Time = ctime(&modtime); - + if (curTime > modtime + SIX_MONTH_SEC || curTime < modtime + ONE_HOUR_SEC) { // The file is fairly old or in the future. POSIX says @@ -298,30 +321,34 @@ void FileDialog::Private::Reread() Time.erase(16, string::npos); } - string Buffer = string(szMode) + ' ' + + string buffer = mode + ' ' + tostr(nlink) + ' ' + user + ' ' + group + ' ' + Time.substr(4, string::npos) + ' '; - Buffer += pDirEntry->d_name; - Buffer += fileInfo.typeIndicator(); + buffer += entry->d_name; + buffer += fileInfo.typeIndicator(); - if ((isLink = fileInfo.isLink())) { + isLink = fileInfo.isLink(); + if (isLink) { string Link; if (LyXReadLink(File, Link)) { - Buffer += " -> "; - Buffer += Link; + buffer += " -> "; + buffer += Link; // This gives the FileType of the file that - // is really pointed too after resolving all + // is really pointed to after resolving all // symlinks. This is not necessarily the same // as the type of Link (which could again be a // link). Is that intended? // JV 199902 fileInfo.newFile(File); - Buffer += fileInfo.typeIndicator(); + if (fileInfo.isOK()) + buffer += fileInfo.typeIndicator(); + else + continue; } } @@ -330,126 +357,152 @@ void FileDialog::Private::Reread() || fileInfo.isChar() || fileInfo.isBlock() || fileInfo.isFifo()) { - if (!regexMatch(fname, pszMask)) + typedef vector::const_iterator viterator; + viterator gbegin = glob_matches.begin(); + viterator const gend = glob_matches.end(); + if (std::find(gbegin, gend, fname) == gend) continue; } else if (!(isDir = fileInfo.isDir())) continue; DirEntry tmp; - // Note pszLsEntry is an string! - tmp.pszLsEntry = Buffer; + // Note ls_entry_ is an string! + tmp.ls_entry_ = buffer; // creates used name string temp = fname; - if (isDir) temp += '/'; + if (isDir) + temp += '/'; - tmp.pszName = temp; + tmp.name_ = temp; // creates displayed name - temp = pDirEntry->d_name; + temp = entry->d_name; if (isLink) temp += '@'; else temp += fileInfo.typeIndicator(); - tmp.pszDisplayed = temp; + tmp.displayed_ = temp; - direntries.push_back(tmp); + dir_entries_.push_back(tmp); } - closedir(pDirectory); + closedir(dir); // Sort the names - sort(direntries.begin(), direntries.end(), comp_direntry()); - + sort(dir_entries_.begin(), dir_entries_.end(), comp_direntry()); + // Add them to directory box - for (DirEntries::const_iterator cit = direntries.begin(); - cit != direntries.end(); ++cit) { - string const temp = line + cit->pszDisplayed; - fl_add_browser_line(pFileDlgForm->List, temp.c_str()); + for (DirEntries::const_iterator cit = dir_entries_.begin(); + cit != dir_entries_.end(); ++cit) { + string const temp = line + cit->displayed_; + fl_add_browser_line(file_dlg_form_->List, temp.c_str()); } - fl_set_browser_topline(pFileDlgForm->List, iDepth); - fl_show_object(pFileDlgForm->List); - iLastSel = -1; + fl_set_browser_topline(file_dlg_form_->List, depth_); + fl_show_object(file_dlg_form_->List); + last_sel_ = -1; } // SetDirectory: sets dialog current directory -void FileDialog::Private::SetDirectory(string const & Path) +void FileDialog::Private::SetDirectory(string const & path) { string tmp; - - if (!pszDirectory.empty()) { - string TempPath = ExpandPath(Path); // Expand ~/ - TempPath = MakeAbsPath(TempPath, pszDirectory); - tmp = MakeAbsPath(TempPath); - } else { - tmp = MakeAbsPath(Path); - } - + if (path.empty()) + tmp = getcwd(); + else + tmp = MakeAbsPath(ExpandPath(path), directory_); + // must check the directory exists - DIR * pDirectory = ::opendir(tmp.c_str()); - if (!pDirectory) { + DIR * dir = ::opendir(tmp.c_str()); + if (!dir) { +// FIXME: re-add ... +#if 0 Alert::err_alert(_("Warning! Couldn't open directory."), tmp); +#endif } else { - ::closedir(pDirectory); - pszDirectory = tmp; + ::closedir(dir); + directory_ = tmp; } } -// SetMask: sets dialog file mask -void FileDialog::Private::SetMask(string const & NewMask) +void FileDialog::Private::SetFilters(string const & mask) +{ + SetFilters(FileFilterList(mask)); +} + + +void FileDialog::Private::SetFilters(FileFilterList const & filters) { - pszMask = NewMask; - fl_set_input(pFileDlgForm->PatBox, pszMask.c_str()); + if (filters.empty()) + return; + + // Just take the first one for now. + typedef FileFilterList::Filter::glob_iterator glob_iterator; + glob_iterator const begin = filters[0].begin(); + glob_iterator const end = filters[0].end(); + if (begin == end) + return; + + ostringstream ss; + for (glob_iterator it = begin; it != end; ++it) { + if (it != begin) + ss << ' '; + ss << *it; + } + + mask_ = ss.str(); + fl_set_input(file_dlg_form_->PatBox, mask_.c_str()); } // SetInfoLine: sets dialog information line -void FileDialog::Private::SetInfoLine(string const & Line) +void FileDialog::Private::SetInfoLine(string const & line) { - pszInfoLine = Line; - fl_set_object_label(pFileDlgForm->FileInfo, pszInfoLine.c_str()); + info_line_ = line; + fl_set_object_label(file_dlg_form_->FileInfo, info_line_.c_str()); } FileDialog::Private::Private() { - pszDirectory = MakeAbsPath(string(".")); - pszMask = '*'; + directory_ = MakeAbsPath(string(".")); // Creates form if necessary. - if (!pFileDlgForm) { - pFileDlgForm = build_filedialog(); + if (!file_dlg_form_) { + file_dlg_form_ = build_filedialog(this); + minw_ = file_dlg_form_->form->w; + minh_ = file_dlg_form_->form->h; // Set callbacks. This means that we don't need a patch file - fl_set_object_callback(pFileDlgForm->DirBox, + fl_set_object_callback(file_dlg_form_->DirBox, C_LyXFileDlg_FileDlgCB, 0); - fl_set_object_callback(pFileDlgForm->PatBox, + fl_set_object_callback(file_dlg_form_->PatBox, C_LyXFileDlg_FileDlgCB, 1); - fl_set_object_callback(pFileDlgForm->List, + fl_set_object_callback(file_dlg_form_->List, C_LyXFileDlg_FileDlgCB, 2); - fl_set_object_callback(pFileDlgForm->Filename, + fl_set_object_callback(file_dlg_form_->Filename, C_LyXFileDlg_FileDlgCB, 3); - fl_set_object_callback(pFileDlgForm->Rescan, + fl_set_object_callback(file_dlg_form_->Rescan, C_LyXFileDlg_FileDlgCB, 10); - fl_set_object_callback(pFileDlgForm->Home, + fl_set_object_callback(file_dlg_form_->Home, C_LyXFileDlg_FileDlgCB, 11); - fl_set_object_callback(pFileDlgForm->User1, + fl_set_object_callback(file_dlg_form_->User1, C_LyXFileDlg_FileDlgCB, 12); - fl_set_object_callback(pFileDlgForm->User2, + fl_set_object_callback(file_dlg_form_->User2, C_LyXFileDlg_FileDlgCB, 13); - + // Make sure pressing the close box doesn't crash LyX. (RvdK) - fl_set_form_atclose(pFileDlgForm->form, + fl_set_form_atclose(file_dlg_form_->form, C_LyXFileDlg_CancelCB, 0); - // Register doubleclick callback - fl_set_browser_dblclick_callback(pFileDlgForm->List, + // Register doubleclick callback + fl_set_browser_dblclick_callback(file_dlg_form_->List, C_LyXFileDlg_DoubleClickCB, 0); } - fl_hide_object(pFileDlgForm->User1); - fl_hide_object(pFileDlgForm->User2); + fl_hide_object(file_dlg_form_->User1); + fl_hide_object(file_dlg_form_->User2); - r_ = Dialogs::redrawGUI.connect(SigC::slot(this, &FileDialog::Private::redraw)); + r_ = Dialogs::redrawGUI().connect(boost::bind(&FileDialog::Private::redraw, this)); } @@ -461,33 +514,36 @@ FileDialog::Private::~Private() void FileDialog::Private::redraw() { - if (pFileDlgForm->form && pFileDlgForm->form->visible) - fl_redraw_form(pFileDlgForm->form); + if (file_dlg_form_->form && file_dlg_form_->form->visible) + fl_redraw_form(file_dlg_form_->form); } // SetButton: sets file selector user button action -void FileDialog::Private::SetButton(int iIndex, string const & pszName, - string const & pszPath) +void FileDialog::Private::SetButton(int index, string const & name, + string const & path) { - FL_OBJECT * pObject; - string * pTemp; - - if (iIndex == 0) { - pObject = pFileDlgForm->User1; - pTemp = &pszUserPath1; - } else if (iIndex == 1) { - pObject = pFileDlgForm->User2; - pTemp = &pszUserPath2; - } else return; - - if (!pszName.empty() && !pszPath.empty()) { - fl_set_object_label(pObject, pszName.c_str()); - fl_show_object(pObject); - *pTemp = pszPath; + FL_OBJECT * ob; + string * tmp; + + if (index == 0) { + ob = file_dlg_form_->User1; + tmp = &user_path1_; + } else if (index == 1) { + ob = file_dlg_form_->User2; + tmp = &user_path2_; + } else { + return; + } + + if (!name.empty()) { + fl_set_object_label(ob, idex(name).c_str()); + fl_set_button_shortcut(ob, scex(name).c_str(), 1); + fl_show_object(ob); + *tmp = path; } else { - fl_hide_object(pObject); - pTemp->erase(); + fl_hide_object(ob); + tmp->erase(); } } @@ -495,84 +551,87 @@ void FileDialog::Private::SetButton(int iIndex, string const & pszName, // GetDirectory: gets last dialog directory string const FileDialog::Private::GetDirectory() const { - if (!pszDirectory.empty()) - return pszDirectory; + if (!directory_.empty()) + return directory_; else return string("."); } +namespace { + bool x_sync_kludge(bool ret) + { + XSync(fl_get_display(), false); + return ret; + } +} // namespace anon // RunDialog: handle dialog during file selection bool FileDialog::Private::RunDialog() { - force_cancel = false; - force_ok = false; - - // event loop - while (true) { - FL_OBJECT * pObject = fl_do_forms(); - - if (pObject == pFileDlgForm->Ready) { + force_cancel_ = false; + force_ok_ = false; + + // event loop + while (true) { + FL_OBJECT * ob = fl_do_forms(); + + if (ob == file_dlg_form_->Ready) { if (HandleOK()) - return true; - } else if (pObject == pFileDlgForm->Cancel - || force_cancel) - return false; - else if (force_ok) - return true; + return x_sync_kludge(true); + + } else if (ob == file_dlg_form_->Cancel || force_cancel_) + return x_sync_kludge(false); + + else if (force_ok_) + return x_sync_kludge(true); } } // XForms objects callback (static) -void FileDialog::Private::FileDlgCB(FL_OBJECT *, long lArgument) +void FileDialog::Private::FileDlgCB(FL_OBJECT *, long arg) { - if (!pCurrentDlg) return; + if (!current_dlg_) + return; - switch (lArgument) { + switch (arg) { case 0: // get directory - pCurrentDlg->SetDirectory(fl_get_input(pFileDlgForm->DirBox)); - pCurrentDlg->Reread(); + current_dlg_->SetDirectory(fl_get_input(file_dlg_form_->DirBox)); + current_dlg_->Reread(); break; case 1: // get mask - pCurrentDlg->SetMask(fl_get_input(pFileDlgForm->PatBox)); - pCurrentDlg->Reread(); + current_dlg_->SetFilters(fl_get_input(file_dlg_form_->PatBox)); + current_dlg_->Reread(); break; case 2: // list - pCurrentDlg->HandleListHit(); - break; + current_dlg_->HandleListHit(); + break; case 10: // rescan - pCurrentDlg->SetDirectory(fl_get_input(pFileDlgForm->DirBox)); - pCurrentDlg->SetMask(fl_get_input(pFileDlgForm->PatBox)); - pCurrentDlg->Reread(); + current_dlg_->SetDirectory(fl_get_input(file_dlg_form_->DirBox)); + current_dlg_->SetFilters(fl_get_input(file_dlg_form_->PatBox)); + current_dlg_->Reread(); break; case 11: // home - pCurrentDlg->SetDirectory(GetEnvPath("HOME")); - pCurrentDlg->SetMask(fl_get_input(pFileDlgForm->PatBox)); - pCurrentDlg->Reread(); + current_dlg_->SetDirectory(GetEnvPath("HOME")); + current_dlg_->SetFilters(fl_get_input(file_dlg_form_->PatBox)); + current_dlg_->Reread(); break; case 12: // user button 1 - if (!pCurrentDlg->pszUserPath1.empty()) { - pCurrentDlg->SetDirectory(pCurrentDlg->pszUserPath1); - pCurrentDlg->SetMask(fl_get_input(pFileDlgForm - ->PatBox)); - pCurrentDlg->Reread(); - } + current_dlg_->SetDirectory(current_dlg_->user_path1_); + current_dlg_->SetFilters(fl_get_input(file_dlg_form_->PatBox)); + current_dlg_->Reread(); break; case 13: // user button 2 - if (!pCurrentDlg->pszUserPath2.empty()) { - pCurrentDlg->SetDirectory(pCurrentDlg->pszUserPath2); - pCurrentDlg->SetMask(fl_get_input(pFileDlgForm - ->PatBox)); - pCurrentDlg->Reread(); - } + current_dlg_->SetDirectory(current_dlg_->user_path2_); + current_dlg_->SetFilters(fl_get_input(file_dlg_form_->PatBox)); + current_dlg_->Reread(); break; } @@ -583,40 +642,39 @@ void FileDialog::Private::FileDlgCB(FL_OBJECT *, long lArgument) void FileDialog::Private::HandleListHit() { // set info line - int const iSelect = fl_get_browser(pFileDlgForm->List); - if (iSelect > iDepth) { - SetInfoLine(direntries[iSelect - iDepth - 1].pszLsEntry); - } else { + int const select_ = fl_get_browser(file_dlg_form_->List); + if (select_ > depth_) + SetInfoLine(dir_entries_[select_ - depth_ - 1].ls_entry_); + else SetInfoLine(string()); - } } // Callback for double click in list void FileDialog::Private::DoubleClickCB(FL_OBJECT *, long) { - if (pCurrentDlg->HandleDoubleClick()) - // Simulate click on OK button - pCurrentDlg->Force(false); + // Simulate click on OK button + if (current_dlg_->HandleDoubleClick()) + current_dlg_->Force(false); } // Handle double click from list bool FileDialog::Private::HandleDoubleClick() { - string pszTemp; + string tmp; // set info line bool isDir = true; - int const iSelect = fl_get_browser(pFileDlgForm->List); - if (iSelect > iDepth) { - pszTemp = direntries[iSelect - iDepth - 1].pszName; - SetInfoLine(direntries[iSelect - iDepth - 1].pszLsEntry); - if (!suffixIs(pszTemp, '/')) { + int const select_ = fl_get_browser(file_dlg_form_->List); + if (select_ > depth_) { + tmp = dir_entries_[select_ - depth_ - 1].name_; + SetInfoLine(dir_entries_[select_ - depth_ - 1].ls_entry_); + if (!suffixIs(tmp, '/')) { isDir = false; - fl_set_input(pFileDlgForm->Filename, pszTemp.c_str()); + fl_set_input(file_dlg_form_->Filename, tmp.c_str()); } - } else if (iSelect != 0) { + } else if (select_ != 0) { SetInfoLine(string()); } else return true; @@ -626,18 +684,18 @@ bool FileDialog::Private::HandleDoubleClick() string Temp; // builds new directory name - if (iSelect > iDepth) { + if (select_ > depth_) { // Directory deeper down // First, get directory with trailing / - Temp = fl_get_input(pFileDlgForm->DirBox); + Temp = fl_get_input(file_dlg_form_->DirBox); if (!suffixIs(Temp, '/')) Temp += '/'; - Temp += pszTemp; + Temp += tmp; } else { // Directory higher up Temp.erase(); - for (int i = 0; i < iSelect; ++i) { - string piece = fl_get_browser_line(pFileDlgForm->List, i+1); + for (int i = 0; i < select_; ++i) { + string piece = fl_get_browser_line(file_dlg_form_->List, i+1); // The '+2' is here to count the '@b' (JMarc) Temp += piece.substr(i + 2); } @@ -656,32 +714,30 @@ bool FileDialog::Private::HandleDoubleClick() bool FileDialog::Private::HandleOK() { // mask was changed - string pszTemp = fl_get_input(pFileDlgForm->PatBox); - if (pszTemp != pszMask) { - SetMask(pszTemp); + string tmp = fl_get_input(file_dlg_form_->PatBox); + if (tmp != mask_) { + SetFilters(tmp); Reread(); return false; } // directory was changed - pszTemp = fl_get_input(pFileDlgForm->DirBox); - if (pszTemp!= pszDirectory) { - SetDirectory(pszTemp); + tmp = fl_get_input(file_dlg_form_->DirBox); + if (tmp != directory_) { + SetDirectory(tmp); Reread(); return false; } - + // Handle return from list - int const select = fl_get_browser(pFileDlgForm->List); - if (select > iDepth) { - string const temp = direntries[select - iDepth - 1].pszName; + int const select = fl_get_browser(file_dlg_form_->List); + if (select > depth_) { + string const temp = dir_entries_[select - depth_ - 1].name_; if (!suffixIs(temp, '/')) { // If user didn't type anything, use browser - string const name = - fl_get_input(pFileDlgForm->Filename); - if (name.empty()) { - fl_set_input(pFileDlgForm->Filename, temp.c_str()); - } + string const name = fl_get_input(file_dlg_form_->Filename); + if (name.empty()) + fl_set_input(file_dlg_form_->Filename, temp.c_str()); return true; } } @@ -695,8 +751,8 @@ bool FileDialog::Private::HandleOK() int FileDialog::Private::CancelCB(FL_FORM *, void *) { // Simulate a click on the cancel button - pCurrentDlg->Force(true); - return FL_IGNORE; + current_dlg_->Force(true); + return FL_IGNORE; } @@ -704,82 +760,145 @@ int FileDialog::Private::CancelCB(FL_FORM *, void *) void FileDialog::Private::Force(bool cancel) { if (cancel) { - force_cancel = true; - fl_set_button(pFileDlgForm->Cancel, 1); + force_cancel_ = true; + fl_set_button(file_dlg_form_->Cancel, 1); } else { - force_ok = true; - fl_set_button(pFileDlgForm->Ready, 1); + force_ok_ = true; + fl_set_button(file_dlg_form_->Ready, 1); } // Start timer to break fl_do_forms loop soon - fl_set_timer(pFileDlgForm->timer, 0.1); + fl_set_timer(file_dlg_form_->timer, 0.1); } // Select: launches dialog and returns selected file -string const FileDialog::Private::Select(string const & title, string const & path, - string const & mask, string const & suggested) +string const FileDialog::Private::Select(string const & title, + string const & path, + FileFilterList const & filters, + string const & suggested) { // handles new mask and path - bool isOk = true; - if (!mask.empty()) { - SetMask(mask); - isOk = false; - } - if (!path.empty()) { - SetDirectory(path); - isOk = false; - } - if (!isOk) Reread(); + SetFilters(filters); + SetDirectory(path); + Reread(); // highlight the suggested file in the browser, if it exists. int sel = 0; string const filename = OnlyFilename(suggested); if (!filename.empty()) { - for (int i = 0; - i < fl_get_browser_maxline(pFileDlgForm->List); ++i) { - string s = - fl_get_browser_line(pFileDlgForm->List, i + 1); - s = strip(frontStrip(s)); + for (int i = 0; i < fl_get_browser_maxline(file_dlg_form_->List); ++i) { + string s = fl_get_browser_line(file_dlg_form_->List, i + 1); + s = trim(s); if (s == filename) { sel = i + 1; break; } } } - - if (sel != 0) fl_select_browser_line(pFileDlgForm->List, sel); + + if (sel != 0) + fl_select_browser_line(file_dlg_form_->List, sel); int const top = max(sel - 5, 1); - fl_set_browser_topline(pFileDlgForm->List, top); + fl_set_browser_topline(file_dlg_form_->List, top); // checks whether dialog can be started - if (pCurrentDlg) return string(); - pCurrentDlg = this; + if (current_dlg_) + return string(); + current_dlg_ = this; // runs dialog SetInfoLine(string()); - fl_set_input(pFileDlgForm->Filename, suggested.c_str()); - fl_set_button(pFileDlgForm->Cancel, 0); - fl_set_button(pFileDlgForm->Ready, 0); - fl_set_focus_object(pFileDlgForm->form, pFileDlgForm->Filename); + setEnabled(file_dlg_form_->Filename, true); + fl_set_input(file_dlg_form_->Filename, suggested.c_str()); + fl_set_button(file_dlg_form_->Cancel, 0); + fl_set_button(file_dlg_form_->Ready, 0); + fl_set_focus_object(file_dlg_form_->form, file_dlg_form_->Filename); fl_deactivate_all_forms(); - fl_show_form(pFileDlgForm->form, + // Prevent xforms crashing if the dialog gets too small by preventing + // it from being shrunk beyond a minimum size. + // calls to fl_set_form_minsize/maxsize apply only to the next + // fl_show_form(), so this comes first. + fl_set_form_minsize(file_dlg_form_->form, minw_, minh_); + + fl_show_form(file_dlg_form_->form, FL_PLACE_MOUSE | FL_FREE_SIZE, 0, title.c_str()); - isOk = RunDialog(); - - fl_hide_form(pFileDlgForm->form); + bool const isOk = RunDialog(); + + fl_hide_form(file_dlg_form_->form); fl_activate_all_forms(); - pCurrentDlg = 0; + current_dlg_ = 0; // Returns filename or string() if no valid selection was made - if (!isOk || !fl_get_input(pFileDlgForm->Filename)[0]) return string(); + if (!isOk || !fl_get_input(file_dlg_form_->Filename)[0]) + return string(); + + file_name_ = fl_get_input(file_dlg_form_->Filename); + + if (!AbsolutePath(file_name_)) + file_name_ = AddName(fl_get_input(file_dlg_form_->DirBox), file_name_); + return file_name_; +} - pszFileName = fl_get_input(pFileDlgForm->Filename); - if (!AbsolutePath(pszFileName)) { - pszFileName = AddName(fl_get_input(pFileDlgForm->DirBox), - pszFileName); +// SelectDir: launches dialog and returns selected directory +string const FileDialog::Private::SelectDir(string const & title, + string const & path, + string const & suggested) +{ + SetFilters("*/"); + // handles new path + bool isOk = true; + if (!path.empty()) { + // handle case where path does not end with "/" + // remerge path+suggested and check if it is a valid path + if (!suggested.empty()) { + string tmp = suggested; + if (!suffixIs(tmp, '/')) + tmp += '/'; + string full_path = path; + full_path += tmp; + // check if this is really a directory + DIR * dir = ::opendir(full_path.c_str()); + if (dir) + SetDirectory(full_path); + else + SetDirectory(path); + } else + SetDirectory(path); + isOk = false; } - return pszFileName; + if (!isOk) + Reread(); + + // checks whether dialog can be started + if (current_dlg_) + return string(); + current_dlg_ = this; + + // runs dialog + SetInfoLine(string()); + fl_set_input(file_dlg_form_->Filename, ""); + setEnabled(file_dlg_form_->Filename, false); + fl_set_button(file_dlg_form_->Cancel, 0); + fl_set_button(file_dlg_form_->Ready, 0); + fl_set_focus_object(file_dlg_form_->form, file_dlg_form_->DirBox); + fl_deactivate_all_forms(); + fl_show_form(file_dlg_form_->form, + FL_PLACE_MOUSE | FL_FREE_SIZE, 0, + title.c_str()); + + isOk = RunDialog(); + + fl_hide_form(file_dlg_form_->form); + fl_activate_all_forms(); + current_dlg_ = 0; + + // Returns directory or string() if no valid selection was made + if (!isOk) + return string(); + + file_name_ = fl_get_input(file_dlg_form_->DirBox); + return file_name_; }