Forked mumble-django project from https://bitbucket.org/Svedrin/mumble-django
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
11 KiB

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # kate: space-indent on; indent-width 4; replace-tabs on;
  4. """
  5. * Copyright (C) 2009, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net>
  6. *
  7. * Mumble-Django is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This package is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. """
  17. # Set this to the same path you used in settings.py, or None for auto-detection.
  18. MUMBLE_DJANGO_ROOT = None
  19. ### DO NOT CHANGE ANYTHING BELOW THIS LINE ###
  20. import os, sys
  21. from os.path import join, dirname, abspath, exists
  22. # Path auto-detection
  23. if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ):
  24. MUMBLE_DJANGO_ROOT = dirname(abspath(__file__))
  25. # environment variables
  26. sys.path.append( MUMBLE_DJANGO_ROOT )
  27. sys.path.append( join( MUMBLE_DJANGO_ROOT, 'pyweb' ) )
  28. os.environ['DJANGO_SETTINGS_MODULE'] = 'pyweb.settings'
  29. # If you get an error about Python not being able to write to the Python
  30. # egg cache, the egg cache path might be set awkwardly. This should not
  31. # happen under normal circumstances, but every now and then, it does.
  32. # Uncomment this line to point the egg cache to /tmp.
  33. #os.environ['PYTHON_EGG_CACHE'] = '/tmp/pyeggs'
  34. import locale
  35. import curses
  36. from curses.textpad import Textbox
  37. from django.core.exceptions import ValidationError
  38. from django.db.models.fields.related import ForeignKey
  39. from django.db import models
  40. from mumble.models import *
  41. from mumble.forms import *
  42. locale.setlocale(locale.LC_ALL, '')
  43. class BaseWindow( object ):
  44. tabName = "tehBasez"
  45. def __init__( self, parentwin, mumble, pos_x, pos_y ):
  46. self.pos = ( pos_x, pos_y )
  47. self.win = parentwin.subwin( pos_y, pos_x )
  48. self.mm = mumble
  49. self.win.keypad(1)
  50. def draw( self ):
  51. self.win.addstr( 1, 1, self.tabName )
  52. def border( self ):
  53. self.win.border()
  54. def enter( self ):
  55. while( True ):
  56. key = self.win.getch()
  57. if key == curses.KEY_UP:
  58. return
  59. class WndChannels( BaseWindow ):
  60. tabName = 'Channels'
  61. def printItem( self, item, level ):
  62. namestr = ""
  63. if item.is_server or item.is_channel:
  64. namestr = "%s (Channel)" % item.name
  65. else:
  66. namestr = "%s (Player)" % item.name
  67. self.win.addstr( self.curr_y, 4*level+1, namestr.encode(locale.getpreferredencoding()) )
  68. self.curr_y += 1
  69. def draw( self ):
  70. self.curr_y = 1
  71. self.mm.rootchan.visit( self.printItem )
  72. class WndSettings( BaseWindow ):
  73. tabName = 'Server settings'
  74. blacklist = ( 'id', 'sslkey', 'sslcrt' )
  75. def __init__( self, parentwin, mumble, pos_x, pos_y ):
  76. BaseWindow.__init__( self, parentwin, mumble, pos_x, pos_y )
  77. self.form = MumbleAdminForm( instance=mumble )
  78. self.editors = {}
  79. self.fields = [ mf for mf in mumble._meta.fields if mf.name not in self.blacklist ]
  80. def getFieldHeight( self, field ):
  81. if isinstance( field, models.TextField ):
  82. return 10
  83. return 1
  84. def getFieldYPos( self, field ):
  85. ypos = 3
  86. for curr_field in self.fields:
  87. if curr_field is field:
  88. return ypos
  89. ypos += self.getFieldHeight( curr_field )
  90. raise ReferenceError( "Field not found!" )
  91. def draw( self ):
  92. curr_y = 3
  93. for field in self.fields:
  94. value = unicode( getattr( self.mm, field.name ) )
  95. self.win.addstr( curr_y, 1, field.verbose_name.encode(locale.getpreferredencoding()) )
  96. height = self.getFieldHeight( field )
  97. winsize = self.win.getmaxyx()
  98. editwin = self.win.subwin( height, winsize[1]-31, self.pos[1] + curr_y, self.pos[0] + 30 )
  99. editwin.keypad(1)
  100. editwin.addstr( value.encode(locale.getpreferredencoding()) )
  101. editbox = Textbox( editwin )
  102. self.editors[field.name] = ( editwin, editbox )
  103. curr_y += height
  104. def enter( self ):
  105. self.selIdx = 0
  106. self.selMax = len( self.fields ) - 1
  107. while( True ):
  108. # Highlight selected field label
  109. field = self.fields[self.selIdx]
  110. self.win.addstr(
  111. self.getFieldYPos(field), 1,
  112. field.verbose_name.encode(locale.getpreferredencoding()),
  113. curses.A_STANDOUT
  114. )
  115. self.win.refresh()
  116. key = self.win.getch()
  117. if key == curses.KEY_UP:
  118. if self.selIdx > 0:
  119. self.selIdx -= 1
  120. else:
  121. return
  122. elif key == curses.KEY_DOWN and self.selIdx < self.selMax:
  123. self.selIdx += 1
  124. elif key in ( ord('q'), ord('Q') ):
  125. return
  126. elif key in ( ord('s'), ord('S') ):
  127. try:
  128. self.mm.save()
  129. except Exception, instance:
  130. msg = unicode( instance )
  131. else:
  132. msg = "Your settings have been saved."
  133. self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()) )
  134. elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
  135. valid = False
  136. while not valid:
  137. self.editors[field.name][1].edit()
  138. try:
  139. setattr( self.mm, field.name,
  140. field.to_python( self.editors[field.name][1].gather().strip() )
  141. )
  142. except ValidationError, instance:
  143. msg = unicode( instance )
  144. self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()), curses.A_STANDOUT )
  145. self.win.refresh()
  146. else:
  147. valid = True
  148. self.win.move( 1, 5 )
  149. self.win.clrtoeol()
  150. self.editors[field.name][0].refresh()
  151. self.win.addstr(
  152. self.getFieldYPos(field), 1,
  153. field.verbose_name.encode(locale.getpreferredencoding())
  154. )
  155. class WndUsers( BaseWindow ):
  156. tabName = 'Registered users'
  157. def draw( self ):
  158. curr_y = 3
  159. for acc in self.mm.mumbleuser_set.all():
  160. self.win.addstr( curr_y, 1, acc.name.encode(locale.getpreferredencoding()) )
  161. curr_y += 1
  162. class MumbleForm( object ):
  163. def __init__( self, parentwin, mumble, pos_x, pos_y ):
  164. self.pos = ( pos_x, pos_y )
  165. self.win = parentwin.subwin( pos_y, pos_x )
  166. self.mm = mumble
  167. self.win.keypad(1)
  168. self.windows = (
  169. WndChannels( self.win, mumble, pos_x + 2, pos_y + 2 ),
  170. WndSettings( self.win, mumble, pos_x + 2, pos_y + 2 ),
  171. WndUsers( self.win, mumble, pos_x + 2, pos_y + 2 ),
  172. )
  173. self.curridx = 0
  174. self.currmax = len( self.windows ) - 1
  175. currwin = property( lambda self: self.windows[self.curridx], None )
  176. def mvwin( self, pos_x, pos_y ):
  177. self.win.mvwin( pos_y, pos_x )
  178. def mvdefault( self ):
  179. self.win.mvwin( self.pos[1], self.pos[0] )
  180. def draw( self ):
  181. self.win.addstr( 0, 0, self.mm.name.encode(locale.getpreferredencoding()) )
  182. def drawTabs( self ):
  183. first = True
  184. for subwin in self.windows:
  185. flags = 0
  186. if subwin is self.currwin: flags |= curses.A_STANDOUT
  187. if first:
  188. self.win.addstr( 1, 2, "%-20s" % subwin.tabName, flags )
  189. first = False
  190. else:
  191. self.win.addstr( "%-20s" % subwin.tabName, flags )
  192. def enter( self ):
  193. self.drawTabs()
  194. self.currwin.draw()
  195. self.currwin.border()
  196. while( True ):
  197. key = self.win.getch()
  198. if key == curses.KEY_LEFT and self.curridx > 0:
  199. self.curridx -= 1
  200. elif key == curses.KEY_RIGHT and self.curridx < self.currmax:
  201. self.curridx += 1
  202. elif key in ( ord('q'), ord('Q'), curses.KEY_UP ):
  203. return
  204. elif key in ( curses.KEY_ENTER, curses.KEY_DOWN, ord('\n') ):
  205. self.currwin.enter()
  206. self.win.clear()
  207. self.draw()
  208. self.drawTabs()
  209. self.currwin.draw()
  210. self.currwin.border()
  211. self.win.refresh()
  212. def main( stdscr ):
  213. first_y = 3
  214. curr_y = first_y
  215. mumbles = list()
  216. for mm in Mumble.objects.all().order_by( "name", "id" ):
  217. mwin = MumbleForm( stdscr, mm, pos_x=5, pos_y=curr_y )
  218. mumbles.append( mwin )
  219. mwin.draw()
  220. curr_y += 1
  221. selectedIdx = 0
  222. selectedMax = len(mumbles) - 1
  223. myname = "Mumble Commander"
  224. while( True ):
  225. selectedObj = mumbles[selectedIdx]
  226. maxyx = stdscr.getmaxyx()
  227. stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE )
  228. # Draw selection marker
  229. stdscr.addstr( first_y + selectedIdx, 3, '*' )
  230. stdscr.refresh()
  231. key = stdscr.getch()
  232. if key == curses.KEY_UP:
  233. stdscr.addstr( first_y + selectedIdx, 3, ' ' )
  234. selectedIdx -= 1
  235. elif key == curses.KEY_DOWN:
  236. stdscr.addstr( first_y + selectedIdx, 3, ' ' )
  237. selectedIdx += 1
  238. elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
  239. stdscr.clear()
  240. stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE )
  241. selectedObj.mvwin( 5, first_y )
  242. selectedObj.draw()
  243. stdscr.refresh()
  244. selectedObj.enter()
  245. stdscr.clear()
  246. selectedObj.mvdefault()
  247. for mwin in mumbles:
  248. mwin.draw()
  249. elif key in ( ord('q'), ord('Q') ):
  250. return
  251. if selectedIdx < 0: selectedIdx = 0
  252. elif selectedIdx > selectedMax: selectedIdx = selectedMax
  253. if __name__ == '__main__':
  254. #parser = OptionParser()
  255. #parser.add_option( "-v", "--verbose", help="verbose output messages", default=False, action="store_true" )
  256. #parser.add_option( "-n", "--num", help="size of the Matrix", default=4, type = 'int' )
  257. #parser.add_option( "-s", "--sure", help="don't prompt if num >= 10", default=False, action="store_true" )
  258. #options, args = parser.parse_args()
  259. curses.wrapper( main )