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.

364 lines
9.2 KiB

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