History: Save or Load file dialog using boost
Source of version: 2 (current)
Copy to clipboard
You need boost/filesystem library for this! It's not included in depedencys of Ogre packet.
{CODE(caption="YourApplication", wrap="1", colors="c++")}
//Create new dialog:
m_pFileDialog = new FileSelectionDialog;
m_pFileDialog->setDialogTitle("Save file");
m_pFileDialog->setButtonCaption("Save");
m_pFileDialog->addFileExtension(".h");
m_pFileDialog->addFileExtension(".cpp");
//Add youd own callback function:
boost::function<void(Dialog*, const std::string&)> my_callback = boost::bind(&My_Class::myFileSelectedCallBack, this, _1, _2);
m_pFileDialog->eventEndDialog(my_callback);
//Your callback must be something like that:
//void myFileSelectedCallBack(FileSelectionDialog* dialog, const std::string& path){...Do what you want...};
//How to pop it up:
m_pFileDialog->update();
m_pFileDialog->setVisible(true);
//After all don't foget delete it:
delete m_pFileDialog;
{CODE}
{CODE(caption="FileDialog.layout", wrap="1", colors="c++")}
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout" version="3.2.0">
<Widget type="Window" skin="WindowCSX" position="40 44 505 351" layer="Main" name="DialogWindow">
<Widget type="ListBox" skin="ListBox" position="5 35 485 246" align="Stretch" name="List"/>
<Widget type="ComboBox" skin="ComboBox" position="5 3 485 30" align="HStretch Top" name="Recent"/>
<Widget type="Button" skin="Button" position="400 285 90 26" align="Right Bottom" name="Confirm"/>
<Widget type="EditBox" skin="EditBox" position="5 285 285 26" align="HStretch Bottom" name="Edit"/>
<Widget type="ComboBox" skin="ComboBox" position="300 285 95 26" align="Right Bottom" name="Extension"/>
</Widget>
</MyGUI>
{CODE}
{CODE(caption="FileSelectionDialog.h", wrap="1", colors="c++")}
#ifndef DIALOG_H
#define DIALOG_H
#include <boost\filesystem.hpp>
#include <boost\function.hpp>
#include <MyGUI.h>
class FileSelectionDialog
{
public:
FileSelectionDialog(const std::string& name);
const std::string& getName();
void update();
void setVisible(bool set);
void setDialogTitle(const std::string& title);
void setButtonCaption(const std::string& caption);
void addFileExtension(const std::string& ext);
void setDefaultExtension(int index);
void setUserString(const std::string& value);
void buildGUI();
const std::string& getUserString();
void eventEndDialog(boost::function<void(FileSelectionDialog*, const std::string&)> method);
private:
void windowCloseCallback(MyGUI::Window* _sender, const std::string& _name);
void itemAcceptedCallback(MyGUI::ListBox* _sender, size_t _index);
void itemSelectedCallback(MyGUI::ListBox* _sender, size_t _index);
void recentPathSelectedCallback(MyGUI::ComboBox* _sender, size_t _index);
void endDialogCallback(MyGUI::Widget* _sender);
void windowResizeCallback(MyGUI::Widget* _sender, const std::string& _key, const std::string& _value);
void extensionChangeCallback(MyGUI::ComboBox* _sender, size_t _index);
void updatePathList(boost::filesystem::path my_path);
//static int nDialogs;
//int mDialogIndex;
//void (GUIManager::*mUserMethod)(const std::string&, const std::string&);
std::string mName;
std::string mUserString;
// user callback
boost::function<void(FileSelectionDialog*, const std::string&)> mUserMethod;
// widgets
MyGUI::Window* mWindow;
MyGUI::List* mPathList;
MyGUI::Edit* mFileEdit;
MyGUI::Button* mButton;
MyGUI::ComboBox* mRecentCombo;
MyGUI::ComboBox* mExtensionCombo;
boost::filesystem::path mCurrentPath; // current viewed directory
std::vector<boost::filesystem::path> mPath_set; // list of paths in the viewed directory
boost::filesystem::path* mSelectedFile;
std::vector<boost::filesystem::path> mRecentPaths;
};
#endif // DIALOG_H
{CODE}
{CODE(caption="FileSelectionDialog.cpp", wrap="1", colors="c++")}
#include "FileSelectionDialog.h"
using namespace boost::filesystem;
//int Dialog::nDialogs = 0;
FileSelectionDialog::FileSelectionDialog(const std::string& name) :
mName(name),
mWindow(0),
mPathList(0),
mFileEdit(0),
mButton(0),
mRecentCombo(0),
mExtensionCombo(0),
mSelectedFile(0),
mUserMethod(0)
{
buildGUI();
}
//==========================================================================
// Useful after after deleted all widgets from scene
//==========================================================================
void FileSelectionDialog::buildGUI(){
// load dialog layout
MyGUI::VectorWidgetPtr widgets = MyGUI::LayoutManager::getInstance().loadLayout("FileDialog.layout");
mWindow = (MyGUI::Window*)*widgets.begin();
mWindow->eventWindowButtonPressed += MyGUI::newDelegate(this, &FileSelectionDialog::windowCloseCallback);
mWindow->setVisible(false);
mPathList = (MyGUI::List*)mWindow->findWidget("List");
mPathList->eventListSelectAccept += MyGUI::newDelegate(this, &FileSelectionDialog::itemAcceptedCallback);
mPathList->eventListChangePosition += MyGUI::newDelegate(this, &FileSelectionDialog::itemSelectedCallback);
mFileEdit = (MyGUI::Edit*)mWindow->findWidget("Edit");
mButton = (MyGUI::Button*)mWindow->findWidget("Confirm");
mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &FileSelectionDialog::endDialogCallback);
mRecentCombo = (MyGUI::ComboBox*)mWindow->findWidget("Recent");
mRecentCombo->eventComboChangePosition += MyGUI::newDelegate(this, &FileSelectionDialog::recentPathSelectedCallback);
mExtensionCombo = (MyGUI::ComboBox*)mWindow->findWidget("Extension");
mExtensionCombo->eventComboChangePosition += MyGUI::newDelegate(this, &FileSelectionDialog::extensionChangeCallback);
mExtensionCombo->addItem("All files \".\"");
mExtensionCombo->setIndexSelected(0);
}
//==========================================================================
// User closed Dialog window
//==========================================================================
void FileSelectionDialog::windowCloseCallback(MyGUI::Window* _sender, const std::string& _name)
{
mWindow->setVisible(false);
}
//==========================================================================
// User selected a path (double-clicked)
//==========================================================================
void FileSelectionDialog::itemAcceptedCallback(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == 0) // user clicked on the "[...]", so back up a directory
{
updatePathList(mCurrentPath.parent_path().string());
}
// it's a folder, open it
else if (is_directory(mPath_set[_index-1]))
{
updatePathList(mPath_set[_index-1]);
}
// it's a file, notify user and quit
else
{
endDialogCallback(0);
}
}
//==========================================================================
// User selected a path (single click)
//==========================================================================
void FileSelectionDialog::itemSelectedCallback(MyGUI::ListBox* _sender, size_t _index)
{
//TODO fix bug?: if in filelist, file / folder selected and then click to list box to empty line, calls this with _index = int.max(?)
if (_index > mPath_set.size())
return;
// make sure it's a file
if (_index != 0 && !is_directory(mPath_set[_index-1]))
{
// mark as selected
mSelectedFile = &mPath_set[_index-1];
mFileEdit->setCaption(mPathList->getItemNameAt(_index));
}
}
//==========================================================================
// User re-opened a recently visited folder
//==========================================================================
void FileSelectionDialog::recentPathSelectedCallback(MyGUI::ComboBox* _sender, size_t _index)
{
updatePathList(mRecentPaths[_index].parent_path());
}
//==========================================================================
// Dialog's closed
//==========================================================================
void FileSelectionDialog::endDialogCallback(MyGUI::Widget* _sender)
{
// last minute fix --forgot to account for the user entering the filename himself
// Note that since the Dialog has no idea if the user should be creating a new file, it doesn't check if the
// file exists or not. That's your job.
std::string filename = mFileEdit->getCaption();
// make sure it has an extension
if (mExtensionCombo->getIndexSelected() != 0)
{
std::string extension = mExtensionCombo->getCaption();
if (filename.length() > extension.length())
{
if(filename.compare(filename.length() - extension.length(), extension.length(), extension))
filename.append(extension);
}
else
filename.append(extension);
}
mSelectedFile = new path(mPath_set[0].parent_path().append(filename.begin(), filename.end()));
//--
if (mSelectedFile)
{
// notify user of selected file (empty string if none)
if (mUserMethod)
{
mUserMethod(this, mSelectedFile->string());
}
// update recently visited paths
bool newEntry = true;
for (size_t i = 0; i < mRecentPaths.size(); i++)
{
if (*mSelectedFile == mRecentPaths[i])
{
newEntry = false;
break;
}
}
if (newEntry)
{
mRecentPaths.push_back(*mSelectedFile);
mRecentCombo->addItem(mSelectedFile->parent_path().string());
}
// close dialog
mWindow->setVisible(false);
}
// follow up of the fix
delete mSelectedFile;
mSelectedFile = 0;
}
//==========================================================================
// called when a new extension is set
//==========================================================================
void FileSelectionDialog::extensionChangeCallback(MyGUI::ComboBox* _sender, size_t _index)
{
update();
}
//==========================================================================
// Set callback for when a file is selected
//==========================================================================
void FileSelectionDialog::eventEndDialog(boost::function<void(FileSelectionDialog*, const std::string&)> method)
{
mUserMethod = method;
}
//==========================================================================
// get dialog name
//==========================================================================
const std::string& FileSelectionDialog::getName()
{
return mName;
}
//==========================================================================
// Must be called once dialog is initialized with the functions below
//==========================================================================
void FileSelectionDialog::update()
{
updatePathList(current_path());
}
//==========================================================================
// show/hide dialog
//==========================================================================
void FileSelectionDialog::setVisible(bool set)
{
mWindow->setVisible(set);
}
//==========================================================================
// set dialog window title
//==========================================================================
void FileSelectionDialog::setDialogTitle(const std::string& title)
{
mWindow->setCaption(title);
}
//==========================================================================
// set button caption (ie: save, load, save as..)
//==========================================================================
void FileSelectionDialog::setButtonCaption(const std::string& caption)
{
mButton->setCaption(caption);
}
//==========================================================================
// Attaches a string to this dialog that can be retrieved later.
// Handy for using the same Dialog for different things
//==========================================================================
void FileSelectionDialog::setUserString(const std::string& value)
{
mUserString = value;
}
//==========================================================================
// Return user string
//==========================================================================
const std::string& FileSelectionDialog::getUserString()
{
return mUserString;
}
//==========================================================================
// Add an extension to the extension combobox
//==========================================================================
void FileSelectionDialog::addFileExtension(const std::string& ext)
{
mExtensionCombo->addItem(ext);
mExtensionCombo->setIndexSelected(0); // MyGUI appears to reset
// the selected item to ITEM_NONE
// whenever a new item is added
}
//==========================================================================
// If this isn't called, the default is show all files.
//==========================================================================
void FileSelectionDialog::setDefaultExtension(int index)
{
mExtensionCombo->setIndexSelected(index + 1);
}
//==========================================================================
// Sort paths alphabetically (folders first, files last)
//==========================================================================
bool sortFunction(boost::filesystem::path p1, boost::filesystem::path p2)
{
bool d1 = is_directory(p1);
bool d2 = is_directory(p2);
if (d1 && d2)
return (p1.filename() < p2.filename());
else if (d1)
return true;
else if (d2)
return false;
else
return (p1.filename() < p2.filename());
}
//==========================================================================
// Update the paths in the dialog
// my_path; parent directory
// Note: this function is slow. Mainly because i'm lazy.
//==========================================================================
void FileSelectionDialog::updatePathList(path my_path)
{
mCurrentPath = my_path;
mPathList->removeAllItems();
mPath_set.clear();
mPathList->addItem("[...]");
std::vector<path> temp_paths;
try
{
copy(directory_iterator(mCurrentPath), directory_iterator(), back_inserter(temp_paths));
}
catch(const filesystem_error& ex)
{
// the user probably backed up too far. Jackass.
mCurrentPath = current_path().parent_path();
copy(directory_iterator(mCurrentPath), directory_iterator(), back_inserter(temp_paths));
}
// some shitty OSs don't sort paths..
sort(temp_paths.begin(), temp_paths.end(), sortFunction);
// extension
std::string ext = mExtensionCombo->getItem(mExtensionCombo->getIndexSelected());
for (size_t i = 0; i < temp_paths.size(); i++)
{
// folder
if (is_directory(temp_paths[i]))
{
mPath_set.push_back(temp_paths[i]);
mPathList->addItem(MyGUI::UString("[") + MyGUI::UString(temp_paths[i].filename().c_str()) + ']');
}
// file
else
{
// filter to extension (if any)
if (mExtensionCombo->getIndexSelected() != 0)
{
if (temp_paths[i].extension() == ext)
{
MyGUI::UString path = temp_paths[i].filename().c_str();
mPathList->addItem(path);
mPath_set.push_back(temp_paths[i]);
}
}
else
{
MyGUI::UString path = temp_paths[i].filename().c_str();
mPathList->addItem(path);
mPath_set.push_back(temp_paths[i]);
}
}
}
}
{CODE}