Code

replace single toggle button with less confusing pick-alpha and set-alpha options
[inkscape.git] / src / util / ucompose.hpp
1 /* Defines String::ucompose(fmt, arg...) for easy, i18n-friendly
2  * composition of strings with Gtkmm >= 1.3.* (see www.gtkmm.org).
3  * Uses Glib::ustring instead of std::string which doesn't work with
4  * Gtkmm due to character encoding troubles with stringstreams.
5  *
6  * Version 1.0.4.
7  *
8  * Copyright (c) 2002, 03, 04 Ole Laursen <olau@hardworking.dk>.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23  * USA.
24  */
26 //
27 // Basic usage is like
28 //
29 //   String::ucompose("This is a %1x%2 matrix.", rows, cols);
30 //
31 // See http://www.cs.aau.dk/~olau/compose/ or the included
32 // README.compose for more details.
33 //
35 #ifndef STRING_UCOMPOSE_HPP
36 #define STRING_UCOMPOSE_HPP
38 #include <glibmm/ustring.h>
39 #include <glibmm/convert.h>
41 #include <sstream>
42 #include <string>
43 #include <list>
44 #include <map>                  // for multimap
46 namespace UStringPrivate
47 {
48   // the actual composition class - using String::ucompose is cleaner, so we
49   // hide it here
50   class Composition
51   {
52   public:
53     // initialize and prepare format string on the form "text %1 text %2 etc."
54     explicit Composition(std::string fmt);
56     // supply an replacement argument starting from %1
57     template <typename T>
58     Composition &arg(const T &obj);
60     // compose and return string
61     Glib::ustring str() const;
63   private:
64   
65     //This is standard, not GCC-specific like wostringstream
66     std::basic_ostringstream<wchar_t> os;
67     
68     int arg_no;
70     // we store the output as a list - when the output string is requested, the
71     // list is concatenated to a string; this way we can keep iterators into
72     // the list instead of into a string where they're possibly invalidated
73     // when inserting a specification string
74     typedef std::list<std::string> output_list;
75     output_list output;
77     // the initial parse of the format string fills in the specification map
78     // with positions for each of the various %?s
79     typedef std::multimap<int, output_list::iterator> specification_map;
80     specification_map specs;
82     template <typename T>
83     std::string stringify(T obj);
84   };
86   // helper for converting spec string numbers
87   inline int char_to_int(char c)
88   {
89     switch (c) {
90     case '0': return 0;
91     case '1': return 1;
92     case '2': return 2;
93     case '3': return 3;
94     case '4': return 4;
95     case '5': return 5;
96     case '6': return 6;
97     case '7': return 7;
98     case '8': return 8;
99     case '9': return 9;
100     default: return -1000;
101     }
102   }
104   inline bool is_number(int n)
105   {
106     switch (n) {
107     case '0':
108     case '1':
109     case '2':
110     case '3':
111     case '4':
112     case '5':
113     case '6':
114     case '7':
115     case '8':
116     case '9':
117       return true;
118     
119     default:
120       return false;
121     }
122   }
124   template <typename T>
125   inline std::string Composition::stringify(T obj)
126   {
127     os << obj;
129     std::wstring str = os.str();
130     
131     return Glib::convert(std::string(reinterpret_cast<const char *>(str.data()),
132                                      str.size() * sizeof(wchar_t)),
133                          "UTF-8", "WCHAR_T");
134   }
136   // specialisations for the common string types
137   template <>
138   inline std::string
139   Composition::stringify<std::string>(std::string obj)
140   {
141     return obj;
142   }
143   
144   template <>
145   inline std::string
146   Composition::stringify<Glib::ustring>(Glib::ustring obj)
147   {
148     return obj;
149   }
150   
151   template <>
152   inline std::string
153   Composition::stringify<const char *>(const char *obj)
154   {
155     return obj;
156   }
157   
158   // implementation of class Composition
159   template <typename T>
160   inline Composition &Composition::arg(const T &obj)
161   {
162     Glib::ustring rep = stringify(obj);
163     
164     if (!rep.empty()) {         // manipulators don't produce output
165       for (specification_map::const_iterator i = specs.lower_bound(arg_no),
166              end = specs.upper_bound(arg_no); i != end; ++i) {
167         output_list::iterator pos = i->second;
168         ++pos;
169       
170         output.insert(pos, rep);
171       }
172     
173       os.str(std::wstring());
174       //os.clear();
175       ++arg_no;
176     }
177   
178     return *this;
179   }
181   inline Composition::Composition(std::string fmt)
182     : arg_no(1)
183   {
184 #if __GNUC__ >= 3
185     os.imbue(std::locale("")); // use the user's locale for the stream
186 #endif
187     std::string::size_type b = 0, i = 0;
188   
189     // fill in output with the strings between the %1 %2 %3 etc. and
190     // fill in specs with the positions
191     while (i < fmt.length()) {
192       if (fmt[i] == '%' && i + 1 < fmt.length()) {
193         if (fmt[i + 1] == '%') { // catch %%
194           fmt.replace(i, 2, "%");
195           ++i;
196         }
197         else if (is_number(fmt[i + 1])) { // aha! a spec!
198           // save string
199           output.push_back(fmt.substr(b, i - b));
200         
201           int n = 1;            // number of digits
202           int spec_no = 0;
204           do {
205             spec_no += char_to_int(fmt[i + n]);
206             spec_no *= 10;
207             ++n;
208           } while (i + n < fmt.length() && is_number(fmt[i + n]));
210           spec_no /= 10;
211           output_list::iterator pos = output.end();
212           --pos;                // safe since we have just inserted a string
213         
214           specs.insert(specification_map::value_type(spec_no, pos));
215         
216           // jump over spec string
217           i += n;
218           b = i;
219         }
220         else
221           ++i;
222       }
223       else
224         ++i;
225     }
226   
227     if (i - b > 0)              // add the rest of the string
228       output.push_back(fmt.substr(b, i - b));
229   }
231   inline Glib::ustring Composition::str() const
232   {
233     // assemble string
234     std::string str;
235   
236     for (output_list::const_iterator i = output.begin(), end = output.end();
237          i != end; ++i)
238       str += *i;
239   
240     return str;
241   }
245 namespace String 
247   // a series of functions which accept a format string on the form "text %1
248   // more %2 less %3" and a number of templated parameters and spits out the
249   // composited string
250   template <typename T1>
251   inline Glib::ustring ucompose(const Glib::ustring &fmt, const T1 &o1)
252   {
253     UStringPrivate::Composition c(fmt);
254     c.arg(o1);
255     return c.str();
256   }
258   template <typename T1, typename T2>
259   inline Glib::ustring ucompose(const Glib::ustring &fmt,
260                                 const T1 &o1, const T2 &o2)
261   {
262     UStringPrivate::Composition c(fmt);
263     c.arg(o1).arg(o2);
264     return c.str();
265   }
267   template <typename T1, typename T2, typename T3>
268   inline Glib::ustring ucompose(const Glib::ustring &fmt,
269                                 const T1 &o1, const T2 &o2, const T3 &o3)
270   {
271     UStringPrivate::Composition c(fmt);
272     c.arg(o1).arg(o2).arg(o3);
273     return c.str();
274   }
276   template <typename T1, typename T2, typename T3, typename T4>
277   inline Glib::ustring ucompose(const Glib::ustring &fmt,
278                                 const T1 &o1, const T2 &o2, const T3 &o3,
279                                 const T4 &o4)
280   {
281     UStringPrivate::Composition c(fmt);
282     c.arg(o1).arg(o2).arg(o3).arg(o4);
283     return c.str();
284   }
286   template <typename T1, typename T2, typename T3, typename T4, typename T5>
287   inline Glib::ustring ucompose(const Glib::ustring &fmt,
288                                 const T1 &o1, const T2 &o2, const T3 &o3,
289                                 const T4 &o4, const T5 &o5)
290   {
291     UStringPrivate::Composition c(fmt);
292     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
293     return c.str();
294   }
296   template <typename T1, typename T2, typename T3, typename T4, typename T5,
297             typename T6>
298   inline Glib::ustring ucompose(const Glib::ustring &fmt,
299                                 const T1 &o1, const T2 &o2, const T3 &o3,
300                                 const T4 &o4, const T5 &o5, const T6 &o6)
301   {
302     UStringPrivate::Composition c(fmt);
303     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
304     return c.str();
305   }
307   template <typename T1, typename T2, typename T3, typename T4, typename T5,
308             typename T6, typename T7>
309   inline Glib::ustring ucompose(const Glib::ustring &fmt,
310                                 const T1 &o1, const T2 &o2, const T3 &o3,
311                                 const T4 &o4, const T5 &o5, const T6 &o6,
312                                 const T7 &o7)
313   {
314     UStringPrivate::Composition c(fmt);
315     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
316     return c.str();
317   }
319   template <typename T1, typename T2, typename T3, typename T4, typename T5,
320             typename T6, typename T7, typename T8>
321   inline Glib::ustring ucompose(const Glib::ustring &fmt,
322                                 const T1 &o1, const T2 &o2, const T3 &o3,
323                                 const T4 &o4, const T5 &o5, const T6 &o6,
324                                 const T7 &o7, const T8 &o8)
325   {
326     UStringPrivate::Composition c(fmt);
327     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
328     return c.str();
329   }
331   template <typename T1, typename T2, typename T3, typename T4, typename T5,
332             typename T6, typename T7, typename T8, typename T9>
333   inline Glib::ustring ucompose(const Glib::ustring &fmt,
334                                 const T1 &o1, const T2 &o2, const T3 &o3,
335                                 const T4 &o4, const T5 &o5, const T6 &o6,
336                                 const T7 &o7, const T8 &o8, const T9 &o9)
337   {
338     UStringPrivate::Composition c(fmt);
339     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
340     return c.str();
341   }
343   template <typename T1, typename T2, typename T3, typename T4, typename T5,
344             typename T6, typename T7, typename T8, typename T9, typename T10>
345   inline Glib::ustring ucompose(const Glib::ustring &fmt,
346                                 const T1 &o1, const T2 &o2, const T3 &o3,
347                                 const T4 &o4, const T5 &o5, const T6 &o6,
348                                 const T7 &o7, const T8 &o8, const T9 &o9,
349                                 const T10 &o10)
350   {
351     UStringPrivate::Composition c(fmt);
352     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
353       .arg(o10);
354     return c.str();
355   }
356   
357   template <typename T1, typename T2, typename T3, typename T4, typename T5,
358             typename T6, typename T7, typename T8, typename T9, typename T10,
359             typename T11>
360   inline Glib::ustring ucompose(const Glib::ustring &fmt,
361                                 const T1 &o1, const T2 &o2, const T3 &o3,
362                                 const T4 &o4, const T5 &o5, const T6 &o6,
363                                 const T7 &o7, const T8 &o8, const T9 &o9,
364                                 const T10 &o10, const T11 &o11)
365   {
366     UStringPrivate::Composition c(fmt);
367     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
368       .arg(o10).arg(o11);
369     return c.str();
370   }
372   template <typename T1, typename T2, typename T3, typename T4, typename T5,
373             typename T6, typename T7, typename T8, typename T9, typename T10,
374             typename T11, typename T12>
375   inline Glib::ustring ucompose(const Glib::ustring &fmt,
376                                 const T1 &o1, const T2 &o2, const T3 &o3,
377                                 const T4 &o4, const T5 &o5, const T6 &o6,
378                                 const T7 &o7, const T8 &o8, const T9 &o9,
379                                 const T10 &o10, const T11 &o11, const T12 &o12)
380   {
381     UStringPrivate::Composition c(fmt);
382     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
383       .arg(o10).arg(o11).arg(o12);
384     return c.str();
385   }
387   template <typename T1, typename T2, typename T3, typename T4, typename T5,
388             typename T6, typename T7, typename T8, typename T9, typename T10,
389             typename T11, typename T12, typename T13>
390   inline Glib::ustring ucompose(const Glib::ustring &fmt,
391                                 const T1 &o1, const T2 &o2, const T3 &o3,
392                                 const T4 &o4, const T5 &o5, const T6 &o6,
393                                 const T7 &o7, const T8 &o8, const T9 &o9,
394                                 const T10 &o10, const T11 &o11, const T12 &o12,
395                                 const T13 &o13)
396   {
397     UStringPrivate::Composition c(fmt);
398     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
399       .arg(o10).arg(o11).arg(o12).arg(o13);
400     return c.str();
401   }
403   template <typename T1, typename T2, typename T3, typename T4, typename T5,
404             typename T6, typename T7, typename T8, typename T9, typename T10,
405             typename T11, typename T12, typename T13, typename T14>
406   inline Glib::ustring ucompose(const Glib::ustring &fmt,
407                                 const T1 &o1, const T2 &o2, const T3 &o3,
408                                 const T4 &o4, const T5 &o5, const T6 &o6,
409                                 const T7 &o7, const T8 &o8, const T9 &o9,
410                                 const T10 &o10, const T11 &o11, const T12 &o12,
411                                 const T13 &o13, const T14 &o14)
412   {
413     UStringPrivate::Composition c(fmt);
414     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
415       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
416     return c.str();
417   }
419   template <typename T1, typename T2, typename T3, typename T4, typename T5,
420             typename T6, typename T7, typename T8, typename T9, typename T10,
421             typename T11, typename T12, typename T13, typename T14,
422             typename T15>
423   inline Glib::ustring ucompose(const Glib::ustring &fmt,
424                                 const T1 &o1, const T2 &o2, const T3 &o3,
425                                 const T4 &o4, const T5 &o5, const T6 &o6,
426                                 const T7 &o7, const T8 &o8, const T9 &o9,
427                                 const T10 &o10, const T11 &o11, const T12 &o12,
428                                 const T13 &o13, const T14 &o14, const T15 &o15)
429   {
430     UStringPrivate::Composition c(fmt);
431     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
432       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
433     return c.str();
434   }
438 #endif // STRING_UCOMPOSE_HPP