Module MultiDirDialog
[hide private]
[frames] | no frames]

Source Code for Module MultiDirDialog

  1  # --------------------------------------------------------------------------------- # 
  2  # MULTIDIRDIALOG wxPython IMPLEMENTATION 
  3  # 
  4  # Andrea Gavana, @ 07 October 2008 
  5  # Latest Revision: 07 October 2008, 22.00 GMT 
  6  # 
  7  # 
  8  # TODO List 
  9  # 
 10  # 1) Implement an meaningful action for the "Make New Folder" button, but this 
 11  #    requires a strong integration with Explorer, at least on Windows; 
 12  # 
 13  # 2) Be more user-friendly with special folders as the Desktop, My Documents etc... 
 14  # 
 15  # 
 16  # For all kind of problems, requests of enhancements and bug reports, please 
 17  # write to me at: 
 18  # 
 19  # andrea.gavana@gmail.com 
 20  # gavana@kpo.kz 
 21  # 
 22  # Or, obviously, to the wxPython mailing list!!! 
 23  # 
 24  # 
 25  # End Of Comments 
 26  # --------------------------------------------------------------------------------- # 
 27   
 28  """ 
 29  Description 
 30  =========== 
 31   
 32  This class represents a possible replacement for wx.DirDialog, with the additional 
 33  ability of selecting multiple folders at once. It may be useful when you wish to 
 34  present to the user a directory browser which allows multiple folder selections. 
 35  MultiDirDialog sports the following features: 
 36   
 37  * Ability to select a single or mutliple folders, depending on the style passed; 
 38  * More colourful and eye-catching buttons; 
 39  * Good old Python code :-D . 
 40   
 41  And a lot more. Check the demo for an almost complete review of the functionalities. 
 42   
 43   
 44  Supported Platforms 
 45  =================== 
 46   
 47  MultiDirDialog has been tested on the following platforms: 
 48    * Windows (Windows XP). 
 49   
 50   
 51  Latest Revision: Andrea Gavana @ 07 October 2008, 22.00 GMT 
 52  Version 0.1 
 53   
 54  """ 
 55   
 56  import os 
 57  import wx 
 58  import wx.lib.buttons as buttons 
 59   
 60  from wx.lib.embeddedimage import PyEmbeddedImage 
 61   
 62  DD_MULTIPLE = 1024 
 63   
 64  _ = wx.GetTranslation 
 65   
 66  _cancel = PyEmbeddedImage( 
 67      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAA1dJ" 
 68      "REFUOI11019oEwccB/Dv3eUuyZ2XpfljsmJ7JY01KZYWty6bdMwnp1X34JNS5sPAsmYruOnL" 
 69      "3kTGcPg6Bdkexqql4EPdBuKbVG0xLmpoWjbW0D+S1Jg24RJzuSR3l58PtpsI/l5/fB5+3x9f" 
 70      "AEDc7VauhMP3prq7q9+1t5/AW+aiLB+ZDocrU6HQk4tAFAC4s8Gg0uVyXTsZiw190Nsr6JnM" 
 71      "kZAkrd6rVtOv4wuyfLS/rW3y6Oioq2tgILiRyXy4v1yexU979yaKIyNEiQRRsUjG2Bjddrtr" 
 72      "532+k9v4B1kevu33l+vnzhFtbBAtL9OLS5douq9v0eZ1OPo8Xi8gSUClAls8jk+qVad148bP" 
 73      "33s8TcY0K32mOTV07JhsP3UKKJUAy8IORYF3584erodopaGqh7qzWYEJBgGGgW3fPrQ/eyY0" 
 74      "5uePewzjxIGDB0U5HgcsC1BV0MOH+GtiojF/9+433P1qNd1pGCvs5uawUijwbDAIWBZsAwPw" 
 75      "5nJsRyBgc8fjYLZwK5lE6uZN88Hc3LdfmeYVDgDu12oLXUSrxvPnw8r6uo3z+cAQwRGJQOzv" 
 76      "B0sEKhZhJRJI3rplJlKpM+OWdRkAuO2gZnQ93UO02CgUjr9bLHKCzweGZcGYJqhchp5I4NGd" 
 77      "O9bjpaUvxol+2Xa211/FAKolSa0XySSq+TzYYBAAYGkaUKnA5LgWA6hvmP//PKgokx9tbspq" 
 78      "Pg8NgL61c0gSJL8f73R04O9KRV9Mp0+PtlrX/zvhgigO749GJ4dKJVc9l0MTgAVAZBg4BQEk" 
 79      "SeCcTjAAOhWF5/3+w7FsdvkPogXuR7f7s/d6eycPqKqrubKC+hZ28DxydnurzHFWwG5niefB" 
 80      "CALYVgu7wmGe2toOfby2lrVFIpFrn9brcmNpCU0ALIAdooiMw9FI1etfkmGUbaY5EXY4JIth" 
 81      "YAIw1tcxODgoEcddZeua9rQqCGB5HgwA0e3GmsdjPtH1s1/Xar+ON5vTi6p6+qmm6U5JAksE" 
 82      "VhBQbzahl0p57n1Nm9kQxVhXINAucxzSLpeZLBTOxHX98nbAfxItxMrlVV4UD+/q7OTJ58Pc" 
 83      "7Ow/uVTq81c1FYTo76HQo5k9expXnc6xt9X5OsuOPIhGtZndu//9DYgBwEt1gHq0YITgmAAA" 
 84      "AABJRU5ErkJggg==") 
 85   
 86  #---------------------------------------------------------------------- 
 87  _ok = PyEmbeddedImage( 
 88      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAjdJ" 
 89      "REFUOI2tksFLk3Ecxp+97975vmuve1dWuiUTNIy1JlsLpkZG0aXLbv0B0aVDUMfVQTp0jJpF" 
 90      "EHl5LxUZgZcuQjAID4KUyWwyEU3d9m7O5d733dze97dfB1siJSn1nJ/P5+ELX+Afwx6YuAMB" 
 91      "AVgwjcaBBdIovP2eyKMLPYNdM+7kNKZA9i3gR+ENCeF4Hx+8VigVBgrKWrXKGp/2JeCfwhsW" 
 92      "Q/HTQiCaVTOYUiZtDuoMQqefrc1S9+uOEGNSRzqd+4j72/c1l4OOQNwn+aOFWg5TdBJEIKbH" 
 93      "dI9zHLMt6H3lHrjScfU5x3DSmOXNrVUUxwFQ6S3vDdh9cZ/zTHSz8R0pMguGMKaRMuX5peQ9" 
 94      "ZULPW8+PnB286L78zH/M76/DwCYtjSTefaAOQZjpEDofn5J8UR0qViqLoCpLql+IXFzS72IC" 
 95      "eQCwssR2NFfOtNXsFZx09SLkDnfSlsYTluUy7a3Hz6mWMrLGKswiJaV0WS6Uyr9gAGC7It0L" 
 96      "WrWYm99K9VdcqugSD8Pd6nG6RNeJCq9ZstwqNL1CMl/z8npdiRkPd2AAYJcTy41FcSVZt+lK" 
 97      "na9FaLspCg4ehDew3qJgs6qStUxerhItlr+h74KB5iPNgVZuGkm6QpQWmy3i8AoiY7dA1XTy" 
 98      "LZuVGYHGZi8t/gbvCABgDFS7vpVEgSgS29bv5CR7XtmQjxxyxt77En+Edwt+Svpua3MbRT5T" 
 99      "a9QXPGL7gxc9L/eE98wwHWaG6JD1783/kB9qTvueLt8LjwAAAABJRU5ErkJggg==") 
