/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002 The Inti Development Team.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
//! @file inti/gtk/fileselection.h
//! @brief A GtkFileSelection C++ wrapper interface.
//!
//! Provides FileSelection, a widget that can be used to retrieve file or directory names from the user.

#ifndef INTI_GTK_FILE_SELECTION_H
#define INTI_GTK_FILE_SELECTION_H

#ifndef INTI_GTK_DIALOG_H
#include <inti/gtk/dialog.h>
#endif

#ifndef __GTK_FILESEL_H__
#include <gtk/gtkfilesel.h>
#endif

namespace Inti {

namespace Gtk {
	
class Entry;
class FileSelectionClass;
class Label;

//! @class FileSelection fileselection.h inti/gtk/fileselection.h
//! @brief A GtkFileSelection C++ wrapper class.
//!
//! FileSelection should be used to retrieve file or directory names from the user.
//! It will create a new dialog window containing a directory list, and a file list
//! corresponding to the current working directory. The filesystem can be navigated
//! using the directory list or the drop-down history menu. Alternatively, the TAB
//! key can be used to navigate using filename completion - common in text based 
//! editors such as emacs and jed.
//!
//! The default filename can be set using set_filename() and the selected filename
//! retrieved using get_filename(). Use complete() to display files and directories
//! that match a given pattern. This can be used for example, to show only *.txt 
//! files, or only files beginning with gtk*.
//!
//! Simple file operations; create directory, delete file, and rename file, are 
//! available from buttons at the top of the dialog. These can be hidden using
//! hide_fileop_buttons() and shown again using show_fileop_buttons().
//!
//! <B>Example:</B> Getting a filename from the user.
//! @code
//! #include <inti/main.h>
//! #include <inti/gtk/fileselection.h>
//! #include <inti/gtk/button.h>
//! #include <iostream>
//!
//! using namespace Inti;
//!
//! class FileSelection : public Gtk::FileSelection
//! {
//! protected:
//! 	void on_ok();
//!
//! public:
//! 	FileSelection();
//! };
//!
//! FileSelection::FileSelection()
//! : Gtk::FileSelection("File selection")
//! {
//! 	ok_button()->sig_clicked().connect(slot(this, &FileSelection::on_ok));
//! 	cancel_button()->sig_clicked().connect(slot(this, &FileSelection::dispose));
//!
//! 	// Lets set the filename, as if this were a save dialog, and we are giving a default filename.
//! 	set_filename("penguin.png");
//! }
//!
//! FileSelection::~FileSelection()
//! {
//! }
//!
//! void
//! FileSelection::on_ok()
//! {
//! 	std::cout << get_filename().c_str() << '\n';
//! }
//!
//! int main (int argc, char *argv[])
//! {
//! 	using namespace Main;
//!
//! 	init(&argc, &argv);
//!
//! 	FileSelection window;
//! 	window.sig_destroy().connect(slot(&Inti::Main::quit));
//! 	window.show();
//!
//! 	run();
//! 	return 0;
//! }
//! @endcode

class FileSelection : public Dialog
{
	friend class G::Object;
	friend class FileSelectionClass;

	FileSelection(const FileSelection&);
	FileSelection& operator=(const FileSelection&);
	
protected:
//! @name Constructors
//! @{

	explicit FileSelection(GtkFileSelection *file_selection, bool reference = false);
	//!< Construct a new FileSelection from an existing GtkFileSelection.
	//!< @param file_selection A pointer to a GtkFileSelection.
	//!< @param reference Set false if the initial reference count is floating, set true if it's not.
	//!<
	//!< <BR>The <EM>file_selection</EM> can be a newly created GtkFileSelection or an existing
	//!< GtkFileSelection (see G::Object::Object).

//! @}
//  Properties

	typedef G::Property<String> FilenamePropertyType;
	typedef G::PropertyProxy<G::Object, FilenamePropertyType> FilenamePropertyProxy;
	static const FilenamePropertyType filename_property;

	typedef G::Property<bool> ShowFileopsPropertyType;
	typedef G::PropertyProxy<G::Object, ShowFileopsPropertyType> ShowFileopsPropertyProxy;
	static const ShowFileopsPropertyType show_fileops_property;

	typedef G::Property<bool> SelectMultiplePropertyType;
	typedef G::PropertyProxy<G::Object, SelectMultiplePropertyType> SelectMultiplePropertyProxy;
	static const SelectMultiplePropertyType select_multiple_property;

public:
//! @name Constructors
//! @{

	FileSelection();
	//!< Construct a new file selection dialog box.
	//!< By default it will contain a  TreeView of the application's current working
	//!< directory, and a file listing. Operation buttons that allow the user to
	//!< create a directory, delete files and rename files, are also present.

	explicit FileSelection(const String& title);
	//!< Construct a new file selection dialog box with the specified title. 
	//!< @param title The text that will be placed in the titlebar.
	//!<
	//!< <BR>By default it will contain a  TreeView of the application's current working
	//!< directory, and a file listing. Operation buttons that allow the user to
	//!< create a directory, delete files and rename files, are also present.

	virtual ~FileSelection();
	//!< Destructor.
	
//! @}
//! @name Accessors
//! @{

