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.

367 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:
  117. if self.selIdx > 0:
  118. self.selIdx -= 1;
  119. else:
  120. return;
  121. elif key == curses.KEY_DOWN and self.selIdx < self.selMax:
  122. self.selIdx += 1;
  123. elif key in ( ord('q'), ord('Q') ):
  124. return;
  125. elif key in ( ord('s'), ord('S') ):
  126. try:
  127. self.mm.save();
  128. except Exception, instance:
  129. msg = unicode( instance );
  130. else:
  131. msg = "Your settings have been saved.";
  132. self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()) );
  133. elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
  134. valid = False;
  135. while not valid:
  136. self.editors[field.name][1].edit();
  137. try:
  138. setattr( self.mm, field.name,
  139. field.to_python( self.editors[field.name][1].gather().strip() )
  140. );
  141. except ValidationError, instance:
  142. msg = unicode( instance );
  143. self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()), curses.A_STANDOUT );
  144. self.win.refresh();
  145. else:
  146. valid = True;
  147. self.win.move( 1, 5 );
  148. self.win.clrtoeol();
  149. self.editors[field.name][0].refresh();
  150. self.win.addstr(
  151. self.getFieldYPos(field), 1,
  152. field.verbose_name.encode(locale.getpreferredencoding())
  153. );
  154. class WndUsers( BaseWindow ):
  155. tabName = 'Registered users';
  156. def draw( self ):
  157. curr_y = 3;
  158. for acc in self.mm.mumbleuser_set.all():
  159. self.win.addstr( curr_y, 1, acc.name.encode(locale.getpreferredencoding()) );
  160. curr_y += 1;
  161. class MumbleForm( object ):
  162. def __init__( self, parentwin, mumble, pos_x, pos_y ):
  163. self.pos = ( pos_x, pos_y );
  164. self.win = parentwin.subwin( pos_y, pos_x );
  165. self.mm = mumble;
  166. self.win.keypad(1);
  167. self.windows = (
  168. WndChannels( self.win, mumble, pos_x + 2, pos_y + 2 ),
  169. WndSettings( self.win, mumble, pos_x + 2, pos_y + 2 ),
  170. WndUsers( self.win, mumble, pos_x + 2, pos_y + 2 ),
  171. );
  172. self.curridx = 0;
  173. self.currmax = len( self.windows ) - 1;
  174. currwin = property( lambda self: self.windows[self.curridx], None );
  175. def mvwin( self, pos_x, pos_y ):
  176. self.win.mvwin( pos_y, pos_x );
  177. def mvdefault( self ):
  178. self.win.mvwin( self.pos[1], self.pos[0] );
  179. def draw( self ):
  180. self.win.addstr( 0, 0, self.mm.name.encode(locale.getpreferredencoding()) );
  181. def drawTabs( self ):
  182. first = True;
  183. for subwin in self.windows:
  184. flags = 0;
  185. if subwin is self.currwin: flags |= curses.A_STANDOUT;
  186. if first:
  187. self.win.addstr( 1, 2, "%-20s" % subwin.tabName, flags );
  188. first = False;
  189. else:
  190. self.win.addstr( "%-20s" % subwin.tabName, flags );
  191. def enter( self ):
  192. self.drawTabs();
  193. self.currwin.draw();
  194. self.currwin.border();
  195. while( True ):
  196. key = self.win.getch();
  197. if key == curses.KEY_LEFT and self.curridx > 0:
  198. self.curridx -= 1;
  199. elif key == curses.KEY_RIGHT and self.curridx < self.currmax:
  200. self.curridx += 1;
  201. elif key in ( ord('q'), ord('Q'), curses.KEY_UP ):
  202. return;
  203. elif key in ( curses.KEY_ENTER, curses.KEY_DOWN, ord('\n') ):
  204. self.currwin.enter();
  205. self.win.clear();
  206. self.draw();
  207. self.drawTabs();
  208. self.currwin.draw();
  209. self.currwin.border();
  210. self.win.refresh();
  211. def main( stdscr ):
  212. first_y = 3;
  213. curr_y = first_y;
  214. mumbles = list();
  215. for mm in Mumble.objects.all().order_by( "name", "id" ):
  216. mwin = MumbleForm( stdscr, mm, pos_x=5, pos_y=curr_y );
  217. mumbles.append( mwin );
  218. mwin.draw();
  219. curr_y += 1;
  220. selectedIdx = 0;
  221. selectedMax = len(mumbles) - 1;
  222. myname = "Mumble Commander";
  223. while( True ):
  224. selectedObj = mumbles[selectedIdx];
  225. maxyx = stdscr.getmaxyx();
  226. stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE );
  227. # Draw selection marker
  228. stdscr.addstr( first_y + selectedIdx, 3, '*' );
  229. stdscr.refresh();
  230. key = stdscr.getch();
  231. if key == curses.KEY_UP:
  232. stdscr.addstr( first_y + selectedIdx, 3, ' ' );
  233. selectedIdx -= 1;
  234. elif key == curses.KEY_DOWN:
  235. stdscr.addstr( first_y + selectedIdx, 3, ' ' );
  236. selectedIdx += 1;
  237. elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ):
  238. stdscr.clear();
  239. stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE );
  240. selectedObj.mvwin( 5, first_y );
  241. selectedObj.draw();
  242. stdscr.refresh();
  243. selectedObj.enter();
  244. stdscr.clear();
  245. selectedObj.mvdefault();
  246. for mwin in mumbles:
  247. mwin.draw();
  248. elif key in ( ord('q'), ord('Q') ):
  249. return;
  250. if selectedIdx < 0: selectedIdx = 0;
  251. elif selectedIdx > selectedMax: selectedIdx = selectedMax;
  252. if __name__ == '__main__':
  253. #parser = OptionParser();
  254. #parser.add_option( "-v", "--verbose", help="verbose output messages", default=False, action="store_true" );
  255. #parser.add_option( "-n", "--num", help="size of the Matrix", default=4, type = 'int' );
  256. #parser.add_option( "-s", "--sure", help="don't prompt if num >= 10", default=False, action="store_true" );
  257. #options, args = parser.parse_args();
  258. curses.wrapper( main );