1
2 '''
3 # DESCRIPTION:
4 # Text formatting and colouring tools
5
6 Copyright 1998-2004 Gentoo Foundation
7 # $Id: output.py 4906 2006-11-01 23:55:29Z zmedico $
8 Copyright (C) 2007-2008 Fabio Erculiani
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 '''
24
25 import sys, os
26 import curses
27 from entropy.const import etpUi
28 from entropy.i18n import _
29 stuff = {}
30 stuff['cols'] = 30
31 try:
32 curses.setupterm()
33 stuff['cols'] = curses.tigetnum('cols')
34 except:
35 pass
36 stuff['cleanline'] = ""
38 stuff['cleanline'] = ""
39 count = stuff['cols']
40 while count:
41 stuff['cleanline'] += ' '
42 count -= 1
43 setcols()
44 stuff['cursor'] = False
45 stuff['ESC'] = chr(27)
46
47 havecolor=1
48 global dotitles
49 dotitles=1
50
51 esc_seq = "\x1b["
52
53 g_attr = {}
54 g_attr["normal"] = 0
55
56 g_attr["bold"] = 1
57 g_attr["faint"] = 2
58 g_attr["standout"] = 3
59 g_attr["underline"] = 4
60 g_attr["blink"] = 5
61 g_attr["overline"] = 6
62 g_attr["reverse"] = 7
63 g_attr["invisible"] = 8
64
65 g_attr["no-attr"] = 22
66 g_attr["no-standout"] = 23
67 g_attr["no-underline"] = 24
68 g_attr["no-blink"] = 25
69 g_attr["no-overline"] = 26
70 g_attr["no-reverse"] = 27
71
72
73 g_attr["black"] = 30
74 g_attr["red"] = 31
75 g_attr["green"] = 32
76 g_attr["yellow"] = 33
77 g_attr["blue"] = 34
78 g_attr["magenta"] = 35
79 g_attr["cyan"] = 36
80 g_attr["white"] = 37
81
82 g_attr["default"] = 39
83 g_attr["bg_black"] = 40
84 g_attr["bg_red"] = 41
85 g_attr["bg_green"] = 42
86 g_attr["bg_yellow"] = 43
87 g_attr["bg_blue"] = 44
88 g_attr["bg_magenta"] = 45
89 g_attr["bg_cyan"] = 46
90 g_attr["bg_white"] = 47
91 g_attr["bg_default"] = 49
92
93
94
95 -def color(fg, bg="default", attr=["normal"]):
96 mystr = esc_seq[:] + "%02d" % g_attr[fg]
97 for x in [bg]+attr:
98 mystr += ";%02d" % g_attr[x]
99 return mystr+"m"
100
101
102
103 codes={}
104 codes["reset"] = esc_seq + "39;49;00m"
105
106 codes["bold"] = esc_seq + "01m"
107 codes["faint"] = esc_seq + "02m"
108 codes["standout"] = esc_seq + "03m"
109 codes["underline"] = esc_seq + "04m"
110 codes["blink"] = esc_seq + "05m"
111 codes["overline"] = esc_seq + "06m"
112
113 ansi_color_codes = []
114 for x in xrange(30, 38):
115 ansi_color_codes.append("%im" % x)
116 ansi_color_codes.append("%i;01m" % x)
117
118 rgb_ansi_colors = ['0x000000', '0x555555', '0xAA0000', '0xFF5555', '0x00AA00',
119 '0x55FF55', '0xAA5500', '0xFFFF55', '0x0000AA', '0x5555FF', '0xAA00AA',
120 '0xFF55FF', '0x00AAAA', '0x55FFFF', '0xAAAAAA', '0xFFFFFF']
121
122 for x in xrange(len(rgb_ansi_colors)):
123 codes[rgb_ansi_colors[x]] = esc_seq + ansi_color_codes[x]
124
125 del x
126
127 codes["black"] = codes["0x000000"]
128 codes["darkgray"] = codes["0x555555"]
129
130 codes["red"] = codes["0xFF5555"]
131 codes["darkred"] = codes["0xAA0000"]
132
133 codes["green"] = codes["0x55FF55"]
134 codes["darkgreen"] = codes["0x00AA00"]
135
136 codes["yellow"] = codes["0xFFFF55"]
137 codes["brown"] = codes["0xAA5500"]
138
139 codes["blue"] = codes["0x5555FF"]
140 codes["darkblue"] = codes["0x0000AA"]
141
142 codes["fuchsia"] = codes["0xFF55FF"]
143 codes["purple"] = codes["0xAA00AA"]
144
145 codes["turquoise"] = codes["0x55FFFF"]
146 codes["teal"] = codes["0x00AAAA"]
147
148 codes["white"] = codes["0xFFFFFF"]
149 codes["lightgray"] = codes["0xAAAAAA"]
150
151 codes["darkteal"] = codes["turquoise"]
152 codes["darkyellow"] = codes["brown"]
153 codes["fuscia"] = codes["fuchsia"]
154 codes["white"] = codes["bold"]
155
156
157 codes["GOOD"] = codes["green"]
158 codes["WARN"] = codes["yellow"]
159 codes["BAD"] = codes["red"]
160 codes["HILITE"] = codes["teal"]
161 codes["BRACKET"] = codes["blue"]
162
163
164 codes["INFORM"] = codes["darkgreen"]
165 codes["UNMERGE_WARN"] = codes["red"]
166 codes["MERGE_LIST_PROGRESS"] = codes["yellow"]
167
169 if dotitles and "TERM" in os.environ and sys.stderr.isatty():
170 myt=os.environ["TERM"]
171 legal_terms = ["xterm","Eterm","aterm","rxvt","screen","kterm","rxvt-unicode","gnome"]
172 if myt in legal_terms:
173 if not raw:
174 mystr = "\x1b]0;%s\x07" % mystr
175 try:
176 sys.stderr.write(mystr)
177 except UnicodeEncodeError:
178 sys.stderr.write(mystr.encode('utf-8'))
179 sys.stderr.flush()
180
181 default_xterm_title = None
182
202
207
209 "turn off colorization"
210 os.environ['ETP_NO_COLOR'] = "1"
211 global havecolor
212 havecolor=0
213
214 nc = os.getenv("ETP_NO_COLOR")
215 if nc:
216 nocolor()
217
219 return codes["reset"]
220
228
231
234
237
240
243
246
249
252
255
258
261
264
267
270
273
276
279
281 def derived_func(*args):
282 newargs = list(args)
283 newargs.insert(0, color_key)
284 return colorize(*newargs)
285 return derived_func
286
288 out = atom.split("/")
289 return blue(out[0])+"/"+red(out[1])
290
292
293 def orig_myfunc(x):
294 return x
295 def orig_myfunc_desc(x):
296 return x
297
298 for item in data:
299
300 myfunc = orig_myfunc
301 myfunc_desc = orig_myfunc_desc
302
303 if not item:
304 writechar("\n")
305 else:
306 n_ident = item[0]
307 name = item[1]
308 n_d_ident = item[2]
309 desc = item[3]
310
311 if n_ident == 0:
312 writechar(" ")
313
314 while n_ident > 0:
315 n_ident -= 1
316 writechar("\t")
317 n_ident = item[0]
318
319
320 if n_ident == 0:
321 myfunc = darkgreen
322 elif n_ident == 1:
323 myfunc = blue
324 myfunc_desc = darkgreen
325 elif n_ident == 2:
326 if not name.startswith("--"):
327 myfunc = red
328 myfunc_desc = brown
329 elif n_ident == 3:
330 myfunc = darkblue
331 myfunc_desc = purple
332 try:
333 print myfunc(name),
334 except UnicodeEncodeError:
335 print myfunc(name.encode('utf-8')),
336
337
338 if desc:
339 while n_d_ident > 0:
340 n_d_ident -= 1
341 writechar("\t")
342 try:
343 print myfunc_desc(desc),
344 except UnicodeEncodeError:
345 print myfunc_desc(desc.encode('utf-8')),
346 writechar("\n")
347
352
356
376
396
398 if etpUi['mute']:
399 return
400 if not back:
401 setcols()
402 reset_cursor()
403 writechar("\r")
404 if back:
405 try:
406 print red(">>"),msg,
407 except UnicodeEncodeError:
408 print red(">>"),msg.encode('utf-8'),
409 else:
410 try:
411 print red(">>"),msg
412 except UnicodeEncodeError:
413 print red(">>"),msg.encode('utf-8')
414 if flush:
415 flush_stdouterr()
416
418 if etpUi['mute']:
419 return
420 writechar("\r")
421 try:
422 print msg
423 except UnicodeEncodeError:
424 print msg.encode('utf-8')
425 flush_stdouterr()
426
428 if etpUi['mute']:
429 return
430 try:
431 sys.stdout.write(char)
432 sys.stdout.flush()
433 except IOError, e:
434 if e.errno == 32:
435 return
436 raise
437
438 -def readtext(request, password = False):
439 xtermTitle(_("Entropy needs your attention"))
440 if password:
441 from getpass import getpass
442 try:
443 text = getpass(request+" ")
444 except UnicodeEncodeError:
445 text = getpass(request.encode('utf-8')+" ")
446 else:
447 try:
448 print request,"",
449 except UnicodeEncodeError:
450 print request.encode('utf-8'),"",
451 flush_stdouterr()
452 text = my_raw_input()
453 return text
454
469
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493 - def updateProgress(self, text, header = "", footer = "", back = False, importance = 0, type = "info", count = [], percent = False):
494 if (etpUi['quiet']) or (etpUi['mute']):
495 return
496
497 flush_stdouterr()
498
499 myfunc = print_info
500 if type == "warning":
501 myfunc = print_warning
502 elif type == "error":
503 myfunc = print_error
504
505 count_str = ""
506 if count:
507 if len(count) > 1:
508 if percent:
509 count_str = " ("+str(round((float(count[0])/count[1])*100,1))+"%) "
510 else:
511 count_str = " (%s/%s) " % (red(str(count[0])),blue(str(count[1])),)
512 if importance == 0:
513 myfunc(header+count_str+text+footer, back = back, flush = False)
514 elif importance == 1:
515 myfunc(header+count_str+text+footer, back = back, flush = False)
516 elif importance in (2,3):
517 myfunc(header+count_str+text+footer, back = back, flush = False)
518
519 flush_stdouterr()
520
521
522
523
524
525
526
527
528
529
530
531 - def askQuestion(self, question, importance = 0, responses = ["Yes","No"]):
532
533 colours = [green, red, blue, darkgreen, darkred, darkblue, brown, purple]
534 colours += colours[:]
535 if len(responses) > len(colours):
536 try:
537 from entropy.exceptions import IncorrectParameter
538 except ImportError:
539 from exceptionTools import IncorrectParameter
540 raise IncorrectParameter("IncorrectParameter: %s = %s" % (_("maximum responses length"),len(colours),))
541 try:
542 print darkgreen(question),
543 except UnicodeEncodeError:
544 print darkgreen(question.encode('utf-8')),
545 flush_stdouterr()
546 try:
547 while True:
548 xtermTitle(_("Entropy got a question for you"))
549 flush_stdouterr()
550 response = my_raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ")
551 flush_stdouterr()
552 for key in responses:
553
554 if response.upper() == key[:len(response)].upper():
555 xtermTitleReset()
556 return key
557 '''
558 try:
559 print "%s '%s'" % (_("I cannot understand"),response,),
560 except UnicodeEncodeError:
561 print "%s '%s'" % (_("I cannot understand"),response.encode('utf-8'),),
562 '''
563 flush_stdouterr()
564 except (EOFError, KeyboardInterrupt):
565 print "%s." % (_("Interrupted"),)
566 xtermTitleReset()
567 raise SystemExit(100)
568 xtermTitleReset()
569 flush_stdouterr()
570
571 '''
572 @ title: title of the input box
573 @ input_parameters: [
574 ('identifier 1','input text 1',input_verification_callback,False),
575 ('password','Password',input_verification_callback,True),
576 ('item_3',('checkbox','Checkbox option (boolean request) - please choose',),input_verification_callback,True),
577 ('item_4',('combo',('Select your favorite option',['option 1', 'option 2', 'option 3']),),input_verification_callback,True),
578 ('item_4',('list',('Setup your list',['default list item 1', 'default list item 2']),),input_verification_callback,True)
579 ]
580 @ cancel_button: show cancel button ?
581 @ output: dictionary as follows:
582 {'identifier 1': result, 'identifier 2': result}
583 '''
584 - def inputBox(self, title, input_parameters, cancel_button = True):
585 results = {}
586 if title:
587 try:
588 print title
589 except UnicodeEncodeError:
590 print title.encode('utf-8')
591 flush_stdouterr()
592
593 def option_chooser(option_data):
594 mydict = {}
595 counter = 1
596 option_text, option_list = option_data
597 self.updateProgress(option_text)
598 for item in option_list:
599 mydict[counter] = item
600 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),)
601 self.updateProgress(txt)
602 counter += 1
603 while 1:
604 myresult = readtext("%s:" % (_('Selected number'),)).decode('utf-8')
605 try:
606 myresult = int(myresult)
607 except ValueError:
608 continue
609 selected = mydict.get(myresult)
610 if selected != None:
611 return myresult, selected
612
613 def list_editor(option_data, can_cancel, callback):
614
615 def selaction():
616 self.updateProgress('')
617 self.updateProgress(darkred(_("Please select an option")))
618 if can_cancel:
619 self.updateProgress(" ("+blue("-1")+") "+darkred(_("Discard all")))
620 self.updateProgress(" ("+blue("0")+") "+darkgreen(_("Confirm")))
621 self.updateProgress(" ("+blue("1")+") "+brown(_("Add item")))
622 self.updateProgress(" ("+blue("2")+") "+darkblue(_("Remove item")))
623 self.updateProgress(" ("+blue("3")+") "+darkgreen(_("Show current list")))
624
625 self.updateProgress('')
626 action = readtext(darkgreen(_("Your choice (type a number and press enter):"))+" ")
627 return action
628
629 mydict = {}
630 counter = 1
631 valid_actions = [0,1,2,3]
632 if can_cancel: valid_actions.insert(0,-1)
633 option_text, option_list = option_data
634 txt = "%s:" % (blue(option_text),)
635 self.updateProgress(txt)
636
637 for item in option_list:
638 mydict[counter] = item
639 txt = "[%s] %s" % (darkgreen(str(counter)), blue(item),)
640 self.updateProgress(txt)
641 counter += 1
642
643 def show_current_list():
644 for key in sorted(mydict):
645 txt = "[%s] %s" % (darkgreen(str(key)), blue(mydict[key]),)
646 self.updateProgress(txt)
647
648 while 1:
649 try:
650 action = int(selaction())
651 except (ValueError,TypeError,):
652 self.updateProgress(_("You don't have typed a number."), type = "warning")
653 continue
654 if action not in valid_actions:
655 self.updateProgress(_("Invalid action."), type = "warning")
656 continue
657 if action == -1:
658 raise KeyboardInterrupt
659 elif action == 0:
660 break
661 elif action == 1:
662 while 1:
663 try:
664 s_el = readtext(darkred(_("String to add:"))+" ")
665 if not callback(s_el):
666 raise ValueError
667 mydict[counter] = s_el
668 counter += 1
669 except (ValueError,):
670 self.updateProgress(_("Invalid string."), type = "warning")
671 continue
672 break
673 show_current_list()
674 continue
675 elif action == 2:
676 while 1:
677 try:
678 s_el = int(readtext(darkred(_("Element number to remove:"))+" "))
679 if s_el not in mydict:
680 raise ValueError
681 del mydict[s_el]
682 except (ValueError,TypeError,):
683 self.updateProgress(_("Invalid element."), type = "warning")
684 continue
685 break
686 show_current_list()
687 continue
688 elif action == 3:
689 show_current_list()
690 continue
691 break
692
693 mylist = [mydict[x] for x in sorted(mydict)]
694 return mylist
695
696 for identifier, input_text, callback, password in input_parameters:
697 while 1:
698 use_cb = True
699 try:
700 if isinstance(input_text,tuple):
701 myresult = False
702 input_type, data = input_text
703 if input_type == "checkbox":
704 answer = self.askQuestion(data)
705 if answer == "Yes": myresult = True
706 elif input_type == "combo":
707 myresult = option_chooser(data)
708 elif input_type == "list":
709 use_cb = False
710 myresult = list_editor(data, cancel_button, callback)
711 else:
712 myresult = readtext(input_text+":", password = password).decode('utf-8')
713 except (KeyboardInterrupt,EOFError,):
714 if not cancel_button:
715 continue
716 return None
717 valid = True
718 if use_cb:
719 valid = callback(myresult)
720 if valid:
721 results[identifier] = myresult
722 break
723 return results
724
725
726
727 - def cycleDone(self):
729
730 - def setTitle(self, title):
732
733 - def setTotalCycles(self, total):
735
738
741
742 - def notitles(self):
744