1 // -*- C++ -*-
2 /* GG is a GUI for OpenGL.
3    Copyright (C) 2003-2008 T. Zachary Laine
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License
7    as published by the Free Software Foundation; either version 2.1
8    of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA
19 
20    If you do not wish to comply with the terms of the LGPL please
21    contact the author as other terms are available for a fee.
22 
23    Zach Laine
24    whatwasthataddress@gmail.com */
25 
26 /** \file FileDlg.h \brief Contains the standard GG file dialog. */
27 
28 #ifndef _GG_FileDlg_h_
29 #define _GG_FileDlg_h_
30 
31 #include <GG/DropDownList.h>
32 
33 #include <boost/filesystem/path.hpp>
34 
35 
36 namespace GG {
37 
38 class TextControl;
39 class Edit;
40 class Button;
41 class Font;
42 
43 /** \brief The default file open/save dialog box.
44 
45     This dialog, like all the common GG dialogs, is modal.  It asks the user
46     for one or more filenames, which the caller may retrieve with a call to
47     Result() after the dialog is closed.  Note that all strings displayed
48     during the run of the FileDlg are customizable.  Sometimes, the FileDlg
49     will pop up a message box (a ThreeButtonDlg) and notify the user of
50     something or ask for input.  These message strings are also customizable.
51     Some of these strings include the filename as part of the message.  When
52     replacing these strings with your own, you need to include the placement
53     of the filename in the message with the character sequence "%1%" (see
54     boost.format for details). */
55 class GG_API FileDlg : public Wnd
56 {
57 public:
58     /** \name Structors */ ///@{
59     /** Basic ctor.  Parameters \a directory and \a filename pass an initial
60         directory and filename to the dialog, if desired (such as when "Save
61         As..." is selected in an app, and there is a current filename).  If \a
62         directory is specified, it is taken as-is if it is absolute, or
63         relative to boost::filesystem::initial_path() if it is relative.  If
64         \a directory is "", the initial directory is WorkingDirectory().  \a
65         save indicates whether this is a save or load dialog; \a multi
66         indicates whether multiple file selections are allowed.  \throw
67         GG::FileDlg::BadInitialDirectory Throws when \a directory is
68         invalid. */
69     FileDlg(const std::string& directory, const std::string& filename, bool save, bool multi, const std::shared_ptr<Font>& font,
70             Clr color, Clr border_color, Clr text_color = CLR_BLACK);
71     //@}
72     void CompleteConstruction() override;
73 
74     /** \name Accessors */ ///@{
75     std::set<std::string> Result() const; ///< returns a set of strings that contains the files chosen by the user; there will be only one file if \a multi == false was passed to the ctor
76 
77     /** Returns true iff this FileDlg will select directories instead of files. */
78     bool SelectDirectories() const;
79 
80     /** Returns true iff this FileDlg will append the missing extension to a
81         file when in save mode.  Note that action is only taken if there is a
82         single file filter containing exactly one wildcard in its first
83         position (i.e. it is of the form "*foo").  If precondition is
84         satisfied, any filename the user selects that does not end in "foo"
85         will have "foo" appended to it. */
86     bool AppendMissingSaveExtension() const;
87     //@}
88 
89     /** \name Mutators */ ///@{
90     void Render() override;
91     void KeyPress(Key key, std::uint32_t key_code_point, Flags<ModKey> mod_keys) override;
92 
93     /** Set this to true if this FileDlg should select directories instead of
94         files.  Note that this will only have an effect in file-open mode. */
95     void SelectDirectories(bool directories);
96 
97     /** Set this to true if this FileDlg should append the missing extension
98         to a file when in save mode.  Note that action is only taken if there
99         is a single file filter containing exactly one wildcard in its first
100         position (i.e. it is of the form "*foo").  If precondition is
101         satisfied, any filename the user selects that does not end in "foo"
102         will have "foo" appended to it. */
103     void AppendMissingSaveExtension(bool append);
104 
105     /** Sets the allowed file types.  Each pair in the \a types parameter
106         contains a description of the file type in its .first member, and
107         wildcarded file types in its .second member.  For example, an entry
108         might be ("Text Files (*.txt)", "*.txt"). Only the '*' character is
109         supported as a wildcard.  More than one wildcard expression can be
110         specified in a filter; if so, they must be separated by a comma and
111         exactly one space (", ").  Each filter is considered OR-ed together
112         with the others, so passing "*.tga, *.png" specifies listing any file
113         that is either a Targa or a PNG file.  Note that an empty filter is
114         considered to match all files, so ("All Files", "") is perfectly
115         correct. */
116     void SetFileFilters(const std::vector<std::pair<std::string, std::string>>& filters);
117     //@}
118 
119     /** Returns the current directory (the one that will be used by default on
120         the next invocation of FileDlg::Run()) */
121     static const boost::filesystem::path& WorkingDirectory();
122 
123     /** Converts a string to a path in a cross platform safe manner. */
124     static const boost::filesystem::path StringToPath(const std::string& str);
125 
126     /** \name Exceptions */ ///@{
127     /** The base class for FileDlg exceptions. */
128     GG_ABSTRACT_EXCEPTION(Exception);
129 
130     /** Thrown when the initial directory for the dialog is bad. */
131     GG_CONCRETE_EXCEPTION(BadInitialDirectory, GG::FileDlg, Exception);
132     //@}
133 
134 protected:
135     static const X DEFAULT_WIDTH;  ///< default width for the dialog
136     static const Y DEFAULT_HEIGHT; ///< default height for the dialog
137 
138 private:
139     void DoLayout();
140     void AttachSignalChildren();
141     void DetachSignalChildren();
142     void OkClicked();
143     void OkHandler(bool double_click);
144     void CancelClicked();
145     void FileSetChanged(const ListBox::SelectionSet& files);
146     void FileDoubleClicked(DropDownList::iterator it, const GG::Pt& pt, const GG::Flags<GG::ModKey>& modkeys);
147     void FilesEditChanged(const std::string& str);
148     void FilterChanged(DropDownList::iterator it);
149     void SetWorkingDirectory(const boost::filesystem::path& p);
150     void PopulateFilters();
151     void UpdateList();
152     void UpdateDirectoryText();
153     void OpenDirectory();
154 
155     Clr              m_color;
156     Clr              m_border_color;
157     Clr              m_text_color;
158     std::shared_ptr<Font> m_font;
159 
160     bool             m_save = false;
161     std::vector<std::pair<std::string, std::string>>
162                      m_file_filters;
163     std::set<std::string>
164                      m_result;
165     bool             m_select_directories = false;;
166     bool             m_append_missing_save_extension = false;;
167     bool             m_in_win32_drive_selection = false;;
168 
169     std::string      m_save_str;
170     std::string      m_open_str;
171 
172     std::shared_ptr<TextControl>     m_curr_dir_text;
173     std::shared_ptr<ListBox>         m_files_list;
174     std::shared_ptr<Edit>            m_files_edit;
175     std::shared_ptr<DropDownList>    m_filter_list;
176     std::shared_ptr<Button>          m_ok_button;
177     std::shared_ptr<Button>          m_cancel_button;
178     std::shared_ptr<TextControl>     m_files_label;
179     std::shared_ptr<TextControl>     m_file_types_label;
180 
181     std::string      m_init_directory; ///< directory passed to constructor
182     std::string      m_init_filename; ///< filename passed to constructor
183 
184     static boost::filesystem::path s_working_dir; ///< declared static so each instance of FileDlg opens up the same directory
185 };
186 
187 } // namespace GG
188 
189 #endif
190