100   
101  #---------------------------------------------------------------------- 
102  _cdrom = PyEmbeddedImage( 
103      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAArRJ" 
104      "REFUOI11kc9rm3Ucx1/f5/eTLV2aJ2vqVseGWzeYDAbCCq2THQqiuB3mP+DBQ3ss3rysILLb" 
105      "2I5FhKHkNFmFHkrFoVDQDautI02ZWqGJ7WzWEkzy/M73u1NKbNj79Dl8Xi8+P+BQhoeHj09N" 
106      "Td1aWlr6s1qtNjY3N/dLpdIvExMTHwPG4f7/ZWRk5M35+fmnqidSSqWUUlEUqdnZ2W+B3Kv4" 
107      "wbm5uaeNRkO1220VRZEKw1D5vq/CMDwQTk9PfwVoffTk5ORMpVJR5XJZ1Wo1FYahCoJAtVot" 
108      "laapSpJEBUGgNjY2VLFYvNblDkzj4+PvJ0kCgJSSvb09tv7eiuv/1tMgDGg2m+zu7mKaJmNj" 
109      "Yx90uYOj5PP5k2ma4jgOuqbT/K/JvYd3n4+eOu9cH7s+lMiE/f19hBAUCoUzfYIkSYJ8Po+u" 
110      "69i2TZIk3Hz3w1MqUtT36iRpgu/7ZDIZfN+P+1ZYXV39bWBgANd1OZo9ilfwuDB0gYunL+K4" 
111      "Dq1WCyEEcRyztra22idYWFj4srxW9j3PQ0pJo9EADWzHxvM8juWO4doZln9c3llfX/+my+nd" 
112      "IgzDrUpceeftS1ffcHSX+os6Ukosy8I0THJHBnn87Cduf/H5/dZO++s+AcA/V2sfbYa/nmFb" 
113      "QwYamjJACWrbVVY2HvMDiyxXnvzMXyz2HRGw8ifJ+6N/sNi+QzE4jbd9Auu5g3Jh6OxrjGZP" 
114      "4HgUgh6oV2B++tZngxOXr2AbBpZpYGomujIR0kTFOqmQ/P56NVfiQb8gm80640fey9nPLKI4" 
115      "IkKhAKk6CDocHyqQcVyuFK8NlnhgAOnhCag36k6pdJ92u43ruliWhRACgWDmkxl27G2anVam" 
116      "93uih9dv3Lh569y5s5fjuCMNQ6BpIIROp9NB13XQ0R599+j7lZUnd7rQS0kMSYjIJmZ4AAAA" 
117      "AElFTkSuQmCC") 
118   
119  #---------------------------------------------------------------------- 
120  _computer = PyEmbeddedImage( 
121      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAshJ" 
122      "REFUOI1dk91PXGUQxn/ve979YkHXmhZ325oUa9Wlxg9q8caoCRde9Hb/Bv4KQ8J/AXdceFF6" 
123      "YYJXNCYWE0xITAxt1cjXKpiYsnQpH3v2sOfMTC8WAZ2rmWSeZ56ZJ+MAzKwEXIHEQ5ELYedp" 
124      "QpKcV8Vise2cOwwAnU63sdFsTx0cnpiJoipkqkiaIaa0Wh2etQ4tyxRVo1xy0eefXf0G+DoA" 
125      "ZJlea/7VGRksF1B1iICIQwUyEb79boMfl/8khDy4wLVamdF3X33LzHwAUJQ47k82U1QVkX7e" 
126      "3u+y2XyB9w7THkZGlnkUNYDw705HHeXgqIdZH6wqmCq/r7XZPzBCroRKSvDKrZsVIt/HnREc" 
127      "x8bRcYaZoCKICCIZf2wcY65IFAIQeOdWhfdH30D1PwSeuOvYfS5wqkBEiOMeu3t6Oj2jXC4x" 
128      "+l6NblfO7Al9OMSJp9V2YJwe0XhxIPSyHFEAH2Vcvz5AL4vY2z85RV1YodM1dp8bDodI34nj" 
129      "Y4+LSkQuUCwYUcjz9z8ppYLiLipQlLiT0NpLCCEHOFQDIuCDxzRgTtnd6zt1+RL4KLqgQDP9" 
130      "6oscI28mmPVwPiKKgoUw4CLvyLLURFKX9nqc9E4oBCUfsnMbvfff3/lgoHK50vLLPy3zbLcV" 
131      "jdy48eHdjz75slAouidPnj7+7denj1wUpXc+HrPq1ZqrDlcfOec0AFQqlZ8bjcYvW1tbgyJy" 
132      "d3x8/F6pOHBlsPyKS9MeWZq+liS9oZWVlYcP7j/4YWJiYn92djY9e4xGoxEBQ8Db09PTC5ub" 
133      "m7a+vmZLS0u2uLhoq6urtr29bXNzc4+HhoY+BS6NjY3lgLNjMj8/Hy0sLBTb7fbtarV6r16v" 
134      "387n86+LiHfOHTabzfW1tbWHuVxueXh4uDMzM5M55+yM4GJMTU35OI7LOzs7AyLiarVaUq/X" 
135      "O5OTk+n/e18CKWqFGqiV9Q4AAAAASUVORK5CYII=") 
136   
137  #---------------------------------------------------------------------- 
138  _folder_close = PyEmbeddedImage( 
139      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAcBJ" 
140      "REFUOI2Nk0FrE1EQx3+zL7vbmFKRQkE/gyfpISL4WYJHsQfPvXkQe6go+AnEi6dcBBEkhYgS" 
141      "oQfFeqo0VJRobaspm2R339sdD9u0IclC/zAwzLz5zbzhPeFUnU5HuYDq9brMBB+/+KQXVavV" 
142      "+jBZWxk79zffl3Z9dO8GQbCAiAAEM4DvvyI21m4SpyCiaK6ogqqiwN2nWzxbu0W1WpuBn00w" 
143      "ih3H/YwkcbgMnFOcU5K0yKdJTLVawzk3H3D8z9GPHKqKy3QGYK0Fiqkm5Y2do77l3ec+mQhD" 
144      "q+eWFgXjzr1ebzgXgBG2u0O+7A/JRYhzCjttqJrTbDb3G43G7blXyEQIlkI+dmNiPK5dqeBE" 
145      "sJoXO7CGdru9VbrEXDzCyyEisPPH8XOgrCwaFgysXl/lwcttLqWjmUd0BnCeh78UYgQQiJxy" 
146      "cpJj8gxcUZdbVw5Q47FYM1REESBTSJ0htYZkVCxChXKAXxGWq4bAnAPiDAbWMPCFEbD7bfew" 
147      "FPD34Hfa3TuKlmth4PsVycWTQYoeDp39EXnpVVh522pvTgPGI4V3Nt7E08lJvXr+ZP3g6+uH" 
148      "ZYB5EsCn+DwhEAHJ9KH/LOgEF+oT+k8AAAAASUVORK5CYII=") 
149   
150  #---------------------------------------------------------------------- 
151  _folder_open = PyEmbeddedImage( 
152      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAvdJ" 
153      "REFUOI1tU01o23UYft7/75ekqXVJWsO6HaZWzDyIih4UCkJBGIroUATxWPEyLx6EDZzz5Dzr" 
154      "xB3FkygoCA7ZR0A3g60zWdutbrZLTNOvJI1pmvyT/8fv4/WQFFzwgZf36zm8HzyEeyEAEAAD" 
155      "gAexM/B6iEsDAwak4eZwzXk48/gTr7w5+04qlUoMkwEgnnnyuekPz372xbGXjr8GAKPp9OSL" 
156      "L796/PQnn57/5Y/lv9q+tp3A8KEHM48BqcT4o888CwA49taJ04vFeqPta22s5Wtz+cL5r77/" 
157      "YW3HdY213Pa1Xd5w+WK+Yr/NremzX17MLZVqrQu5m/MEgM6c+yb70btvzLR6RlmtEInGhKvg" 
158      "lDcb2Nr1jR+yTSbvc6YeGHGOpOMYjZAlInEhm7sm3/7g8+/em319ZqPR061OV5Z3Amq4yhoW" 
159      "eiI1JqYOJZ3JiTFxIMasNEMb0FbHU2OjI6LWaAdyYXHpTk8T1qpN+unmHo4emUT64LhzOCGd" 
160      "iNM/T3VPoWZCsk6Eo8KBUobageev77Q6cnE++2O+2DwVeBCuZ3g8GYfraax4/a9FRP8ZQgDM" 
161      "ISJSQAeKtN/tblabDal3ioW529XVp6fSmZqr+M62j0AzAYAjJKKOQlT2J2FmRIQBQE6n6QWl" 
162      "zXpTAvAvfX3u16MnP85U29r+vNIT9a5BIi4BADEBjEQIsQgBzBBEDCK5sFT5Z+VWZUsCwFpp" 
163      "9cr2bm+27QGtPUZUAnuDFYwBg4jAzIBmrZQlZlHZ5UTY9RwJAI3SQm61VPZk9P54CHCfvA/D" 
164      "VimjtCUCRGiYAKJY2Eg6brEuARD83crq8o1C9KEXpgOC0caQ0YqtNk5oyQGYwm6LwvpK26tc" 
165      "z7ul61ld//MytHdDDgSky7fmsgcPPz/t6Q4TWABA0Nwgv3Z7y/v7t5y/XrikGsWrAO4CsPvz" 
166      "yf1k++7vl+mp2hkVdE2wkV/2y/NXe+uFK/Ba8wDqw8IaePvf4gE58cj7ELEZAKP/o859qd+D" 
167      "fwFu65tDy5tMTAAAAABJRU5ErkJggg==") 
168   
169  #---------------------------------------------------------------------- 
170  _hd = PyEmbeddedImage( 
171      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAxlJ" 
172      "REFUOI11ks1vG1UUxc+b98YzyfM4gxzSpHHttCFRbQto7YQgxRKIRRYIZRepEkQVzYJ/gAUi" 
173      "i/wlSLBhFSEWZMUiQkLCSmUk0o6rNiExcvNRR/Z0xh6P5/OxqFwlfNzVWZz7u0dXh+B/Zn19" 
174      "Pd1qtQpxHBeiKCoKId4aHR39dGdnx7zsY0Oxurq6FIbhZ4yxwgeVcnHuVuaarmvwPB/nL9r4" 
175      "/Y+neHrQ+BLA5mUAHYp8Pr8uSdLXD+7fu/nRh5XktckpKOoIONcwNzeP998r483x8bvKSPKb" 
176      "/f19Z7gnDYUsyz+nUiksLi4ioWqIBcFfBw/R/LOK1nkTCVVDpVJJLpbvfPWfCQzDON/e3v7k" 
177      "9szk9Z7VwUuzA4WnoaXS6LQ7CAYD2C/bODlr3c3O3Pq2Vqt1ryQghKDb7X7XPG9BH5/ExNQN" 
178      "DPo9nJ2+wMxsEfr4JPhYGkEYqrIsb/4rAQBwzp+HUfRF5no6MX1jFlOZmxAihtVuYpSnYDyq" 
179      "QdUm0O323i2Xy99Xq1XzCiCZTPqcp/K247192jxA4DmI4wDPT88xMZXF7NxtPDaeIZfLUdd1" 
180      "39jd3f2RXAYIIcjS0tLHy8vLP42NjUGWZTDGIEkS4jiGruuglIIQAtd1o5OTk3fYZQAhRGia" 
181      "Vi0Wi0/m5+fzhFzhAwBc14VlWbAsi5qmeZ/901AqlazDw8MfSqXSZiKRgOM4sG0bpmmi0+mg" 
182      "3++DUtpWFOWR53m/vT6xtbUl1et1cnR0JDUajTsrKyu/+L4/4nleGIZhw/O8x0EQPLQs69fj" 
183      "4+Mnuq73NjY2PLK2tkYNw6CmaTLP85jv+wnf99O5XO7zKIrMs7OzZ77vdwkhPiHEppSaiqLY" 
184      "09PTjmEYASkUCgnbtqnruiwIAjkMQyWKIkUIoQohZACyEIK+ehEJCCEOY8zmnPey2azHisVi" 
185      "ZBjGq15LkqCURmEY+nEc94UQVAgxLJuQJClkjAWqqvrpdDqo1WohrdfrotVqxbZtR47jRJzz" 
186      "kDEWaJrmqao64Jy7nHNX1/V+JpNxFxYWBnt7e/7FxUUEAH8DenV0NY9j5foAAAAASUVORK5C" 
187      "YII=") 
188   
189  #---------------------------------------------------------------------- 
190  _new = PyEmbeddedImage( 
191      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAqpJ" 
192      "REFUOI1t0c1rXGUUx/Hvc+/czGtmEk1NTCYWY1BERAJVRMW4cCEIunHTnYjgQrduRHDTrX+F" 
193      "u+ZvEF2IRVCRRkpt1VSTmqQ1rzNz733uc855XDSRkfHsz+ec3zmO/6mrVz9vPjHTm52e6c23" 
194      "mq2lmpPFVE/6qrYUcXMON+2y7NP5Zy9/Wxtv/Gx9vXb5ynsfLczPvZnV0kfT+uycq6WdmO/V" 
195      "82GaNtsPucx5NAyqoDYD8B+gc2m53mk13pluZy9DgptK8b5kZ/sPkqzH4xdmiMUeopJU4jKA" 
196      "ZBwYDo4j0cRUiDESo3B8uMfmjV85Hea4GIgmqIRExJoTwGFd1LBgKpgZJp4qP6YoSqIJ0c4A" 
197      "DS5xNjURwfv7Fk28acC5Gi6MsGqIqUA0iIKZYKYuOEsngKOjFZMgXlVIkgBSIOIxOwMsoBIQ" 
198      "FSwGNxFhY2MjqkpQC2jwiB+gUiEqBA1UVYlIhYgSQmBiAwAViaqCaSCGHJGKO+6EnYMf+ObH" 
199      "67zYW2C50aXSB701wAEZ0HzjlbWLVfArKlOgHvTBNO1FwsIBh6OK1aLNQtImRmmdAy2gD3Sf" 
200      "ear/em/+ybWg+0g+4Pt7f7IzOkVmhXovoJmwuXeXraMDsE7jHPBAClwog8yS9ZJQ3qUoCm76" 
201      "Q/J+TqsraDPH0iF3yl2G96B2uvxvBDmL8fAoL6crVVxZEipBNDCo/qYq95HkmMoLeQVVaNKN" 
202      "uPEjeqCd+9C9+VfOonkyNS5al/Yu3J4qOJ3bJamarBw8x5R0bt0oTr4eB7aAzbIIa8lop4hp" 
203      "WSPJ9p+fX71tMf3p59+3Xy1j+kISUh5L+5tvP73+Qf+196+NAwp8d+u37ft+/5evWquLmrSa" 
204      "17uN/vbSpbfylz5Z+bg7eoQsNtIv/daVD9/94tr52/8BSS2agPSymFoAAAAASUVORK5CYII=") 
205   
206  #---------------------------------------------------------------------- 
207  _removable = PyEmbeddedImage( 
208      "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAldJ" 
209      "REFUOI2lkbFOXFcQhr+Zc+7uXRZvFi2GOFHiSInA7CLFCnaRCokij0DjyElFh9K6sfwQeQEX" 
210      "rngAvwBNsCyniNCChCKFSCYOkWADd/fuvfeccUEgrCU3yS+NNNN88/8z8D8l14d+v38jTdv3" 
211      "fD3tqEpdRJxE1AzDYYCFoswGg8HL5eXPDwH8dYBzzR8/aM9855x778ZQC2TZ+TEwB6ATAK8r" 
212      "SZLgvefP316SZed47zl902fw+hXOOZxTfKKzz5//1Jpw8OSJaZIcfyFykeqPw1+QX7f5aOEb" 
213      "pP+Iqv4p1YdfUlUF3omUbtwB/r5ysLa2cztNG+nl3P36W5qzPaZ2HzL67BH15ceMxxnjYkiM" 
214      "FXOt5mSEznxn0aliZoSqRFXofNzjIHnA9M0F1HvG4yFVOQag0UhnJiIkkixEixTFiBgqQqg4" 
215      "G/xFdfY7+eicNG0g6nBaQ6SiVivmJgDiZKEsc8CIoSLGQNqc4cbS9zSmpvEuQZ1D1CFS4BJ/" 
216      "cwJQFKPFIRGwC6Aq6mp0Zm9hplQR1AzRSFUFLFhnAvBi5+e7z549Jc9zzGzy+WYYsHinS7N7" 
217      "wnyyxNIn9+evAKurqx5ke3Pzh68smkRMMDCLglz2iHOJjeKJNXw7HB0dvwCQlZWV5ODgoFkU" 
218      "RTOE0DSzGpCYmf9ngQfUzFREKqAQkaH3/qTb7b5xGxsb7O3tWVmWAPGyRCQApYgUIpKLyFBV" 
219      "z1X1zHs/aLfbp/v7+4X8G9NkfX1dd3d3XZZlmue5izFKjFFU1er1emi1WqHX64Wtra0oIu8c" 
220      "6j/qLUda/yKP2243AAAAAElFTkSuQmCC") 
221   
222  #---------------------------------------------------------------------- 
223   
224   
225 -class MultiDirDialog(wx.Dialog):
226 """ 227 A different implementation of wx.DirDialog which allows multiple 228 folders to be selected at once. 229 """ 230
231 - def __init__(self, parent, message=_("Choose a directory"), title=_("Browse For Folders"), 232 defaultPath="", style=wx.DD_DEFAULT_STYLE|DD_MULTIPLE, pos=wx.DefaultPosition, 233 size=wx.DefaultSize, name="multidirdialog"):
234 235 """ 236 Default class constructor. 237 238 @param parent: the dialog parent widget; 239 @param message: the message to show on the dialog; 240 @param title: the dialog title; 241 @param defaultPath: the default path, or the empty string; 242 @param style: the custom dir dialog style; 243 @param pos: the dialog position; 244 @param size: the dialog size; 245 @param name: the dialog name. 246 """ 247 248 self.ddStyle = style 249 250 wx.Dialog.__init__(self, parent, pos=pos, size=size, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, name=name) 251 252 self.dirCtrl = wx.GenericDirCtrl(self, size=(300, 300), style=wx.DIRCTRL_3D_INTERNAL|wx.DIRCTRL_DIR_ONLY) 253 self.folderText = wx.TextCtrl(self, -1, defaultPath, style=wx.TE_PROCESS_ENTER) 254 self.CreateButtons() 255 256 self.SetProperties(title) 257 # Setup the layout and frame properties 258 self.SetupDirCtrl(defaultPath) 259 self.LayoutItems() 260 self.BindEvents()
261 262
263 - def SetupDirCtrl(self, defaultPath):
264 """ Setup the wx.GenericDirCtrl (icons, labels, etc...). """ 265 266 il = wx.ImageList(16, 16) 267 268 # Add images to list. You need to keep the same order in order for 269 # this to work! 270 271 # closed folder: 272 il.Add(_folder_close.GetBitmap()) 273 274 # open folder: 275 il.Add(_folder_open.GetBitmap()) 276 277 # root of filesystem (linux): 278 il.Add(_computer.GetBitmap()) 279 280 # drive letter (windows): 281 il.Add(_hd.GetBitmap()) 282 283 # cdrom drive: 284 il.Add(_cdrom.GetBitmap()) 285 286 # removable drive on win98: 287 il.Add(_removable.GetBitmap()) 288 289 # removable drive (floppy, flash, etc): 290 il.Add(_removable.GetBitmap()) 291 292 # assign image list: 293 treeCtrl = self.dirCtrl.GetTreeCtrl() 294 treeCtrl.AssignImageList(il) 295 296 if self.ddStyle & DD_MULTIPLE: 297 treeCtrl.SetWindowStyle(treeCtrl.GetWindowStyle() | wx.TR_MULTIPLE) 298 299 if not defaultPath.strip(): 300 return 301 302 # Set the wx.GenericDirCtrl default path 303 self.dirCtrl.ExpandPath(defaultPath) 304 self.dirCtrl.SetDefaultPath(defaultPath) 305 self.dirCtrl.SetPath(defaultPath) 306 307 self.folderText.SetValue(treeCtrl.GetItemText(treeCtrl.GetSelections()[0]))
308 309
310 - def SetProperties(self, title):
311 """ Sets few properties for the dialog. """ 312 313 self.SetTitle(title) 314 self.okButton.SetDefault() 315 316 if self.ddStyle & wx.DD_DIR_MUST_EXIST: 317 self.newButton.Enable(False)
318 319
320 - def LayoutItems(self):
321 """ Layout the widgets using sizers. """ 322 323 mainSizer = wx.BoxSizer(wx.VERTICAL) 324 textSizer = wx.BoxSizer(wx.HORIZONTAL) 325 bottomSizer = wx.BoxSizer(wx.HORIZONTAL) 326 327 staticText = wx.StaticText(self, -1, _("Choose one or more folders:")) 328 staticText.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, False)) 329 330 # Add the main wx.GenericDirCtrl 331 mainSizer.Add(staticText, 0, wx.EXPAND|wx.ALL, 10) 332 mainSizer.Add(self.dirCtrl, 1, wx.EXPAND|wx.ALL, 10) 333 334 label = wx.StaticText(self, -1, _("Folder:")) 335 textSizer.Add(label, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 10) 336 textSizer.Add(self.folderText, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 10) 337 mainSizer.Add(textSizer, 0, wx.EXPAND|wx.BOTTOM, 10) 338 339 # Add the fancy buttons 340 bottomSizer.Add(self.newButton, 0, wx.ALL, 10) 341 bottomSizer.Add((0, 0), 1, wx.EXPAND) 342 bottomSizer.Add(self.okButton, 0, wx.TOP|wx.BOTTOM, 10) 343 bottomSizer.Add(self.cancelButton, 0, wx.TOP|wx.BOTTOM|wx.RIGHT, 10) 344 mainSizer.Add(bottomSizer, 0, wx.EXPAND) 345 346 # Layout the dialog 347 self.SetSizer(mainSizer) 348 mainSizer.Layout() 349 mainSizer.Fit(self) 350 mainSizer.SetSizeHints(self)
351 352
353 - def GetPaths(self):
354 """ Returns the folders selected by the user. """ 355 356 # Retrieve the tree control and the selections the 357 # user has made 358 treeCtrl = self.dirCtrl.GetTreeCtrl() 359 selections = treeCtrl.GetSelections() 360 361 folders = [] 362 363 # Loop recursively over the selected folder and its sub-direcories 364 for select in selections: 365 itemText = treeCtrl.GetItemText(select) 366 # Recurse on it. 367 folder = self.RecurseTopDir(treeCtrl, select, itemText) 368 folders.append(os.path.normpath(folder)) 369 370 return folders
371 372
373 - def RecurseTopDir(self, treeCtrl, item, itemText):
374 """ 375 Recurse a directory tree to include the parent-folder. 376 377 @param treeCtrl: the tree control associated with wx.GenericDirCtrl; 378 @param item: the selected tree control item; 379 @param itemText: the selected tree control item text. 380 """ 381 382 # Get the item parent 383 parent = treeCtrl.GetItemParent(item) 384 if parent != treeCtrl.GetRootItem(): 385 # Not the root item, recurse again on it 386 itemText = treeCtrl.GetItemText(parent) + "/" + itemText 387 itemText = self.RecurseTopDir(treeCtrl, parent, itemText) 388 389 return itemText
390 391
392 - def BindEvents(self):
393 """ Binds the events to specific methods. """ 394 395 self.Bind(wx.EVT_BUTTON, self.OnOk, self.okButton) 396 self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelButton) 397 self.Bind(wx.EVT_CLOSE, self.OnClose) 398 self.Bind(wx.EVT_CHAR_HOOK, self.OnKeyUp) 399 self.dirCtrl.GetTreeCtrl().Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged)
400 401
402 - def CreateButtons(self):
403 """ Creates the Ok, cancel and new folder bitmap buttons. """ 404 405 # Build a couple of fancy buttons 406 self.newButton = buttons.ThemedGenBitmapTextButton(self, wx.ID_NEW, _new.GetBitmap(), 407 _("Make New Folder"), size=(-1, 28)) 408 self.okButton = buttons.ThemedGenBitmapTextButton(self, wx.ID_OK, _ok.GetBitmap(), 409 _("OK"), size=(-1, 28)) 410 self.cancelButton = buttons.ThemedGenBitmapTextButton(self, wx.ID_CANCEL, _cancel.GetBitmap(), 411 _("Cancel"), size=(-1, 28))
412 413
414 - def OnOk(self, event):
415 """ Handles the Ok wx.EVT_BUTTON event for the dialog. """ 416 417 self.EndModal(wx.ID_OK)
418 419
420 - def OnCancel(self, event):
421 """ Handles the Cancel wx.EVT_BUTTON event for the dialog. """ 422 423 self.OnClose(event)
424 425
426 - def OnClose(self, event):
427 """ User canceled the dialog. """ 428 429 self.EndModal(wx.ID_CANCEL)
430 431
432 - def OnKeyUp(self, event):
433 """ Handles the wx.EVT_CHAR_HOOK event for the dialog. """ 434 435 if event.GetKeyCode() == wx.WXK_ESCAPE: 436 # Close the dialog, no action 437 self.OnClose(event) 438 elif event.GetKeyCode() in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]: 439 # Close the dialog, the user wants to continue 440 self.OnOk(event) 441 442 event.Skip()
443 444
445 - def OnSelChanged(self, event):
446 """ 447 Handles the wx.EVT_TREE_SEL_CHANGED event for the tree control associated 448 with MultiDirDialog. 449 """ 450 451 if self.IsBeingDeleted(): 452 # We are being destroyed... 453 event.Skip() 454 return 455 456 item = event.GetItem() 457 if not item.IsOk(): 458 # Bad item? 459 event.Skip() 460 return 461 462 treeCtrl = self.dirCtrl.GetTreeCtrl() 463 text = treeCtrl.GetItemText(item) 464 # Set the item name into the text control 465 self.folderText.SetValue(text) 466 self.folderText.Refresh() 467 468 event.Skip()
469