	GtkFileSelection* gtk_file_selection() const { return (GtkFileSelection*)instance; }
	//!< Get a pointer to the GtkFileSelection structure.

	GtkFileSelectionClass* gtk_file_selection_class() const;
	//!< Get a pointer to the GtkFileSelectionClass structure.

	operator GtkFileSelection* () const;
	//!< Conversion operator; safely converts a FileSelection to a GtkFileSelection pointer.

	Entry* selection_entry() const;
	//!< Returns a pointer to the Entry widget containing the selected filename.

	Label* selection_text() const;
	//!< Returns a pointer to the Label widget above the Entry.

	Button* ok_button() const;
	//!< Returns a pointer to the ok_button. Signals should be connected to this button
	//!< in order to perform an action when the user hits OK.

	Button* cancel_button() const;
	//!< Returns a pointer to the cancel_button. Signals should be connected to this button
	//!< in order to perform an action when the user hits Cancel.

	Button* help_button() const;
	//!< Returns a pointer to the help_button. Signals should be connected to this button
	//!< in order to perform an action when the user hits Help.

	String get_filename(G::Error *error = 0) const;
	//!< Returns the selected filename in UTF-8 encoding; if no file is selected then the selected
	//!< directory path is returned.
	//!< @param error Location to store the conversion error, if any occurs, or null to ignore errors.
	//!< @return The currently selected filename in UTF-8 encoding.
	//!<
	//!< <BR>GTK+ returns the filename in the on-disc encoding, which may or may not be the 
	//!< same as that used by GTK+ (UTF-8). This method calls String::from_filename() to
	//!< convert the returned filename to a UTF-8 string. If error is specified and an error occurs,
	//!< G::Error::get() will be true.

	bool get_selections(std::vector<String>& selections, G::Error *error = 0) const;
	//!< Retrieves the list of file selections the user has made in the dialog box.
	//!< @param selections A reference to a vector of String that will hold the list of selected filenames.
	//!< @param error Location to store the conversion error, if any occurs, or null to ignore errors.
	//!< @return <EM>true</EM> if any files were returned in <EM>selections</EM>.
	//!<
	//!< <BR>This method is intended for use when the user can select multiple files in the file list.
	//!< The first file in the list is equivalent to what get_filename() would return. GTK+ returns
	//!< the filename in the on-disc encoding, which may or may not be the same as that used by GTK+
	//!< (UTF-8). This method calls String::from_filename() to convert each filename in the list to
	//!< a UTF-8 string. If error is specified, the method returns at the first occurrence of an error
	//!< and G::Error::get() will be true.

	bool get_select_multiple() const;
	//!< Returns true if the user is allowed to select multiple files in the file list
	//!< (see set_select_multiple()).

//! @}
//! @name Methods
//! @{

	void set_filename(const String& filename, G::Error *error = 0);
	//!< Sets a default path for the file requestor; if filename includes a directory path,
	//!< then the requestor will open with that path as its current working directory.
	//!< @param filename A UTF-8 String to set as the default file name.
	//!< @param error Location to store the conversion error, if any occurs, or null to ignore errors.
	//!<
	//!< <BR>This method converts the filename from UTF-8 to the on-disc encoding by calling
	//!< String::to_filename(). If error is specified and an error occurs, G::Error::get()
	//!< will be true.

	void complete(const String& pattern);
	//!< Will attempt to match pattern to valid filenames or subdirectories in the current directory.
	//!< @param pattern A string of characters which may or may not match any filenames in
	//!<                the current directory.
	//!<
	//!< <BR>If a match can be made, the matched filename will appear in the text entry field of
	//!< the file selection dialog. If a partial match can be made, the "Files" list will contain
	//!< those file names which have been partially matched, and the "Folders" list those 
	//!< directories which have been partially matched.

	void show_fileop_buttons();
	//!< Shows the file operation buttons, if they have previously been hidden. 
	//!< The rest of the widgets in the dialog will be resized accordingly.

	void hide_fileop_buttons();
	//!< Hides the file operation buttons that normally appear at the top of the dialog. 
	//!< Useful if you wish to create a custom file selector, based on FileSelection.
	
	void set_select_multiple(bool select_multiple);
	//!< Sets whether the user is allowed to select multiple files in the file list.
	//!< @param select_multiple Whether or not the user is allowed to select multiple files.
	//!<
	//!< <BR>Use get_selections() to get the list of selected files.

//! @}
//! @name Property Proxies
//! @{
	
	const FilenamePropertyProxy prop_filename()
	{
		return FilenamePropertyProxy(this, &filename_property);
	}
	//!< The currently selected filename (String : Read / Write).

	const ShowFileopsPropertyProxy prop_show_fileops()
	{
		return ShowFileopsPropertyProxy(this, &show_fileops_property);
	}
	//!< Whether buttons for creating/manipulating files should be displayed (bool : Read / Write).

	const SelectMultiplePropertyProxy prop_select_multiple()
	{
		return SelectMultiplePropertyProxy(this, &select_multiple_property);
	}
	//!< Whether to allow multiple files to be selected (bool : Read / Write).

//! @}
};

} // namespace Gtk

} // namespace Inti

#endif // INTI_GTK_FILE_SELECTION_H

