#!/usr/bin/env python # -*- coding: utf-8 -*- # kate: space-indent on; indent-width 4; replace-tabs on; """ * Copyright (C) 2009, Michael "Svedrin" Ziegler * * Mumble-Django is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. """ # Set this to the same path you used in settings.py, or None for auto-detection. MUMBLE_DJANGO_ROOT = None ### DO NOT CHANGE ANYTHING BELOW THIS LINE ### import os, sys from os.path import join, dirname, abspath, exists # Path auto-detection if not MUMBLE_DJANGO_ROOT or not exists( MUMBLE_DJANGO_ROOT ): MUMBLE_DJANGO_ROOT = dirname(abspath(__file__)) # environment variables sys.path.append( MUMBLE_DJANGO_ROOT ) sys.path.append( join( MUMBLE_DJANGO_ROOT, 'pyweb' ) ) os.environ['DJANGO_SETTINGS_MODULE'] = 'pyweb.settings' # If you get an error about Python not being able to write to the Python # egg cache, the egg cache path might be set awkwardly. This should not # happen under normal circumstances, but every now and then, it does. # Uncomment this line to point the egg cache to /tmp. #os.environ['PYTHON_EGG_CACHE'] = '/tmp/pyeggs' import locale import curses from curses.textpad import Textbox from django.core.exceptions import ValidationError from django.db.models.fields.related import ForeignKey from django.db import models from mumble.models import * from mumble.forms import * locale.setlocale(locale.LC_ALL, '') class BaseWindow( object ): tabName = "tehBasez" def __init__( self, parentwin, mumble, pos_x, pos_y ): self.pos = ( pos_x, pos_y ) self.win = parentwin.subwin( pos_y, pos_x ) self.mm = mumble self.win.keypad(1) def draw( self ): self.win.addstr( 1, 1, self.tabName ) def border( self ): self.win.border() def enter( self ): while( True ): key = self.win.getch() if key == curses.KEY_UP: return class WndChannels( BaseWindow ): tabName = 'Channels' def printItem( self, item, level ): namestr = "" if item.is_server or item.is_channel: namestr = "%s (Channel)" % item.name else: namestr = "%s (Player)" % item.name self.win.addstr( self.curr_y, 4*level+1, namestr.encode(locale.getpreferredencoding()) ) self.curr_y += 1 def draw( self ): self.curr_y = 1 self.mm.rootchan.visit( self.printItem ) class WndSettings( BaseWindow ): tabName = 'Server settings' blacklist = ( 'id', 'sslkey', 'sslcrt' ) def __init__( self, parentwin, mumble, pos_x, pos_y ): BaseWindow.__init__( self, parentwin, mumble, pos_x, pos_y ) self.form = MumbleAdminForm( instance=mumble ) self.editors = {} self.fields = [ mf for mf in mumble._meta.fields if mf.name not in self.blacklist ] def getFieldHeight( self, field ): if isinstance( field, models.TextField ): return 10 return 1 def getFieldYPos( self, field ): ypos = 3 for curr_field in self.fields: if curr_field is field: return ypos ypos += self.getFieldHeight( curr_field ) raise ReferenceError( "Field not found!" ) def draw( self ): curr_y = 3 for field in self.fields: value = unicode( getattr( self.mm, field.name ) ) self.win.addstr( curr_y, 1, field.verbose_name.encode(locale.getpreferredencoding()) ) height = self.getFieldHeight( field ) winsize = self.win.getmaxyx() editwin = self.win.subwin( height, winsize[1]-31, self.pos[1] + curr_y, self.pos[0] + 30 ) editwin.keypad(1) editwin.addstr( value.encode(locale.getpreferredencoding()) ) editbox = Textbox( editwin ) self.editors[field.name] = ( editwin, editbox ) curr_y += height def enter( self ): self.selIdx = 0 self.selMax = len( self.fields ) - 1 while( True ): # Highlight selected field label field = self.fields[self.selIdx] self.win.addstr( self.getFieldYPos(field), 1, field.verbose_name.encode(locale.getpreferredencoding()), curses.A_STANDOUT ) self.win.refresh() key = self.win.getch() if key == curses.KEY_UP: if self.selIdx > 0: self.selIdx -= 1 else: return elif key == curses.KEY_DOWN and self.selIdx < self.selMax: self.selIdx += 1 elif key in ( ord('q'), ord('Q') ): return elif key in ( ord('s'), ord('S') ): try: self.mm.save() except Exception, instance: msg = unicode( instance ) else: msg = "Your settings have been saved." self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()) ) elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ): valid = False while not valid: self.editors[field.name][1].edit() try: setattr( self.mm, field.name, field.to_python( self.editors[field.name][1].gather().strip() ) ) except ValidationError, instance: msg = unicode( instance ) self.win.addstr( 1, 5, msg.encode(locale.getpreferredencoding()), curses.A_STANDOUT ) self.win.refresh() else: valid = True self.win.move( 1, 5 ) self.win.clrtoeol() self.editors[field.name][0].refresh() self.win.addstr( self.getFieldYPos(field), 1, field.verbose_name.encode(locale.getpreferredencoding()) ) class WndUsers( BaseWindow ): tabName = 'Registered users' def draw( self ): curr_y = 3 for acc in self.mm.mumbleuser_set.all(): self.win.addstr( curr_y, 1, acc.name.encode(locale.getpreferredencoding()) ) curr_y += 1 class MumbleForm( object ): def __init__( self, parentwin, mumble, pos_x, pos_y ): self.pos = ( pos_x, pos_y ) self.win = parentwin.subwin( pos_y, pos_x ) self.mm = mumble self.win.keypad(1) self.windows = ( WndChannels( self.win, mumble, pos_x + 2, pos_y + 2 ), WndSettings( self.win, mumble, pos_x + 2, pos_y + 2 ), WndUsers( self.win, mumble, pos_x + 2, pos_y + 2 ), ) self.curridx = 0 self.currmax = len( self.windows ) - 1 currwin = property( lambda self: self.windows[self.curridx], None ) def mvwin( self, pos_x, pos_y ): self.win.mvwin( pos_y, pos_x ) def mvdefault( self ): self.win.mvwin( self.pos[1], self.pos[0] ) def draw( self ): self.win.addstr( 0, 0, self.mm.name.encode(locale.getpreferredencoding()) ) def drawTabs( self ): first = True for subwin in self.windows: flags = 0 if subwin is self.currwin: flags |= curses.A_STANDOUT if first: self.win.addstr( 1, 2, "%-20s" % subwin.tabName, flags ) first = False else: self.win.addstr( "%-20s" % subwin.tabName, flags ) def enter( self ): self.drawTabs() self.currwin.draw() self.currwin.border() while( True ): key = self.win.getch() if key == curses.KEY_LEFT and self.curridx > 0: self.curridx -= 1 elif key == curses.KEY_RIGHT and self.curridx < self.currmax: self.curridx += 1 elif key in ( ord('q'), ord('Q'), curses.KEY_UP ): return elif key in ( curses.KEY_ENTER, curses.KEY_DOWN, ord('\n') ): self.currwin.enter() self.win.clear() self.draw() self.drawTabs() self.currwin.draw() self.currwin.border() self.win.refresh() def main( stdscr ): first_y = 3 curr_y = first_y mumbles = list() for mm in Mumble.objects.all().order_by( "name", "id" ): mwin = MumbleForm( stdscr, mm, pos_x=5, pos_y=curr_y ) mumbles.append( mwin ) mwin.draw() curr_y += 1 selectedIdx = 0 selectedMax = len(mumbles) - 1 myname = "Mumble Commander" while( True ): selectedObj = mumbles[selectedIdx] maxyx = stdscr.getmaxyx() stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE ) # Draw selection marker stdscr.addstr( first_y + selectedIdx, 3, '*' ) stdscr.refresh() key = stdscr.getch() if key == curses.KEY_UP: stdscr.addstr( first_y + selectedIdx, 3, ' ' ) selectedIdx -= 1 elif key == curses.KEY_DOWN: stdscr.addstr( first_y + selectedIdx, 3, ' ' ) selectedIdx += 1 elif key in ( curses.KEY_RIGHT, curses.KEY_ENTER, ord('\n') ): stdscr.clear() stdscr.addstr( 0, maxyx[1] / 2 - len(myname)/2, myname, curses.A_UNDERLINE ) selectedObj.mvwin( 5, first_y ) selectedObj.draw() stdscr.refresh() selectedObj.enter() stdscr.clear() selectedObj.mvdefault() for mwin in mumbles: mwin.draw() elif key in ( ord('q'), ord('Q') ): return if selectedIdx < 0: selectedIdx = 0 elif selectedIdx > selectedMax: selectedIdx = selectedMax if __name__ == '__main__': #parser = OptionParser() #parser.add_option( "-v", "--verbose", help="verbose output messages", default=False, action="store_true" ) #parser.add_option( "-n", "--num", help="size of the Matrix", default=4, type = 'int' ) #parser.add_option( "-s", "--sure", help="don't prompt if num >= 10", default=False, action="store_true" ) #options, args = parser.parse_args() curses.wrapper( main )