installer/textpane.py
bc3b375f
 #    Copyright (C) 2015 vmware inc.
 #
 #    Author: Mahmoud Bassiouny <mbassiouny@vmware.com>
 import curses
 from actionresult import ActionResult
 from action import Action
 
 class TextPane(Action):
c533b308
     def __init__(self, starty, maxx, width, text_file_path, height,
                  menu_items, partition=False, popupWindow=False,
                  install_config={}, text_items=[], table_space=0,
                  default_start=0, info=[], size_left=[]):
bc3b375f
         self.head_position = 0  #This is the start of showing
72832a72
         self.menu_position = default_start
bc3b375f
         self.lines = []
72832a72
         self.menu_items = menu_items
         self.text_items = text_items
         self.table_space = table_space
c533b308
         self.info = info
         self.size_left = size_left
bc3b375f
 
         self.width = width
c533b308
 
72832a72
         if partition == False:
c533b308
             self.read_file(text_file_path, self.width - 3)
72832a72
         else:
c533b308
             self.install_config = install_config
             self.partition()
 
bc3b375f
         self.num_items = len(self.lines)
72832a72
         if self.info:
             self.text_height = height - 4
         else:
             self.text_height = height - 2
bc3b375f
 
         # Check if we need to add a scroll bar
         if self.num_items > self.text_height:
             self.show_scroll = True
         else:
             self.show_scroll = False
 
         # Some calculation to detitmine the size of the scroll filled portion
c533b308
         if self.num_items == 0:
72832a72
             self.filled = 0
         else:
             self.filled = int(round(self.text_height * self.text_height / float(self.num_items)))
bc3b375f
         if self.filled == 0:
             self.filled += 1
         for i in [1, 2]:
c533b308
             if ((self.num_items - self.text_height) >= i and
                     (self.text_height - self.filled) == (i - 1)):
bc3b375f
                 self.filled -= 1
 
         self.window = curses.newwin(height, self.width)
         self.window.bkgd(' ', curses.color_pair(2))
72832a72
         self.popupWindow = popupWindow
bc3b375f
 
         self.window.keypad(1)
         self.panel = curses.panel.new_panel(self.window)
 
