1 /**
2  * Dialog module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.window.dialog.openfiledialog;
8 
9 /**
10  * Imports.
11  */
12 import std.array;
13 import std.regex;
14 import tkd.window.dialog.filedialog;
15 import tkd.window.window;
16 
17 /**
18  * Pops up a dialog box for the user to open a file.
19  *
20  * Example:
21  * ---
22  * auto dialog = new OpenFileDialog("Open a file")
23  * 	.setMultiSelection(false)
24  * 	.setDefaultExtension(".txt")
25  * 	.addFileType("{{All files} {*}}")
26  * 	.addFileType("{{Text files} {.txt}}")
27  * 	.setInitialDirectory("~")
28  * 	.setInitialFile("file.txt")
29  * 	.show();
30  *
31  * string fileToOpen = dialog.getResult();
32  * ---
33  *
34  * Result:
35  *     The full path of the file selected.
36  *
37  * See_Also:
38  *     $(LINK2 ./filedialog.html, tkd.dialog.filedialog) $(BR)
39  */
40 class OpenFileDialog : FileDialog
41 {
42 	/*
43 	 * Allows the user to choose multiple files from the Open dialog.
44 	 */
45 	protected bool _selectMultiple;
46 
47 	/**
48 	 * Construct the dialog.
49 	 *
50 	 * Params:
51 	 *     parent = The parent window of the dialog.
52 	 *     title = The title of the dialog.
53 	 */
54 	this(Window parent, string title = "Open")
55 	{
56 		super(parent, title);
57 	}
58 
59 	/**
60 	 * Construct the dialog.
61 	 *
62 	 * Params:
63 	 *     title = The title of the dialog.
64 	 */
65 	this(string title = "Open")
66 	{
67 		this(null, title);
68 	}
69 
70 	/**
71 	 * Set whether to enable mutli-selection.
72 	 *
73 	 * Params:
74 	 *     enable = Enables multi-selections.
75 	 *
76 	 * Returns:
77 	 *     This dialog to aid method chaining.
78 	 */
79 	public auto setMultiSelection(this T)(bool enable)
80 	{
81 		this._selectMultiple = enable;
82 
83 		return cast(T) this;
84 	}
85 
86 	/**
87 	 * Show the dialog.
88 	 *
89 	 * Returns:
90 	 *     This dialog to aid method chaining.
91 	 */
92 	public auto show(this T)()
93 	{
94 		if (this._parent)
95 		{
96 			// String concatentation is used here to avoid the character escaping done on args.
97 			this._tk.eval("tk_getOpenFile -parent %s -title {%s} -multiple %s -defaultextension {%s} -filetypes {" ~ this._fileTypes.join(" ") ~ "} -initialdir {%s} -initialfile {%s} -typevariable %s", this._parent.id, this._title, this._selectMultiple, this._defaultExtension, this._initialDirectory, this._initialFile, this._typeVariable);
98 		}
99 		else
100 		{
101 			// String concatentation is used here to avoid the character escaping done on args.
102 			this._tk.eval("tk_getOpenFile -title {%s} -multiple %s -defaultextension {%s} -filetypes {" ~ this._fileTypes.join(" ") ~ "} -initialdir {%s} -initialfile {%s} -typevariable %s", this._title, this._selectMultiple, this._defaultExtension, this._initialDirectory, this._initialFile, this._typeVariable);
103 		}
104 
105 		string result = this._tk.getResult!(string);
106 
107 		if (match(result, r"^bad window path name").empty)
108 		{
109 			if (this._selectMultiple)
110 			{
111 				auto regexResult = matchAll(result, r"\{.*?\}");
112 				result           = result.replaceAll(regex(r"\{.*?\}"), "");
113 				this._results   ~= result.split();
114 
115 				foreach (match; regexResult)
116 				{
117 					this._results ~= match.hit;
118 				}
119 
120 				this.removeBracesFromResults;
121 			}
122 			else
123 			{
124 				this._results = [result];
125 			}
126 		}
127 
128 		return cast(T) this;
129 	}
130 
131 	/**
132 	 * Get multiple dialog results.
133 	 *
134 	 * Returns:
135 	 *     The multiple results of the dialog.
136 	 */
137 	public string[] getResults()
138 	{
139 		assert(this._selectMultiple, "You need to set multi-selection on to retrieve more than one result.");
140 
141 		return this._results;
142 	}
143 }