1 /**
2  * Dialog module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.window.dialog.filedialog;
8 
9 /**
10  * Imports.
11  */
12 import std.regex;
13 import std..string;
14 import tkd.window.dialog.dialog;
15 import tkd.window.window;
16 
17 /**
18  * Pops up a dialog box for the user to select a color.
19  *
20  * See_Also:
21  *     $(LINK2 ./dialog.html, tkd.dialog.dialog) $(BR)
22  */
23 abstract class FileDialog : Dialog
24 {
25 	/*
26 	 * The default extension for the file.
27 	 */
28 	protected string _defaultExtension;
29 
30 	/*
31 	 * A list of allowed file types.
32 	 */
33 	protected string[] _fileTypes;
34 
35 	/*
36 	 * The initial directory to start in the dialog.
37 	 */
38 	protected string _initialDirectory;
39 
40 	/*
41 	 * The initial file to use in the dialog.
42 	 */
43 	protected string _initialFile;
44 
45 	/*
46 	 * A variable to hold the state of the selected file type.
47 	 */
48 	protected string _typeVariable;
49 
50 	/**
51 	 * Construct the dialog.
52 	 *
53 	 * Params:
54 	 *     parent = The parent window of the dialog.
55 	 *     title = The title of the dialog.
56 	 */
57 	this(Window parent, string title)
58 	{
59 		this._typeVariable = format("variable-%s", this.generateHash("%s%s", this._elementId, this.id));
60 		super(parent, title);
61 
62 		// Fix to hide hidden files by default on Posix systems. This also
63 		// enables a checkbutton to show them again within the dialog.
64 		version (Posix)
65 		{
66 			this._tk.eval("catch {tk_getOpenFile foo bar}");
67 			this._tk.eval("set ::tk::dialog::file::showHiddenVar 0");
68 			this._tk.eval("set ::tk::dialog::file::showHiddenBtn 1");
69 		}
70 	}
71 
72 	/**
73 	 * Construct the dialog.
74 	 *
75 	 * Params:
76 	 *     title = The title of the dialog.
77 	 */
78 	this(string title)
79 	{
80 		this(null, title);
81 	}
82 
83 	/**
84 	 * Set the default extension.
85 	 *
86 	 * Params:
87 	 *     extension = The default extension.
88 	 *
89 	 * Returns:
90 	 *     This dialog to aid method chaining.
91 	 */
92 	public auto setDefaultExtension(this T)(string extension)
93 	{
94 		this._defaultExtension = extension;
95 
96 		return cast(T) this;
97 	}
98 
99 	/**
100 	 * Add an allowed file type. If a filetype combobox exists in the file 
101 	 * dialog on the particular platform, this adds entries to it. When the 
102 	 * user choose a filetype in the combobox, only the files of that type are 
103 	 * listed. If no types are added or if the filetypes combobox is not 
104 	 * supported by the particular platform then all files are listed 
105 	 * regardless of their types.
106 	 *
107 	 * Filetypes must be added in the correct format, i.e. all fields are 
108 	 * enclosed within curly braces and separated by a space. Extensions must 
109 	 * contain a dot. The format is described below in which the carats 
110 	 * indicate essential required space.
111 	 * ----
112 	 * {{Description} {.ext1 .ext2 .ext3 ...}}
113 	 *               ^      ^     ^     ^
114 	 * ----
115 	 *
116 	 * Params:
117 	 *     fileType = The file type to add.
118 	 *
119 	 * Returns:
120 	 *     This dialog to aid method chaining.
121 	 */
122 	public auto addFileType(this T)(string fileType)
123 	{
124 		assert(!std.regex.match(fileType, r"^\{\{.*?\} \{.*?\}\}$").empty,
125 				"File type must take the form of '{{Description} {.ext1 .ext2 .ext3 ...}}'. Braces and spaces are important!");
126 
127 		this._fileTypes ~= fileType;
128 
129 		return cast(T) this;
130 	}
131 
132 	/**
133 	 * Set the initial directory in the dialog.
134 	 *
135 	 * Params:
136 	 *     directory = The initial directory.
137 	 *
138 	 * Returns:
139 	 *     This dialog to aid method chaining.
140 	 */
141 	public auto setInitialDirectory(this T)(string directory)
142 	{
143 		this._initialDirectory = directory;
144 
145 		return cast(T) this;
146 	}
147 
148 	/**
149 	 * Set the initial file in the dialog.
150 	 *
151 	 * Params:
152 	 *     file = The initial file.
153 	 *
154 	 * Returns:
155 	 *     This dialog to aid method chaining.
156 	 */
157 	public auto setInitialFile(this T)(string file)
158 	{
159 		this._initialFile = file;
160 
161 		return cast(T) this;
162 	}
163 }