0c250142
         self.panel.move(starty, (maxx - self.width) // 2)
bc3b375f
         self.panel.hide()
         curses.panel.update_panels()
 
72832a72
     def partition(self):
         if self.install_config == {}:
             return
 
         tstring = ''
         #calculate the start index for each item and draw the title
         for index, item in enumerate(self.text_items):
             tstring = tstring + item[0] + ' '*(item[1] - len(item[0])) + ' '*self.table_space
 
         self.lines.append(tstring)
         #draw the table
c533b308
         for i in range(int(self.install_config['partitionsnumber'])):
72832a72
             pdisk = self.install_config['partition_disk']
             if len(pdisk) > self.text_items[0][1]:
                 pdisk = pdisk[-self.text_items[0][1]:]
             psize = self.install_config[str(i)+'partition_info'+str(0)]
             if len(psize) > self.text_items[1][1]:
                 psize = psize[-self.text_items[1][1]:]
c533b308
             if len(psize) == 0:
                 psize = '<' + self.size_left + '>'
             ptype = self.install_config[str(i) + 'partition_info' + str(1)]
72832a72
             if len(ptype) > self.text_items[2][1]:
                 ptype = ptype[-self.text_items[2][1]:]
c533b308
             pmountpoint = self.install_config[str(i) + 'partition_info' + str(2)]
72832a72
             if len(pmountpoint) > self.text_items[3][1]:
                 pmountpoint = pmountpoint[-self.text_items[3][1]:]
c533b308
             pstring = (pdisk + ' '*(self.text_items[0][1] - len(pdisk)) +
                        ' ' * self.table_space + psize +
                        ' '*(self.text_items[1][1] - len(psize)) +
                        ' ' * self.table_space + ptype +
                        ' '*(self.text_items[2][1] - len(ptype) +
                             self.table_space) + pmountpoint)
72832a72
             self.lines.append(pstring)
 
bc3b375f
     def read_file(self, text_file_path, line_width):
a672bd24
         with open(text_file_path, "rb") as f:
bc3b375f
             for line in f:
286a6cae
                 # expand tab to 8 spaces.
a672bd24
                 try:
                     line = line.decode(encoding='latin1')
                 except UnicodeDecodeError:
                     pass
286a6cae
                 line = line.expandtabs()
bbfff61b
                 indent = len(line) - len(line.lstrip())
                 actual_line_width = line_width - indent
                 line = line.strip()
bc3b375f
                 # Adjust the words on the lines
bbfff61b
                 while len(line) > actual_line_width:
                     sep_index = actual_line_width
bb4b7c31
 
                     while sep_index > 0 and line[sep_index-1] != ' ' and line[sep_index] != ' ':
bc3b375f
                         sep_index = sep_index - 1
bb4b7c31
 
c533b308
                     current_line_width = sep_index
bb4b7c31
                     if sep_index == 0:
bbfff61b
                         current_line_width = actual_line_width
bb4b7c31
                     currLine = line[:current_line_width]
                     line = line[current_line_width:]
286a6cae
                     line = line.strip()
bc3b375f
 
                     # Lengthen the line with spaces
c533b308
                     self.lines.append(' ' * indent + currLine +
                                       ' ' *(actual_line_width - len(currLine)))
bc3b375f
 
                 # lengthen the line with spaces
bbfff61b
                 self.lines.append(' ' * indent + line + ' ' *(actual_line_width - len(line)))
bc3b375f
 
     def navigate(self, n):
72832a72
         if self.show_scroll:
             self.head_position += n
             if self.head_position < 0:
                 self.head_position = 0
             elif self.head_position > (len(self.lines) - self.text_height + 1):
                 self.head_position = len(self.lines) - self.text_height + 1
bc3b375f
 
     def navigate_menu(self, n):
         self.menu_position += n
         if self.menu_position < 0:
             self.menu_position = 0
         elif self.menu_position >= len(self.menu_items):
             self.menu_position = len(self.menu_items) - 1
 
 
     def render_scroll_bar(self):
         if self.show_scroll:
             remaining_above = self.head_position
             remaining_down = self.num_items - self.text_height - self.head_position#
c533b308
 
bc3b375f
             up = int(round(remaining_above * self.text_height / float(self.num_items)))
             down = self.text_height - up - self.filled
 
             if up == 0 and remaining_above > 0:
                 up += 1
                 down -= 1
             if down == 0 and remaining_down > 0:
                 up -= 1
                 down += 1
             if remaining_down == 0 and down != 0:
                 up += down
                 down = 0
 
 
             for index in range(up):
                 self.window.addch(index, self.width - 2, curses.ACS_CKBOARD)
 
             for index in range(self.filled):
                 self.window.addstr(index + up, self.width - 2, ' ', curses.A_REVERSE)
 
             for index in range(down):
                 self.window.addch(index + up + self.filled, self.width - 2, curses.ACS_CKBOARD)
 
     def refresh(self):
         self.window.clear()
         for index, line in enumerate(self.lines):
c533b308
             if index < self.head_position:
bc3b375f
                 continue
c533b308
             elif index > self.head_position + self.text_height - 1:
bc3b375f
                 continue
 
             x = 0
             y = index - self.head_position
             if len(line) > 0:
                 self.window.addstr(y, x, line)
 
         xpos = self.width
         for index, item in enumerate(self.menu_items):
             if index == self.menu_position:
                 mode = curses.color_pair(3)
             else:
                 mode = curses.color_pair(2)
72832a72
             if self.info:
                 self.window.addstr(self.text_height + 3, xpos - len(item[0]) - 4, item[0], mode)
             else:
                 self.window.addstr(self.text_height + 1, xpos - len(item[0]) - 4, item[0], mode)
bc3b375f
             xpos = xpos - len(item[0]) - 4
 
72832a72
         if self.info:
             self.window.addstr(self.text_height+1, 5, self.info)
 
 
bc3b375f
         self.render_scroll_bar()
 
         self.window.refresh()
         self.panel.top()
         self.panel.show()
         curses.panel.update_panels()
         curses.doupdate()
 
     def hide(self):
         self.panel.hide()
         curses.panel.update_panels()
         curses.doupdate()
 
     def do_action(self):
         while True:
             self.refresh()
 
             key = self.window.getch()
 
             if key in [curses.KEY_ENTER, ord('\n')]:
                 self.hide()
                 return self.menu_items[self.menu_position][1]()
             if key == curses.KEY_UP:
                 self.navigate(-1)
             elif key == curses.KEY_DOWN:
                 self.navigate(1)
 
             elif key == curses.KEY_LEFT:
                 self.navigate_menu(1)
             elif key == curses.KEY_RIGHT:
                 self.navigate_menu(-1)
 
             elif key == curses.KEY_NPAGE:
                 self.navigate(self.text_height)
             elif key == curses.KEY_PPAGE:
                 self.navigate(-self.text_height)
 
             elif key == curses.KEY_HOME:
                 self.head_position = 0