platform_drag_and_drop_data.hpp
Go to the documentation of this file.
00001 /* 00002 Copyright 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_CARBON_DRAG_AND_DROP_PLATFORM_DATA_HPP 00010 #define ADOBE_CARBON_DRAG_AND_DROP_PLATFORM_DATA_HPP 00011 00012 /**************************************************************************************************/ 00013 00014 #include <adobe/config.hpp> 00015 00016 #include <adobe/algorithm/find.hpp> 00017 #include <adobe/future/drag_and_drop_fwd.hpp> 00018 #include <adobe/future/macintosh_events.hpp> 00019 00020 #include <boost/cstdint.hpp> 00021 #include <boost/function.hpp> 00022 #include <boost/next_prior.hpp> 00023 00024 #include <cassert> 00025 #include <functional> 00026 00027 /**************************************************************************************************/ 00028 00029 namespace adobe { 00030 00031 /**************************************************************************************************/ 00032 00033 namespace implementation { 00034 00035 /**************************************************************************************************/ 00036 00037 typedef std::pair< ::DragItemRef, ::UInt16 > drag_flavor_descriptor_t; 00038 typedef std::pair<drag_flavor_descriptor_t, boost::uint32_t> drag_flavor_uber_descriptor_t; 00039 00040 template <typename InputIterator> 00041 drag_flavor_uber_descriptor_t find_drag_flavor(::DragRef the_drag, 00042 InputIterator first, 00043 InputIterator last) 00044 { 00045 ::UInt16 count(0); 00046 drag_flavor_descriptor_t result(0, 0); 00047 00048 ::CountDragItems(the_drag, &count); 00049 00050 for (::UInt16 cur_item_index(1); cur_item_index <= count; ++cur_item_index) 00051 { 00052 ::DragItemRef drag_item(0); 00053 00054 if (::GetDragItemReferenceNumber(the_drag, cur_item_index, &drag_item) != noErr) 00055 continue; 00056 00057 ::UInt16 flavor_count(0); 00058 00059 if (::CountDragItemFlavors(the_drag, drag_item, &flavor_count) != noErr) 00060 continue; 00061 00062 for (::UInt16 cur_flavor(1); cur_flavor <= flavor_count; ++cur_flavor) 00063 { 00064 ::FlavorType flavor_type(0); 00065 00066 if (::GetFlavorType(the_drag, drag_item, cur_flavor, &flavor_type) == noErr) 00067 { 00068 InputIterator found(std::find(first, last, flavor_type)); 00069 00070 if (found != last) 00071 { 00072 result.first = drag_item; 00073 result.second = cur_flavor; 00074 00075 return drag_flavor_uber_descriptor_t(result, *found); 00076 } 00077 } 00078 } 00079 } 00080 00081 return drag_flavor_uber_descriptor_t(result, flavor_invalid); 00082 } 00083 00084 /**************************************************************************************************/ 00085 00086 template <typename InputIterator> 00087 drag_flavor_uber_descriptor_t find_drag_flavor(::EventRef event, 00088 InputIterator first, 00089 InputIterator last) 00090 { 00091 ::DragRef the_drag(0); 00092 00093 adobe::get_event_parameter<kEventParamDragRef>(event, the_drag); 00094 00095 return find_drag_flavor(the_drag, first, last); 00096 } 00097 00098 /**************************************************************************************************/ 00099 00100 inline drag_flavor_uber_descriptor_t find_drag_flavor(::DragRef the_drag, boost::uint32_t flavor) 00101 { 00102 boost::uint32_t* first(&flavor); 00103 00104 return find_drag_flavor(the_drag, first, boost::next(first)); 00105 } 00106 00107 /**************************************************************************************************/ 00108 00109 inline drag_flavor_uber_descriptor_t find_drag_flavor(::EventRef event, boost::uint32_t flavor) 00110 { 00111 boost::uint32_t* first(&flavor); 00112 00113 return find_drag_flavor(event, first, boost::next(first)); 00114 } 00115 00116 /**************************************************************************************************/ 00117 00118 any_regular_t flavor_extract_character_sequence(const dictionary_t& drag_parameters); 00119 00120 /**************************************************************************************************/ 00121 00125 std::string file_url_to_path(const std::string& src); 00126 00127 /**************************************************************************************************/ 00128 00129 template <typename T> 00130 struct converter_echo 00131 { 00132 typedef T source_type; 00133 typedef T dest_type; 00134 00135 inline T convert(const T& x) const 00136 { return x; } 00137 }; 00138 00139 /**************************************************************************************************/ 00140 00141 } // namespace implementation 00142 00143 /**************************************************************************************************/ 00144 00145 extern aggregate_name_t key_drag_ref; 00146 extern aggregate_name_t key_drag_item; 00147 extern aggregate_name_t key_flavor; 00148 00149 /**************************************************************************************************/ 00150 00151 template <typename SourceType, typename TargetType> 00152 class drag_and_drop_handler_platform_data 00153 { 00154 public: 00155 typedef SourceType source_type; 00156 typedef TargetType target_type; 00157 typedef boost::function<void (const target_type&)> client_callback_proc_t; 00158 00159 drag_and_drop_handler_platform_data() : 00160 chosen_flavor_m(flavor_invalid) 00161 { 00162 event_handler_m.monitor_proc_m = 00163 boost::bind(&drag_and_drop_handler_platform_data<source_type, target_type>::handle_event, 00164 boost::ref(*this), _1, _2); 00165 } 00166 00167 template <typename InputIterator> 00168 drag_and_drop_handler_platform_data(InputIterator first, InputIterator last) : 00169 flavor_set_m(first, last), 00170 chosen_flavor_m(flavor_invalid) 00171 { 00172 event_handler_m.monitor_proc_m = 00173 boost::bind(&drag_and_drop_handler_platform_data<source_type, target_type>::handle_event, 00174 boost::ref(*this), _1, _2); 00175 } 00176 00177 void init() 00178 { 00179 event_handler_m.insert(kEventClassControl, kEventControlDragEnter); 00180 event_handler_m.insert(kEventClassControl, kEventControlDragWithin); 00181 event_handler_m.insert(kEventClassControl, kEventControlDragLeave); 00182 event_handler_m.insert(kEventClassControl, kEventControlDragReceive); 00183 00184 // REVISIT (fbrereto) : adobe::once this! 00185 // set up platform-specific flavor converters 00186 if (is_dnd_converter_registered<std::string>(flavor_file_url) == false) 00187 { 00188 register_dnd_extractor<std::string>(flavor_file_url, 00189 &implementation::flavor_extract_character_sequence); 00190 register_dnd_extractor<std::string>(flavor_text, 00191 &implementation::flavor_extract_character_sequence); 00192 00193 register_dnd_converter<std::string>(flavor_file_url, 00194 make_function_as_poly_drag_and_drop_converter 00195 (&implementation::file_url_to_path)); 00196 register_dnd_converter<std::string>(flavor_text, 00197 poly_drag_and_drop_converter_t 00198 (implementation::converter_echo<std::string>())); 00199 } 00200 } 00201 00202 template <typename Client> 00203 void attach(const Client& control, const client_callback_proc_t& proc) 00204 { 00205 set_callback(proc); 00206 00207 install(control); 00208 } 00209 00210 void detach() 00211 { 00212 event_handler_m.uninstall(); 00213 } 00214 00215 void insert_flavor(boost::uint32_t flavor) 00216 { 00217 if (adobe::find(flavor_set_m, flavor) == flavor_set_m.end()) 00218 flavor_set_m.push_back(flavor); 00219 } 00220 00221 void erase_flavor(boost::uint32_t flavor) 00222 { 00223 flavor_set_m.erase(adobe::find(flavor_set_m, flavor)); 00224 } 00225 00226 void set_callback(const client_callback_proc_t& proc) 00227 { 00228 callback_m = proc; 00229 } 00230 00231 void install(::HIViewRef control) 00232 { 00233 event_handler_m.install(control); 00234 00235 ::SetControlDragTrackingEnabled(control, true); 00236 } 00237 00238 private: 00239 ::OSStatus handle_event(::EventHandlerCallRef next, ::EventRef event); 00240 00241 client_callback_proc_t callback_m; 00242 std::vector<boost::uint32_t> flavor_set_m; 00243 boost::uint32_t chosen_flavor_m; 00244 event_handler_t event_handler_m; 00245 }; 00246 00247 /**************************************************************************************************/ 00248 00249 template <typename SourceType, typename TargetType> 00250 ::OSStatus 00251 drag_and_drop_handler_platform_data<SourceType, TargetType>::handle_event(::EventHandlerCallRef /*next*/, 00252 ::EventRef event) 00253 { 00254 ::UInt32 event_class(::GetEventClass(event)); 00255 ::UInt32 event_kind(::GetEventKind(event)); 00256 00257 assert(event_class == kEventClassControl); 00258 00259 std::vector<boost::uint32_t> flavor_set(flavor_set_m.empty() ? registered_flavor_set() : 00260 flavor_set_m); 00261 00262 if (flavor_set.empty()) 00263 return eventNotHandledErr; // drag and drop is totally out of comission 00264 00265 if (event_kind == kEventControlDragEnter) 00266 { 00267 if (callback_m.empty()) 00268 return eventNotHandledErr; 00269 00270 implementation::drag_flavor_uber_descriptor_t flavor = 00271 implementation::find_drag_flavor(event, flavor_set.begin(), flavor_set.end()); 00272 00273 if (flavor.second != flavor_invalid && callback_m.empty() == false) 00274 { 00275 adobe::set_event_parameter<kEventParamControlWouldAcceptDrop>(event, true); 00276 00277 chosen_flavor_m = flavor.second; 00278 } 00279 } 00280 else if (event_kind == kEventControlDragWithin) 00281 { 00282 // REVISIT (fbrereto) : Fix me up 00283 ::SetThemeCursor(kThemeCopyArrowCursor); 00284 } 00285 else if (event_kind == kEventControlDragLeave) 00286 { 00287 // REVISIT (fbrereto) : Fix me up 00288 ::SetThemeCursor(kThemeArrowCursor); 00289 } 00290 else if (event_kind == kEventControlDragReceive) 00291 { 00292 ::DragRef the_drag(0); 00293 00294 adobe::get_event_parameter<kEventParamDragRef>(event, the_drag); 00295 00296 implementation::drag_flavor_uber_descriptor_t flavor = 00297 implementation::find_drag_flavor(the_drag, chosen_flavor_m); 00298 00299 assert(flavor.second == chosen_flavor_m); 00300 assert(callback_m.empty() == false); 00301 00302 dictionary_t drag_parameters; 00303 00304 drag_parameters.insert(std::make_pair(key_drag_ref, the_drag)); 00305 drag_parameters.insert(std::make_pair(key_drag_item, flavor.first.first)); 00306 drag_parameters.insert(std::make_pair(key_flavor, chosen_flavor_m)); 00307 00308 source_type flavor_data(invoke_dnd_extractor<source_type>(chosen_flavor_m, 00309 drag_parameters)); 00310 00311 target_type converted_result = 00312 invoke_dnd_converter<target_type>(chosen_flavor_m, flavor_data); 00313 00314 callback_m(converted_result); 00315 00316 chosen_flavor_m = flavor_invalid; 00317 } 00318 else 00319 { 00320 throw std::runtime_error("Bad drag and drop event."); 00321 } 00322 00323 return noErr; 00324 } 00325 00326 /**************************************************************************************************/ 00327 00328 } // namespace adobe 00329 00330 /**************************************************************************************************/ 00331 00332 // ADOBE_CARBON_DRAG_AND_DROP_HPP 00333 #endif 00334 00335 /**************************************************************************************************/ |