1 <?php
2 /**
3 * Contains Dialog class for Alphred
4 *
5 * PHP version 5
6 *
7 * @package Alphred
8 * @copyright Shawn Patrick Rice 2014
9 * @license http://opensource.org/licenses/MIT MIT
10 * @version 1.0.0
11 * @author Shawn Patrick Rice <rice@shawnrice.org>
12 * @link http://www.github.com/shawnrice/alphred
13 * @link http://shawnrice.github.io/alphred
14 * @since File available since Release 1.0.0
15 *
16 */
17
18 namespace Alphred;
19
20 /**
21 * Class to create standard AppleScript dialogs.
22 *
23 * This class is awkward.
24 *
25 * @todo Revisit developer experience of creating dialogs
26 *
27 */
28 class Dialog {
29
30 /**
31 * Initializes the AppleScript dialog, optionally setting values necessary
32 *
33 * @since 1.0.0
34 * @todo Add in better error checking
35 *
36 * @param array $values an array of values to set
37 */
38 public function __construct( $values = [] ) {
39 // Has this been initialized with values in the array?
40 if ( count( $values ) > 0 ) {
41 // Cycle through the array and set the appropriate variables
42 foreach ( $values as $k => $v ) :
43 // Make sure that the method exists and then set the value
44 if ( method_exists( $this, "set_{$k}" ) ) {
45 $method = "set_{$k}";
46 // Call the methods on this object
47 $this->$method( $v );
48 }
49 endforeach;
50 }
51
52 }
53
54 /**
55 * Assembles the AppleScript code for the dialog based on the object's values
56 *
57 * @since 1.0.0
58 *
59 * @return [type] [description]
60 */
61 private function create_dialog() {
62
63 // The script starts with this....
64 $this->script = "display dialog \"{$this->text}\"";
65
66 // Cycle through all the possible values...
67 /**
68 * @todo Should I change this to a foreach loop with an array?
69 */
70 if ( isset( $this->buttons_ ) ) {
71 $this->script .= $this->buttons_;
72 }
73 if ( isset( $this->default_answer ) ) {
74 $this->script .= $this->default_answer;
75 }
76 if ( isset( $this->title ) ) {
77 $this->script .= $this->title;
78 }
79 if ( isset( $this->icon ) ) {
80 $this->script .= $this->icon;
81 }
82 if ( isset( $this->hidden_answer ) ) {
83 $this->script .= $this->hidden_answer;
84 }
85 if ( isset( $this->cancel ) ) {
86 $this->script .= $this->cancel;
87 }
88 if ( isset( $this->timeout ) ) {
89 $this->script .= $this->timeout;
90 }
91 }
92
93 /**
94 * Executes the dialog
95 *
96 * @return text the text returned from the dialog (button press/answer)
97 */
98 public function execute() {
99 // Create the script
100 $this->create_dialog();
101
102 // Execute the script
103 $result = exec( "osascript -e '{$this->script}' 2>&1" );
104
105 // Each of these below processes the text returned
106 if ( false !== strpos( $result, ', gave up:false' ) ) {
107 $result = str_replace( ', gave up:false', '', $result );
108 }
109 if ( false !== strpos( $result, 'gave up:true' ) ) {
110 // There was a timeout on the dialog, and it, well, timed out
111 return 'timeout';
112 }
113 if ( false !== strpos( $result, 'execution error: User canceled. (-128)' ) ) {
114 // The user pressed the cancel button
115 return 'canceled';
116 }
117 if ( false !== strpos( $result, 'text returned:' ) ) {
118 return substr( $result, strpos( $result, 'text returned:' ) + 14 );
119 }
120 return str_replace( 'button returned:', '', $result );
121 }
122
123 /**
124 * Sets an icon to use in the dialog box
125 *
126 * @since 1.0.0
127 * @todo Add in exceptions?
128 *
129 * @param string $icon the path to the icon or the name of the icon
130 */
131 public function set_icon( $icon ) {
132 // These are the default options
133 $default_icons = [ 'stop', 'note', 'caution' ];
134 // The is icon one of the defualts?
135 if ( in_array( strtolower( $icon ), $default_icons ) ) {
136 // Set the "icon" text
137 $this->icon = ' with icon ' . array_search( $icon, $default_icons );
138 return true;
139 }
140 if ( ! file_exists( realpath( $icon ) ) ) {
141 // The icon doesn't exist. Should I throw an exception?
142 return false;
143 }
144 // Convert the POSIX path to the kind that AppleScript wants
145 $icon = str_replace( '/', ':', realpath( $icon ) );
146 // Set the "icon text"
147 $this->icon = ' with icon file "' . substr( $icon, 1, strlen( $icon ) - 1 ) . '"';
148 return true;
149 }
150
151 /**
152 * Sets the text for the dialog and adds slashes to ensure the dialog code does not break
153 *
154 * @since 1.0.0
155 * @todo Check to make sure that this is necessary
156 *
157 * @param string $text the text for the AppleScript dialog
158 */
159 public function set_text( $text ) {
160 $this->text = addslashes( $text ); // is the addslashes necessary?
161 }
162
163 /**
164 * Sets the buttons for the dialog box
165 *
166 * @since 1.0.0
167 * @todo Check for what I need to do to santize these
168 *
169 * @param array $buttons [description]
170 * @param string $default [description]
171 */
172 public function set_buttons( $buttons, $default = '' ) {
173 if ( empty( $buttons ) ) {
174 // One could wonder why you're trying to give us an empty set of buttons. Give me an array, please.
175 // Or a string. Just something. Give me something.
176 return false;
177 }
178 $this->buttons = $buttons; // to use later if setting the default.
179 if ( is_array( $buttons ) && ( count( $buttons ) > 0 ) ) {
180 $this->buttons_ = 'buttons {';
181 foreach ( $buttons as $b ) :
182 $this->buttons_ .= "\"{$b}\",";
183 endforeach;
184 $this->buttons_ = substr( $this->buttons_, 0, -1 ) . '}';
185 } else if ( is_string( $buttons ) ) {
186 $this->buttons_ = " buttons {\"{$buttons}\"}";
187 }
188
189 // If the default button was also passed, then set the default button
190 if ( ! empty( $default ) ) {
191 $this->set_default_button( $default );
192 }
193 }
194
195 /**
196 * Sets the default button
197 *
198 * @since 1.0.0
199 *
200 * @param sting $button the name of the button to set as default
201 */
202 public function set_default_button( $button ) {
203 // The button must be in the extant array of buttons. And AppleScript
204 // wants the number of the button, but it starts with 1 and not 0, so
205 // do a search, add 1, and set it as that.
206 if ( $default = ( array_search( $button, $this->buttons ) + 1 ) ) {
207 $this->buttons_ .= " default button {$default}";
208 return true;
209 }
210 // The button wasn't found. Um.... what?
211 return false;
212 }
213
214 /**
215 * Sets the title of the dialog
216 *
217 * @since 1.0.0
218 *
219 * @param string $title title for the dialog
220 */
221 public function set_title( $title ) {
222 // Add slashes so as not to break the dialog
223 $title = addslashes( $title );
224 $this->title = " with title \"{$title}\"";
225 }
226
227 public function set_default_answer( $text ) {
228 $this->default_answer = " default answer \"{$text}\"";
229 }
230
231 public function set_timeout( $seconds ) {
232 $this->timeout = " giving up after {$seconds}";
233 }
234
235 public function set_cancel( $cancel ) {
236 $this->cancel = " cancel button \"{$cancel}\"";
237 }
238
239 public function set_hidden_answer( $hidden = false ) {
240 if ( $hidden ) {
241 $this->hidden_answer = ' hidden answer true';
242 // Since the input box will not show up unless there is a default answer
243 // set, we'll go ahead and set a blank default answer if one hasn't been
244 // set yet.
245 if ( ! isset( $this->default_answer ) ) {
246 $this->set_default_answer( '' );
247 }
248 }
249 }
250
251 }