widget_factory.hpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2005-2007 Adobe Systems Incorporated 00003 Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt 00004 or a copy at http://stlab.adobe.com/licenses.html) 00005 */ 00006 00007 /*************************************************************************************************/ 00008 00009 #ifndef ADOBE_WIDGET_FACTORY_HPP 00010 #define ADOBE_WIDGET_FACTORY_HPP 00011 00012 /*************************************************************************************************/ 00013 00014 #include <boost/concept_check.hpp> 00015 #include <boost/utility/enable_if.hpp> 00016 #include <boost/type_traits.hpp> 00017 #include <boost/mpl/bool_fwd.hpp> 00018 #include <boost/signals/connection.hpp> 00019 00020 #include <adobe/adam.hpp> 00021 #include <adobe/any_regular.hpp> 00022 #include <adobe/eve.hpp> 00023 #include <adobe/eve_evaluate.hpp> 00024 #include <adobe/poly_controller.hpp> 00025 #include <adobe/poly_placeable.hpp> 00026 #include <adobe/poly_view.hpp> 00027 00028 #include <adobe/future/widgets/headers/factory.hpp> 00029 #include <adobe/future/widgets/headers/widget_tokens.hpp> 00030 00031 /*************************************************************************************************/ 00032 00033 namespace adobe { 00034 00035 /*************************************************************************************************/ 00036 00037 typedef std::vector<name_t> touch_set_t; 00038 00039 struct factory_token_t; 00040 00041 /*************************************************************************************************/ 00042 00043 template <typename FactoryToken> 00044 sheet_t& token_layout_sheet(const FactoryToken& token) 00045 { 00046 return token.client_holder_m.layout_sheet_m; 00047 } 00048 00049 /*************************************************************************************************/ 00050 00051 template <typename FactoryToken> 00052 sheet_t& token_property_model(const FactoryToken& token) 00053 { 00054 return token.sheet_m; 00055 } 00056 00057 /*************************************************************************************************/ 00058 00059 template <typename FactoryToken> 00060 assemblage_t& token_assemblage(const FactoryToken& token) 00061 { 00062 return token.client_holder_m.assemblage_m; 00063 } 00064 00065 /*************************************************************************************************/ 00066 00067 template <typename FactoryToken> 00068 behavior_t& token_layout_behavior(const FactoryToken& token) 00069 { 00070 return token.client_holder_m.root_behavior_m; 00071 } 00072 00073 /****************************************************************************************************/ 00074 00075 namespace implementation { 00076 00077 /*************************************************************************************************/ 00078 00079 inline void sheet_set(sheet_t* sheet, 00080 name_t name, 00081 const any_regular_t& value) 00082 { 00083 sheet->set(name, value); 00084 sheet->update(); 00085 } 00086 00087 /*************************************************************************************************/ 00088 00089 size_enum_t enumerate_size(const name_t& size); 00090 00091 /*************************************************************************************************/ 00092 00093 theme_t size_to_theme(size_enum_t size); 00094 00095 /*************************************************************************************************/ 00096 00097 touch_set_t touch_set(const dictionary_t& parameters); 00098 00099 /*************************************************************************************************/ 00100 00101 template <typename ModelType> 00102 inline void touch_set_update(sheet_t& sheet, 00103 const sheet_t::monitor_value_t& set_proc, 00104 const ModelType& new_value, 00105 touch_set_t touch_set, 00106 behavior_t& layout_behavior) 00107 { 00108 if (!touch_set.empty()) 00109 sheet.touch(&touch_set.front(), &touch_set.front() + touch_set.size()); 00110 00111 set_proc(any_regular_t(new_value)); 00112 00113 layout_behavior(); 00114 } 00115 00116 /*************************************************************************************************/ 00117 00118 inline sheet_t::monitor_value_t obtain_set_cell_from_controller_proc(sheet_t& sheet, name_t cell) 00119 { 00120 return boost::bind(&implementation::sheet_set, 00121 &sheet, 00122 cell, 00123 _1); 00124 } 00125 00126 /*************************************************************************************************/ 00127 00128 } // namespace implementation 00129 00130 /*************************************************************************************************/ 00131 00132 template <class AP, class P> // P models poly_placeable_t or poly_placeable_twopass_t, 00133 inline eve_t::iterator attach_placeable(eve_t::iterator parent_token, 00134 P& widget, 00135 const dictionary_t& parameters, 00136 const factory_token_t& token, 00137 bool is_container, 00138 const layout_attributes_t& layout_attributes) 00139 { 00140 AP* element = new AP(&widget); 00141 token.client_holder_m.assemblage_m.cleanup(boost::bind(delete_ptr(), element)); 00142 00143 layout_attributes_t attributes = layout_attributes; 00144 apply_layout_parameters(attributes, parameters); 00145 00146 return token.client_holder_m.eve_m.add_placeable( parent_token, 00147 attributes, 00148 is_container, 00149 poly_cast<poly_placeable_t&>(*element)); 00150 } 00151 00152 /*************************************************************************************************/ 00153 00154 template <typename Controller, typename FactoryToken> 00155 void attach_monitor(Controller& controller, 00156 name_t cell, 00157 sheet_t& sheet, 00158 const FactoryToken& token, 00159 const dictionary_t& parameters) 00160 { 00161 sheet_t::monitor_value_t set_cell_from_controller_proc = 00162 implementation::obtain_set_cell_from_controller_proc(sheet, cell); 00163 00164 typedef typename ControllerConcept<Controller>::model_type controller_model_type; 00165 00166 boost::function<void (const controller_model_type&)> setter 00167 (boost::bind(&implementation::touch_set_update<controller_model_type>, 00168 boost::ref(sheet), 00169 set_cell_from_controller_proc, 00170 _1, 00171 implementation::touch_set(parameters), 00172 boost::ref(token_layout_behavior(token)))); 00173 00174 controller.monitor(setter); 00175 } 00176 00177 /*************************************************************************************************/ 00183 template <typename ModelType> 00184 class splitter_controller_adaptor 00185 { 00186 public: 00187 typedef ModelType model_type; 00188 00189 splitter_controller_adaptor(sheet_t& sheet, 00190 behavior_t& layout_behavior, 00191 const array_t& cell_set, 00192 modifiers_t pass_thru = modifiers_t()) : 00193 sheet_m(&sheet), 00194 layout_behavior_m(&layout_behavior), 00195 cell_set_m(cell_set), 00196 pass_thru_m(pass_thru) 00197 { } 00198 00199 void operator()(const model_type& value, 00200 modifiers_t modifiers = modifiers_t()) 00201 { 00202 if ((pass_thru_m & modifiers) == 0) 00203 return; 00204 00205 array_t::iterator iter(cell_set_m.begin()); 00206 array_t::iterator last(cell_set_m.end()); 00207 00208 while (iter != last) 00209 { 00210 sheet_m->set(iter->cast<name_t>(), value); 00211 00212 ++iter; 00213 } 00214 00215 sheet_m->update(); 00216 00217 (*layout_behavior_m)(); 00218 } 00219 00220 private: 00221 sheet_t* sheet_m; 00222 behavior_t* layout_behavior_m; 00223 array_t cell_set_m; 00224 modifiers_t pass_thru_m; 00225 }; 00226 00227 /*************************************************************************************************/ 00228 00229 template <typename View> 00230 struct force_relayout_view_adaptor 00231 { 00232 typedef typename ViewConcept<View>::model_type model_type; 00233 00234 force_relayout_view_adaptor(View& view, visible_change_queue_t& queue) : 00235 view_m(&view), 00236 queue_m(&queue) 00237 { } 00238 00239 void display(const model_type& value) 00240 { 00241 assert(view_m && queue_m); 00242 00243 ViewConcept<View>::display(*view_m, value); 00244 00245 queue_m->force_m = true; 00246 } 00247 00248 View* view_m; 00249 visible_change_queue_t* queue_m; 00250 }; 00251 00252 /*************************************************************************************************/ 00253 00254 template <class View, class Sheet> 00255 void attach_view(assemblage_t& assemblage, 00256 name_t cell, 00257 View& control, 00258 Sheet& sheet) 00259 { 00260 poly_view_t* view(new poly_view_t(boost::ref(control))); 00261 assemblage_cleanup_ptr(assemblage, view); 00262 sheet_t::monitor_value_t m(boost::bind(&ViewConcept<poly_view_t>::display, 00263 boost::ref(*view), _1)); 00264 typename Sheet::connection_t c(sheet.monitor_value(cell, m)); 00265 assemblage_cleanup_connection(assemblage, c); 00266 } 00267 00268 /*************************************************************************************************/ 00269 00270 template <class Controller> 00271 void attach_enabler(assemblage_t& assemblage, name_t cell, Controller& control, sheet_t& sheet, 00272 const dictionary_t& parameters) 00273 { 00274 poly_controller_t* controller(new poly_controller_t(&control)); 00275 assemblage_cleanup_ptr(assemblage, controller); 00276 touch_set_t v(implementation::touch_set(parameters)); 00277 sheet_t::monitor_enabled_t 00278 m(boost::bind(&ControllerConcept<poly_controller_t>::enable, boost::ref(*controller), _1)); 00279 00280 typename sheet_t::connection_t c; 00281 if(v.empty()) c = sheet.monitor_enabled(cell, NULL, NULL, m); 00282 else c = sheet.monitor_enabled(cell, &v[0], &v[0] + v.size(), m); 00283 assemblage_cleanup_connection(assemblage, c); 00284 } 00285 00286 /*************************************************************************************************/ 00287 00288 template <typename T, typename P> 00289 inline widget_node_t create_and_hookup_widget(const dictionary_t& parameters, 00290 const widget_node_t& parent, 00291 const factory_token_t& token, 00292 bool is_container, 00293 const layout_attributes_t& layout_attributes) 00294 { 00295 size_enum_t size(parameters.count(key_size) ? 00296 implementation::enumerate_size( 00297 get_value(parameters, key_size).cast<name_t>()) : parent.size_m); 00298 00299 T* widget(NULL); 00300 create_widget(parameters, size, widget); 00301 token.client_holder_m.assemblage_m.cleanup(boost::bind(delete_ptr(),widget)); 00302 00303 // 00304 // Call display_insertion to embed the new widget within the view heirarchy 00305 // 00306 platform_display_type display_token(insert(get_main_display(), 00307 parent.display_token_m, *widget)); 00308 00309 // 00310 // As per SF.net bug 1428833, we want to attach the poly_placeable_t 00311 // to Eve before we attach the controller and view to the model 00312 // 00313 00314 eve_t::iterator eve_token; 00315 00316 eve_token = attach_placeable<P>(parent.eve_token_m, 00317 *widget, 00318 parameters, 00319 token, 00320 is_container, 00321 layout_attributes); 00322 00323 attach_view_and_controller(*widget, parameters, token); 00324 00325 // 00326 // Return the widget_node_t that comprises the tokens created for 00327 // this widget by the various components 00328 // 00329 //revist: MM, hook up keyboard insertion mechanism 00330 return widget_node_t(size, eve_token, display_token, parent.keyboard_token_m); 00331 } 00332 00333 /****************************************************************************************************/ 00334 00335 template <typename Controller, typename FactoryToken> 00336 void couple_controller_to_cell(Controller& controller, 00337 name_t cell, 00338 sheet_t& sheet, 00339 const FactoryToken& token, 00340 const dictionary_t& parameters) 00341 00342 { 00343 attach_enabler(token_assemblage(token), cell, controller, sheet, parameters); 00344 attach_monitor(controller, cell, sheet, token, parameters); 00345 } 00346 00347 /*************************************************************************************************/ 00348 00349 template <typename T, typename FactoryToken> 00350 void attach_controller_direct(T& control, 00351 const adobe::dictionary_t& parameters, 00352 const FactoryToken& token, 00353 adobe::name_t cell) 00354 { 00355 if (cell == name_t()) 00356 return; 00357 00358 sheet_t& layout_sheet(token_layout_sheet(token)); 00359 sheet_t& property_model(token_property_model(token)); 00360 00361 // is the cell in the layout sheet or the Adam sheet? 00362 if (layout_sheet.count_interface(cell) != 0) 00363 couple_controller_to_cell(control, cell, layout_sheet, 00364 token, parameters); 00365 else 00366 couple_controller_to_cell(control, cell, property_model, 00367 token, parameters); 00368 } 00369 00370 /*************************************************************************************************/ 00371 00372 template <typename T, typename FactoryToken> 00373 void attach_controller(T& control, 00374 const adobe::dictionary_t& parameters, 00375 const FactoryToken& token, 00376 adobe::name_t key_name = key_bind) 00377 { 00378 name_t cell; 00379 00380 get_value(parameters, key_name, cell); 00381 00382 attach_controller_direct(control,parameters,token,cell); 00383 } 00384 00385 /*************************************************************************************************/ 00386 00387 template <typename T, typename FactoryToken> 00388 void attach_view_direct(T& control, 00389 const adobe::dictionary_t& /*parameters*/, 00390 const FactoryToken& token, 00391 adobe::name_t cell) 00392 { 00393 if (cell == name_t()) 00394 return; 00395 00396 sheet_t& layout_sheet(token_layout_sheet(token)); 00397 assemblage_t& assemblage(token_assemblage(token)); 00398 00399 // is the cell in the layout sheet or the Adam sheet? 00400 if (layout_sheet.count_interface(cell) != 0) 00401 attach_view(assemblage, cell, control, layout_sheet); 00402 else 00403 attach_view(assemblage, cell, control, token_property_model(token)); 00404 } 00405 00406 /*************************************************************************************************/ 00407 00408 template <typename T, typename FactoryToken> 00409 void attach_view(T& control, 00410 const adobe::dictionary_t& parameters, 00411 const FactoryToken& token, 00412 adobe::name_t key_name = key_bind) 00413 { 00414 name_t cell; 00415 00416 get_value(parameters, key_name, cell); 00417 00418 attach_view_direct(control, parameters, token, cell); 00419 } 00420 00421 /*************************************************************************************************/ 00422 00423 template <typename T, typename FactoryToken> 00424 void attach_view_and_controller_direct(T& control, 00425 const adobe::dictionary_t& parameters, 00426 const FactoryToken& token, 00427 adobe::name_t widget_cell = name_t(), 00428 adobe::name_t view_cell = name_t(), 00429 adobe::name_t controller_cell = name_t()) 00430 { 00431 if (widget_cell == name_t() && view_cell== name_t() && controller_cell== name_t()) 00432 return; 00433 00434 sheet_t& layout_sheet(token_layout_sheet(token)); 00435 sheet_t& property_model(token_property_model(token)); 00436 00437 if (widget_cell != name_t()) 00438 { 00439 controller_cell = widget_cell; 00440 view_cell = widget_cell; 00441 } 00442 00443 if (controller_cell != name_t()) 00444 { 00445 // is the cell in the layout sheet or the Adam sheet? 00446 00447 if (layout_sheet.count_interface(controller_cell) != 0) 00448 couple_controller_to_cell(control, controller_cell, layout_sheet, 00449 token, parameters); 00450 else 00451 couple_controller_to_cell(control, controller_cell, property_model, 00452 token, parameters); 00453 } 00454 00455 if (view_cell != name_t()) 00456 { 00457 // is the cell in the layout sheet or the Adam sheet? 00458 00459 assemblage_t& assemblage(token_assemblage(token)); 00460 00461 if (layout_sheet.count_interface(view_cell) != 0) 00462 attach_view(assemblage, view_cell, control, layout_sheet); 00463 else 00464 attach_view(assemblage, view_cell, control, token_property_model(token)); 00465 } 00466 } 00467 00468 /*************************************************************************************************/ 00469 00470 template <typename T, typename FactoryToken> 00471 void attach_view_and_controller(T& control, 00472 const dictionary_t& parameters, 00473 const FactoryToken& token, 00474 adobe::name_t bind_cell_name = key_bind, 00475 adobe::name_t bind_view_cell_name = key_bind_view, 00476 adobe::name_t bind_controller_cell_name = key_bind_controller) 00477 { 00478 if (parameters.count(bind_cell_name) == 0 && 00479 parameters.count(bind_view_cell_name) == 0 && 00480 parameters.count(bind_controller_cell_name) == 0) 00481 return; 00482 00483 name_t controller_cell; 00484 name_t view_cell; 00485 name_t widget_cell; 00486 00487 get_value(parameters, bind_controller_cell_name, controller_cell); 00488 get_value(parameters, bind_view_cell_name, view_cell); 00489 get_value(parameters, bind_cell_name, widget_cell); 00490 00491 attach_view_and_controller_direct(control, parameters, token, widget_cell, view_cell, controller_cell); 00492 } 00493 00494 /*************************************************************************************************/ 00495 00496 } // namespace adobe 00497 00498 /*************************************************************************************************/ 00499 00500 #endif 00501 00502 /*************************************************************************************************/ |