Thread: [Pymoul-svn] SF.net SVN: pymoul: [68] pymoul/trunk/src/moul (Page 2)
Status: Alpha
Brought to you by:
tiran
From: <ti...@us...> - 2007-01-24 17:01:22
|
Revision: 68 http://pymoul.svn.sourceforge.net/pymoul/?rev=68&view=rev Author: tiran Date: 2007-01-24 09:01:15 -0800 (Wed, 24 Jan 2007) Log Message: ----------- Fixed some min/max values for sliders Added some useful comments about values Modified Paths: -------------- pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-24 16:16:39 UTC (rev 67) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-24 17:01:15 UTC (rev 68) @@ -458,17 +458,18 @@ class AudioIni(ConfFile): _filename = 'audio.ini' _options = { - 'Audio.Initialize' : (BoolString, Constrain()), - 'Audio.UseEAX' : (BoolString, Constrain()), - 'Audio.SetPriorityCutoff' : (int, Constrain()), - 'Audio.MuteAll' : (int, MinMax(0, 1)), - 'Audio.SetChannelVolume SoundFX' : (FloatString, MinMax(0.0, 1.0)), - 'Audio.SetChannelVolume BgndMusic' : (FloatString, MinMax(0.0, 1.0)), - 'Audio.SetChannelVolume Ambience' : (FloatString, MinMax(0.0, 1.0)), - 'Audio.SetChannelVolume NPCVoice' : (FloatString, MinMax(0.0, 1.0)), - 'Audio.EnableVoiceRecording' : (int, MinMax(0, 1)), + 'Audio.Initialize' : (BoolString, Constrain()), # true/false, no ui + 'Audio.UseEAX' : (BoolString, Constrain()), # true/false + 'Audio.SetPriorityCutoff' : (int, Constrain()), # ??? + 'Audio.MuteAll' : (int, MinMax(0, 1)), # 0, 1 + 'Audio.SetChannelVolume SoundFX' : (FloatString, MinMax(0.0, 1.0)), # 0-100% + 'Audio.SetChannelVolume BgndMusic' : (FloatString, MinMax(0.0, 1.0)), # 0-100% + 'Audio.SetChannelVolume Ambience' : (FloatString, MinMax(0.0, 1.0)), # 0-100% + 'Audio.SetChannelVolume NPCVoice' : (FloatString, MinMax(0.0, 1.0)), # 0-100% + 'Audio.EnableVoiceRecording' : (int, MinMax(0, 1)), # 0, 1 'Audio.SetDeviceName' : (QuotedString, Constrain()), # TODO: add check - 'Audio.SetChannelVolume GUI' : (FloatString, MinMax(0.0, 1.0)), + 'Audio.SetChannelVolume GUI' : (FloatString, MinMax(0.0, 1.0)), # 0-100%, no ui + # microphon missing -> OS mixer } _devices = ['Generic Software', 'Generic Hardware'] # plus maybe a custom OpenAL v1.1 device @@ -547,16 +548,16 @@ _options = { 'Graphics.Width' : (int, Contains(videoModes.widths())), 'Graphics.Height' : (int, Contains(videoModes.heights())), - 'Graphics.ColorDepth' : (int, Constrain()), # no ui - 'Graphics.Windowed' : (BoolString, Constrain()), - 'Graphics.AntiAliasAmount' : (int, MinMax(1,4)), - 'Graphics.AnisotropicLevel' : (int, MinMax(1,5)), - 'Graphics.TextureQuality' : (int, MinMax(1,3)), - 'Quality.Level' : (int, MinMax(1,4)), - 'Graphics.Shadow.Enable' : (int, MinMax(0, 1)), - 'Graphics.EnablePlanarReflections' : (int, MinMax(0, 1)), # no ui - 'Graphics.EnableVSync' : (BoolString, Constrain()), - 'Graphics.Shadow.VisibleDistance' : (FloatString, MinMax(0.0, 1.0)), + 'Graphics.ColorDepth' : (int, Constrain()), # no ui, 32 + 'Graphics.Windowed' : (BoolString, Constrain()), # true/false + 'Graphics.AntiAliasAmount' : (int, MinMax(0,6)), # 0 - 6; 4 + 'Graphics.AnisotropicLevel' : (int, MinMax(1,16)), # 1 - 16; 5 + 'Graphics.TextureQuality' : (int, MinMax(0,2)), # 0-2, 3 + 'Quality.Level' : (int, MinMax(0,3)), # 0-3, 4 + 'Graphics.Shadow.Enable' : (int, MinMax(0, 1)), # 0, 1 + 'Graphics.EnablePlanarReflections' : (int, MinMax(0, 1)), # 0,1; no ui + 'Graphics.EnableVSync' : (BoolString, Constrain()), # true/false + 'Graphics.Shadow.VisibleDistance' : (FloatString, MinMax(0.0, 1.0)), # 0-1, 0-100% } def _getScreenRes(self): Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-24 16:16:39 UTC (rev 67) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-24 17:01:15 UTC (rev 68) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Wed Jan 24 16:49:25 2007 +# Created: Wed Jan 24 17:55:00 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -79,6 +79,86 @@ self.tab_graphics1 = QtGui.QWidget() self.tab_graphics1.setObjectName("tab_graphics1") + self.groupBox_gra_checkboxes = QtGui.QGroupBox(self.tab_graphics1) + self.groupBox_gra_checkboxes.setEnabled(True) + self.groupBox_gra_checkboxes.setGeometry(QtCore.QRect(240,10,201,71)) + self.groupBox_gra_checkboxes.setObjectName("groupBox_gra_checkboxes") + + self.groupBox_4 = QtGui.QGroupBox(self.groupBox_gra_checkboxes) + self.groupBox_4.setGeometry(QtCore.QRect(250,100,201,71)) + self.groupBox_4.setObjectName("groupBox_4") + + self.verticalLayout_4 = QtGui.QWidget(self.groupBox_4) + self.verticalLayout_4.setGeometry(QtCore.QRect(10,0,160,71)) + self.verticalLayout_4.setObjectName("verticalLayout_4") + + self.vboxlayout = QtGui.QVBoxLayout(self.verticalLayout_4) + self.vboxlayout.setMargin(0) + self.vboxlayout.setSpacing(6) + self.vboxlayout.setObjectName("vboxlayout") + + self.checkBox_4 = QtGui.QCheckBox(self.verticalLayout_4) + self.checkBox_4.setObjectName("checkBox_4") + self.vboxlayout.addWidget(self.checkBox_4) + + self.checkBox_5 = QtGui.QCheckBox(self.verticalLayout_4) + self.checkBox_5.setObjectName("checkBox_5") + self.vboxlayout.addWidget(self.checkBox_5) + + self.checkBox_6 = QtGui.QCheckBox(self.verticalLayout_4) + self.checkBox_6.setObjectName("checkBox_6") + self.vboxlayout.addWidget(self.checkBox_6) + + self.verticalLayout = QtGui.QWidget(self.groupBox_gra_checkboxes) + self.verticalLayout.setGeometry(QtCore.QRect(10,0,160,71)) + self.verticalLayout.setObjectName("verticalLayout") + + self.vboxlayout1 = QtGui.QVBoxLayout(self.verticalLayout) + self.vboxlayout1.setMargin(0) + self.vboxlayout1.setSpacing(6) + self.vboxlayout1.setObjectName("vboxlayout1") + + self.cb_gra_windowed = QtGui.QCheckBox(self.verticalLayout) + self.cb_gra_windowed.setObjectName("cb_gra_windowed") + self.vboxlayout1.addWidget(self.cb_gra_windowed) + + self.cb_gra_vsync = QtGui.QCheckBox(self.verticalLayout) + self.cb_gra_vsync.setObjectName("cb_gra_vsync") + self.vboxlayout1.addWidget(self.cb_gra_vsync) + + self.cb_gra_shadow = QtGui.QCheckBox(self.verticalLayout) + self.cb_gra_shadow.setObjectName("cb_gra_shadow") + self.vboxlayout1.addWidget(self.cb_gra_shadow) + + self.groupBox_screenres = QtGui.QGroupBox(self.tab_graphics1) + self.groupBox_screenres.setGeometry(QtCore.QRect(10,0,220,81)) + self.groupBox_screenres.setObjectName("groupBox_screenres") + + self.verticalLayout_2 = QtGui.QWidget(self.groupBox_screenres) + self.verticalLayout_2.setGeometry(QtCore.QRect(20,20,181,51)) + self.verticalLayout_2.setObjectName("verticalLayout_2") + + self.vboxlayout2 = QtGui.QVBoxLayout(self.verticalLayout_2) + self.vboxlayout2.setMargin(0) + self.vboxlayout2.setSpacing(6) + self.vboxlayout2.setObjectName("vboxlayout2") + + self.sl_gra_screenres = QtGui.QSlider(self.verticalLayout_2) + self.sl_gra_screenres.setMaximum(10) + self.sl_gra_screenres.setPageStep(1) + self.sl_gra_screenres.setSliderPosition(0) + self.sl_gra_screenres.setTracking(False) + self.sl_gra_screenres.setOrientation(QtCore.Qt.Horizontal) + self.sl_gra_screenres.setTickPosition(QtGui.QSlider.TicksBelow) + self.sl_gra_screenres.setTickInterval(1) + self.sl_gra_screenres.setObjectName("sl_gra_screenres") + self.vboxlayout2.addWidget(self.sl_gra_screenres) + + self.lb_screenres = QtGui.QLabel(self.verticalLayout_2) + self.lb_screenres.setAlignment(QtCore.Qt.AlignCenter) + self.lb_screenres.setObjectName("lb_screenres") + self.vboxlayout2.addWidget(self.lb_screenres) + self.groupBox_gra_quality = QtGui.QGroupBox(self.tab_graphics1) self.groupBox_gra_quality.setEnabled(True) self.groupBox_gra_quality.setGeometry(QtCore.QRect(10,79,430,261)) @@ -88,27 +168,28 @@ self.verticalLayout_7.setGeometry(QtCore.QRect(230,20,179,71)) self.verticalLayout_7.setObjectName("verticalLayout_7") - self.vboxlayout = QtGui.QVBoxLayout(self.verticalLayout_7) - self.vboxlayout.setMargin(0) - self.vboxlayout.setSpacing(6) - self.vboxlayout.setObjectName("vboxlayout") + self.vboxlayout3 = QtGui.QVBoxLayout(self.verticalLayout_7) + self.vboxlayout3.setMargin(0) + self.vboxlayout3.setSpacing(6) + self.vboxlayout3.setObjectName("vboxlayout3") self.label_20 = QtGui.QLabel(self.verticalLayout_7) self.label_20.setAlignment(QtCore.Qt.AlignCenter) self.label_20.setObjectName("label_20") - self.vboxlayout.addWidget(self.label_20) + self.vboxlayout3.addWidget(self.label_20) self.sl_gra_texture = QtGui.QSlider(self.verticalLayout_7) - self.sl_gra_texture.setMinimum(1) - self.sl_gra_texture.setMaximum(3) + self.sl_gra_texture.setMinimum(0) + self.sl_gra_texture.setMaximum(2) self.sl_gra_texture.setPageStep(1) - self.sl_gra_texture.setSliderPosition(1) + self.sl_gra_texture.setProperty("value",QtCore.QVariant(0)) + self.sl_gra_texture.setSliderPosition(0) self.sl_gra_texture.setTracking(False) self.sl_gra_texture.setOrientation(QtCore.Qt.Horizontal) self.sl_gra_texture.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_gra_texture.setTickInterval(1) self.sl_gra_texture.setObjectName("sl_gra_texture") - self.vboxlayout.addWidget(self.sl_gra_texture) + self.vboxlayout3.addWidget(self.sl_gra_texture) self.hboxlayout1 = QtGui.QHBoxLayout() self.hboxlayout1.setMargin(0) @@ -123,33 +204,35 @@ self.label_22.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.label_22.setObjectName("label_22") self.hboxlayout1.addWidget(self.label_22) - self.vboxlayout.addLayout(self.hboxlayout1) + self.vboxlayout3.addLayout(self.hboxlayout1) self.verticalLayout_5 = QtGui.QWidget(self.groupBox_gra_quality) self.verticalLayout_5.setGeometry(QtCore.QRect(20,100,179,71)) self.verticalLayout_5.setObjectName("verticalLayout_5") - self.vboxlayout1 = QtGui.QVBoxLayout(self.verticalLayout_5) - self.vboxlayout1.setMargin(0) - self.vboxlayout1.setSpacing(6) - self.vboxlayout1.setObjectName("vboxlayout1") + self.vboxlayout4 = QtGui.QVBoxLayout(self.verticalLayout_5) + self.vboxlayout4.setMargin(0) + self.vboxlayout4.setSpacing(6) + self.vboxlayout4.setObjectName("vboxlayout4") self.label_13 = QtGui.QLabel(self.verticalLayout_5) self.label_13.setAlignment(QtCore.Qt.AlignCenter) self.label_13.setObjectName("label_13") - self.vboxlayout1.addWidget(self.label_13) + self.vboxlayout4.addWidget(self.label_13) self.sl_gra_antialias = QtGui.QSlider(self.verticalLayout_5) - self.sl_gra_antialias.setMinimum(1) - self.sl_gra_antialias.setMaximum(4) - self.sl_gra_antialias.setPageStep(1) - self.sl_gra_antialias.setSliderPosition(1) + self.sl_gra_antialias.setMinimum(0) + self.sl_gra_antialias.setMaximum(6) + self.sl_gra_antialias.setSingleStep(2) + self.sl_gra_antialias.setPageStep(2) + self.sl_gra_antialias.setProperty("value",QtCore.QVariant(0)) + self.sl_gra_antialias.setSliderPosition(0) self.sl_gra_antialias.setTracking(False) self.sl_gra_antialias.setOrientation(QtCore.Qt.Horizontal) self.sl_gra_antialias.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_gra_antialias.setTickInterval(1) + self.sl_gra_antialias.setTickInterval(2) self.sl_gra_antialias.setObjectName("sl_gra_antialias") - self.vboxlayout1.addWidget(self.sl_gra_antialias) + self.vboxlayout4.addWidget(self.sl_gra_antialias) self.hboxlayout2 = QtGui.QHBoxLayout() self.hboxlayout2.setMargin(0) @@ -164,33 +247,34 @@ self.label_16.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.label_16.setObjectName("label_16") self.hboxlayout2.addWidget(self.label_16) - self.vboxlayout1.addLayout(self.hboxlayout2) + self.vboxlayout4.addLayout(self.hboxlayout2) self.verticalLayout_3 = QtGui.QWidget(self.groupBox_gra_quality) self.verticalLayout_3.setGeometry(QtCore.QRect(20,20,179,71)) self.verticalLayout_3.setObjectName("verticalLayout_3") - self.vboxlayout2 = QtGui.QVBoxLayout(self.verticalLayout_3) - self.vboxlayout2.setMargin(0) - self.vboxlayout2.setSpacing(6) - self.vboxlayout2.setObjectName("vboxlayout2") + self.vboxlayout5 = QtGui.QVBoxLayout(self.verticalLayout_3) + self.vboxlayout5.setMargin(0) + self.vboxlayout5.setSpacing(6) + self.vboxlayout5.setObjectName("vboxlayout5") self.label_2 = QtGui.QLabel(self.verticalLayout_3) self.label_2.setAlignment(QtCore.Qt.AlignCenter) self.label_2.setObjectName("label_2") - self.vboxlayout2.addWidget(self.label_2) + self.vboxlayout5.addWidget(self.label_2) self.sl_gra_quality = QtGui.QSlider(self.verticalLayout_3) - self.sl_gra_quality.setMinimum(1) - self.sl_gra_quality.setMaximum(4) + self.sl_gra_quality.setMinimum(0) + self.sl_gra_quality.setMaximum(3) self.sl_gra_quality.setPageStep(1) - self.sl_gra_quality.setSliderPosition(1) + self.sl_gra_quality.setProperty("value",QtCore.QVariant(0)) + self.sl_gra_quality.setSliderPosition(0) self.sl_gra_quality.setTracking(False) self.sl_gra_quality.setOrientation(QtCore.Qt.Horizontal) self.sl_gra_quality.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_gra_quality.setTickInterval(1) self.sl_gra_quality.setObjectName("sl_gra_quality") - self.vboxlayout2.addWidget(self.sl_gra_quality) + self.vboxlayout5.addWidget(self.sl_gra_quality) self.hboxlayout3 = QtGui.QHBoxLayout() self.hboxlayout3.setMargin(0) @@ -215,21 +299,21 @@ self.label_7.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.label_7.setObjectName("label_7") self.hboxlayout3.addWidget(self.label_7) - self.vboxlayout2.addLayout(self.hboxlayout3) + self.vboxlayout5.addLayout(self.hboxlayout3) self.verticalLayout_8 = QtGui.QWidget(self.groupBox_gra_quality) self.verticalLayout_8.setGeometry(QtCore.QRect(20,180,179,71)) self.verticalLayout_8.setObjectName("verticalLayout_8") - self.vboxlayout3 = QtGui.QVBoxLayout(self.verticalLayout_8) - self.vboxlayout3.setMargin(0) - self.vboxlayout3.setSpacing(6) - self.vboxlayout3.setObjectName("vboxlayout3") + self.vboxlayout6 = QtGui.QVBoxLayout(self.verticalLayout_8) + self.vboxlayout6.setMargin(0) + self.vboxlayout6.setSpacing(6) + self.vboxlayout6.setObjectName("vboxlayout6") self.label_15 = QtGui.QLabel(self.verticalLayout_8) self.label_15.setAlignment(QtCore.Qt.AlignCenter) self.label_15.setObjectName("label_15") - self.vboxlayout3.addWidget(self.label_15) + self.vboxlayout6.addWidget(self.label_15) self.sl_gra_shadow = QtGui.QSlider(self.verticalLayout_8) self.sl_gra_shadow.setMinimum(0) @@ -242,7 +326,7 @@ self.sl_gra_shadow.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_gra_shadow.setTickInterval(25) self.sl_gra_shadow.setObjectName("sl_gra_shadow") - self.vboxlayout3.addWidget(self.sl_gra_shadow) + self.vboxlayout6.addWidget(self.sl_gra_shadow) self.hboxlayout4 = QtGui.QHBoxLayout() self.hboxlayout4.setMargin(0) @@ -257,33 +341,34 @@ self.label_24.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.label_24.setObjectName("label_24") self.hboxlayout4.addWidget(self.label_24) - self.vboxlayout3.addLayout(self.hboxlayout4) + self.vboxlayout6.addLayout(self.hboxlayout4) self.verticalLayout_6 = QtGui.QWidget(self.groupBox_gra_quality) self.verticalLayout_6.setGeometry(QtCore.QRect(230,100,179,73)) self.verticalLayout_6.setObjectName("verticalLayout_6") - self.vboxlayout4 = QtGui.QVBoxLayout(self.verticalLayout_6) - self.vboxlayout4.setMargin(0) - self.vboxlayout4.setSpacing(6) - self.vboxlayout4.setObjectName("vboxlayout4") + self.vboxlayout7 = QtGui.QVBoxLayout(self.verticalLayout_6) + self.vboxlayout7.setMargin(0) + self.vboxlayout7.setSpacing(6) + self.vboxlayout7.setObjectName("vboxlayout7") self.label_17 = QtGui.QLabel(self.verticalLayout_6) self.label_17.setAlignment(QtCore.Qt.AlignCenter) self.label_17.setObjectName("label_17") - self.vboxlayout4.addWidget(self.label_17) + self.vboxlayout7.addWidget(self.label_17) self.sl_gra_anisotropic = QtGui.QSlider(self.verticalLayout_6) self.sl_gra_anisotropic.setMinimum(1) - self.sl_gra_anisotropic.setMaximum(5) - self.sl_gra_anisotropic.setPageStep(1) + self.sl_gra_anisotropic.setMaximum(16) + self.sl_gra_anisotropic.setSingleStep(3) + self.sl_gra_anisotropic.setPageStep(3) self.sl_gra_anisotropic.setSliderPosition(1) self.sl_gra_anisotropic.setTracking(False) self.sl_gra_anisotropic.setOrientation(QtCore.Qt.Horizontal) self.sl_gra_anisotropic.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_gra_anisotropic.setTickInterval(1) + self.sl_gra_anisotropic.setTickInterval(5) self.sl_gra_anisotropic.setObjectName("sl_gra_anisotropic") - self.vboxlayout4.addWidget(self.sl_gra_anisotropic) + self.vboxlayout7.addWidget(self.sl_gra_anisotropic) self.hboxlayout5 = QtGui.QHBoxLayout() self.hboxlayout5.setMargin(0) @@ -298,87 +383,7 @@ self.label_19.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.label_19.setObjectName("label_19") self.hboxlayout5.addWidget(self.label_19) - self.vboxlayout4.addLayout(self.hboxlayout5) - - self.groupBox_gra_checkboxes = QtGui.QGroupBox(self.tab_graphics1) - self.groupBox_gra_checkboxes.setEnabled(True) - self.groupBox_gra_checkboxes.setGeometry(QtCore.QRect(240,10,201,71)) - self.groupBox_gra_checkboxes.setObjectName("groupBox_gra_checkboxes") - - self.groupBox_4 = QtGui.QGroupBox(self.groupBox_gra_checkboxes) - self.groupBox_4.setGeometry(QtCore.QRect(250,100,201,71)) - self.groupBox_4.setObjectName("groupBox_4") - - self.verticalLayout_4 = QtGui.QWidget(self.groupBox_4) - self.verticalLayout_4.setGeometry(QtCore.QRect(10,0,160,71)) - self.verticalLayout_4.setObjectName("verticalLayout_4") - - self.vboxlayout5 = QtGui.QVBoxLayout(self.verticalLayout_4) - self.vboxlayout5.setMargin(0) - self.vboxlayout5.setSpacing(6) - self.vboxlayout5.setObjectName("vboxlayout5") - - self.checkBox_4 = QtGui.QCheckBox(self.verticalLayout_4) - self.checkBox_4.setObjectName("checkBox_4") - self.vboxlayout5.addWidget(self.checkBox_4) - - self.checkBox_5 = QtGui.QCheckBox(self.verticalLayout_4) - self.checkBox_5.setObjectName("checkBox_5") - self.vboxlayout5.addWidget(self.checkBox_5) - - self.checkBox_6 = QtGui.QCheckBox(self.verticalLayout_4) - self.checkBox_6.setObjectName("checkBox_6") - self.vboxlayout5.addWidget(self.checkBox_6) - - self.verticalLayout = QtGui.QWidget(self.groupBox_gra_checkboxes) - self.verticalLayout.setGeometry(QtCore.QRect(10,0,160,71)) - self.verticalLayout.setObjectName("verticalLayout") - - self.vboxlayout6 = QtGui.QVBoxLayout(self.verticalLayout) - self.vboxlayout6.setMargin(0) - self.vboxlayout6.setSpacing(6) - self.vboxlayout6.setObjectName("vboxlayout6") - - self.cb_gra_windowed = QtGui.QCheckBox(self.verticalLayout) - self.cb_gra_windowed.setObjectName("cb_gra_windowed") - self.vboxlayout6.addWidget(self.cb_gra_windowed) - - self.cb_gra_vsync = QtGui.QCheckBox(self.verticalLayout) - self.cb_gra_vsync.setObjectName("cb_gra_vsync") - self.vboxlayout6.addWidget(self.cb_gra_vsync) - - self.cb_gra_shadow = QtGui.QCheckBox(self.verticalLayout) - self.cb_gra_shadow.setObjectName("cb_gra_shadow") - self.vboxlayout6.addWidget(self.cb_gra_shadow) - - self.groupBox_screenres = QtGui.QGroupBox(self.tab_graphics1) - self.groupBox_screenres.setGeometry(QtCore.QRect(10,0,220,81)) - self.groupBox_screenres.setObjectName("groupBox_screenres") - - self.verticalLayout_2 = QtGui.QWidget(self.groupBox_screenres) - self.verticalLayout_2.setGeometry(QtCore.QRect(20,20,181,51)) - self.verticalLayout_2.setObjectName("verticalLayout_2") - - self.vboxlayout7 = QtGui.QVBoxLayout(self.verticalLayout_2) - self.vboxlayout7.setMargin(0) - self.vboxlayout7.setSpacing(6) - self.vboxlayout7.setObjectName("vboxlayout7") - - self.sl_gra_screenres = QtGui.QSlider(self.verticalLayout_2) - self.sl_gra_screenres.setMaximum(10) - self.sl_gra_screenres.setPageStep(1) - self.sl_gra_screenres.setSliderPosition(0) - self.sl_gra_screenres.setTracking(False) - self.sl_gra_screenres.setOrientation(QtCore.Qt.Horizontal) - self.sl_gra_screenres.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_gra_screenres.setTickInterval(1) - self.sl_gra_screenres.setObjectName("sl_gra_screenres") - self.vboxlayout7.addWidget(self.sl_gra_screenres) - - self.lb_screenres = QtGui.QLabel(self.verticalLayout_2) - self.lb_screenres.setAlignment(QtCore.Qt.AlignCenter) - self.lb_screenres.setObjectName("lb_screenres") - self.vboxlayout7.addWidget(self.lb_screenres) + self.vboxlayout7.addLayout(self.hboxlayout5) self.tab_graphics.addTab(self.tab_graphics1,"") self.tab_audio = QtGui.QWidget() @@ -720,6 +725,14 @@ def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "Tool for Myst Online", None, QtGui.QApplication.UnicodeUTF8)) self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "Configure", None, QtGui.QApplication.UnicodeUTF8)) + self.checkBox_4.setText(QtGui.QApplication.translate("MainWindow", "CheckBox", None, QtGui.QApplication.UnicodeUTF8)) + self.checkBox_5.setText(QtGui.QApplication.translate("MainWindow", "CheckBox", None, QtGui.QApplication.UnicodeUTF8)) + self.checkBox_6.setText(QtGui.QApplication.translate("MainWindow", "CheckBox", None, QtGui.QApplication.UnicodeUTF8)) + self.cb_gra_windowed.setText(QtGui.QApplication.translate("MainWindow", "Windowed", None, QtGui.QApplication.UnicodeUTF8)) + self.cb_gra_vsync.setText(QtGui.QApplication.translate("MainWindow", "Vertical Sync", None, QtGui.QApplication.UnicodeUTF8)) + self.cb_gra_shadow.setText(QtGui.QApplication.translate("MainWindow", "Display Shadows", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox_screenres.setTitle(QtGui.QApplication.translate("MainWindow", "Screen Resolution", None, QtGui.QApplication.UnicodeUTF8)) + self.lb_screenres.setText(QtGui.QApplication.translate("MainWindow", "800x600 (4:3)", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox_gra_quality.setTitle(QtGui.QApplication.translate("MainWindow", "Quality", None, QtGui.QApplication.UnicodeUTF8)) self.label_20.setText(QtGui.QApplication.translate("MainWindow", "Texture Quality", None, QtGui.QApplication.UnicodeUTF8)) self.label_21.setText(QtGui.QApplication.translate("MainWindow", "Low", None, QtGui.QApplication.UnicodeUTF8)) @@ -738,14 +751,6 @@ self.label_17.setText(QtGui.QApplication.translate("MainWindow", "Anisotropic-Filtering", None, QtGui.QApplication.UnicodeUTF8)) self.label_18.setText(QtGui.QApplication.translate("MainWindow", "Low", None, QtGui.QApplication.UnicodeUTF8)) self.label_19.setText(QtGui.QApplication.translate("MainWindow", "High", None, QtGui.QApplication.UnicodeUTF8)) - self.checkBox_4.setText(QtGui.QApplication.translate("MainWindow", "CheckBox", None, QtGui.QApplication.UnicodeUTF8)) - self.checkBox_5.setText(QtGui.QApplication.translate("MainWindow", "CheckBox", None, QtGui.QApplication.UnicodeUTF8)) - self.checkBox_6.setText(QtGui.QApplication.translate("MainWindow", "CheckBox", None, QtGui.QApplication.UnicodeUTF8)) - self.cb_gra_windowed.setText(QtGui.QApplication.translate("MainWindow", "Windowed", None, QtGui.QApplication.UnicodeUTF8)) - self.cb_gra_vsync.setText(QtGui.QApplication.translate("MainWindow", "Vertical Sync", None, QtGui.QApplication.UnicodeUTF8)) - self.cb_gra_shadow.setText(QtGui.QApplication.translate("MainWindow", "Display Shadows", None, QtGui.QApplication.UnicodeUTF8)) - self.groupBox_screenres.setTitle(QtGui.QApplication.translate("MainWindow", "Screen Resolution", None, QtGui.QApplication.UnicodeUTF8)) - self.lb_screenres.setText(QtGui.QApplication.translate("MainWindow", "800x600 (4:3)", None, QtGui.QApplication.UnicodeUTF8)) self.tab_graphics.setTabText(self.tab_graphics.indexOf(self.tab_graphics1), QtGui.QApplication.translate("MainWindow", "Graphics", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox_aud_level.setTitle(QtGui.QApplication.translate("MainWindow", "Level", None, QtGui.QApplication.UnicodeUTF8)) self.label_31.setText(QtGui.QApplication.translate("MainWindow", "NPC Voices", None, QtGui.QApplication.UnicodeUTF8)) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-24 16:16:39 UTC (rev 67) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-24 17:01:15 UTC (rev 68) @@ -135,6 +135,179 @@ <attribute name="title" > <string>Graphics</string> </attribute> + <widget class="QGroupBox" name="groupBox_gra_checkboxes" > + <property name="enabled" > + <bool>true</bool> + </property> + <property name="geometry" > + <rect> + <x>240</x> + <y>10</y> + <width>201</width> + <height>71</height> + </rect> + </property> + <property name="title" > + <string/> + </property> + <widget class="QGroupBox" name="groupBox_4" > + <property name="geometry" > + <rect> + <x>250</x> + <y>100</y> + <width>201</width> + <height>71</height> + </rect> + </property> + <property name="title" > + <string/> + </property> + <widget class="QWidget" name="verticalLayout_4" > + <property name="geometry" > + <rect> + <x>10</x> + <y>0</y> + <width>160</width> + <height>71</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QCheckBox" name="checkBox_4" > + <property name="text" > + <string>CheckBox</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox_5" > + <property name="text" > + <string>CheckBox</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="checkBox_6" > + <property name="text" > + <string>CheckBox</string> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <widget class="QWidget" name="verticalLayout" > + <property name="geometry" > + <rect> + <x>10</x> + <y>0</y> + <width>160</width> + <height>71</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QCheckBox" name="cb_gra_windowed" > + <property name="text" > + <string>Windowed</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cb_gra_vsync" > + <property name="text" > + <string>Vertical Sync</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="cb_gra_shadow" > + <property name="text" > + <string>Display Shadows</string> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <widget class="QGroupBox" name="groupBox_screenres" > + <property name="geometry" > + <rect> + <x>10</x> + <y>0</y> + <width>220</width> + <height>81</height> + </rect> + </property> + <property name="title" > + <string>Screen Resolution</string> + </property> + <widget class="QWidget" name="verticalLayout_2" > + <property name="geometry" > + <rect> + <x>20</x> + <y>20</y> + <width>181</width> + <height>51</height> + </rect> + </property> + <layout class="QVBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QSlider" name="sl_gra_screenres" > + <property name="maximum" > + <number>10</number> + </property> + <property name="pageStep" > + <number>1</number> + </property> + <property name="sliderPosition" > + <number>0</number> + </property> + <property name="tracking" > + <bool>false</bool> + </property> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition" > + <enum>QSlider::TicksBelow</enum> + </property> + <property name="tickInterval" > + <number>1</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lb_screenres" > + <property name="text" > + <string>800x600 (4:3)</string> + </property> + <property name="alignment" > + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </widget> + </widget> <widget class="QGroupBox" name="groupBox_gra_quality" > <property name="enabled" > <bool>true</bool> @@ -179,16 +352,19 @@ <item> <widget class="QSlider" name="sl_gra_texture" > <property name="minimum" > - <number>1</number> + <number>0</number> </property> <property name="maximum" > - <number>3</number> + <number>2</number> </property> <property name="pageStep" > <number>1</number> </property> + <property name="value" > + <number>0</number> + </property> <property name="sliderPosition" > - <number>1</number> + <number>0</number> </property> <property name="tracking" > <bool>false</bool> @@ -262,16 +438,22 @@ <item> <widget class="QSlider" name="sl_gra_antialias" > <property name="minimum" > - <number>1</number> + <number>0</number> </property> <property name="maximum" > - <number>4</number> + <number>6</number> </property> + <property name="singleStep" > + <number>2</number> + </property> <property name="pageStep" > - <number>1</number> + <number>2</number> </property> + <property name="value" > + <number>0</number> + </property> <property name="sliderPosition" > - <number>1</number> + <number>0</number> </property> <property name="tracking" > <bool>false</bool> @@ -283,7 +465,7 @@ <enum>QSlider::TicksBelow</enum> </property> <property name="tickInterval" > - <number>1</number> + <number>2</number> </property> </widget> </item> @@ -345,16 +527,19 @@ <item> <widget class="QSlider" name="sl_gra_quality" > <property name="minimum" > - <number>1</number> + <number>0</number> </property> <property name="maximum" > - <number>4</number> + <number>3</number> </property> <property name="pageStep" > <number>1</number> </property> + <property name="value" > + <number>0</number> + </property> <property name="sliderPosition" > - <number>1</number> + <number>0</number> </property> <property name="tracking" > <bool>false</bool> @@ -537,10 +722,13 @@ <number>1</number> </property> <property name="maximum" > - <number>5</number> + <number>16</number> </property> + <property name="singleStep" > + <number>3</number> + </property> <property name="pageStep" > - <number>1</number> + <number>3</number> </property> <property name="sliderPosition" > <number>1</number> @@ -555,7 +743,7 @@ <enum>QSlider::TicksBelow</enum> </property> <property name="tickInterval" > - <number>1</number> + <number>5</number> </property> </widget> </item> @@ -589,179 +777,6 @@ </layout> </widget> </widget> - <widget class="QGroupBox" name="groupBox_gra_checkboxes" > - <property name="enabled" > - <bool>true</bool> - </property> - <property name="geometry" > - <rect> - <x>240</x> - <y>10</y> - <width>201</width> - <height>71</height> - </rect> - </property> - <property name="title" > - <string/> - </property> - <widget class="QGroupBox" name="groupBox_4" > - <property name="geometry" > - <rect> - <x>250</x> - <y>100</y> - <width>201</width> - <height>71</height> - </rect> - </property> - <property name="title" > - <string/> - </property> - <widget class="QWidget" name="verticalLayout_4" > - <property name="geometry" > - <rect> - <x>10</x> - <y>0</y> - <width>160</width> - <height>71</height> - </rect> - </property> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QCheckBox" name="checkBox_4" > - <property name="text" > - <string>CheckBox</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="checkBox_5" > - <property name="text" > - <string>CheckBox</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="checkBox_6" > - <property name="text" > - <string>CheckBox</string> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - <widget class="QWidget" name="verticalLayout" > - <property name="geometry" > - <rect> - <x>10</x> - <y>0</y> - <width>160</width> - <height>71</height> - </rect> - </property> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QCheckBox" name="cb_gra_windowed" > - <property name="text" > - <string>Windowed</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="cb_gra_vsync" > - <property name="text" > - <string>Vertical Sync</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="cb_gra_shadow" > - <property name="text" > - <string>Display Shadows</string> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - <widget class="QGroupBox" name="groupBox_screenres" > - <property name="geometry" > - <rect> - <x>10</x> - <y>0</y> - <width>220</width> - <height>81</height> - </rect> - </property> - <property name="title" > - <string>Screen Resolution</string> - </property> - <widget class="QWidget" name="verticalLayout_2" > - <property name="geometry" > - <rect> - <x>20</x> - <y>20</y> - <width>181</width> - <height>51</height> - </rect> - </property> - <layout class="QVBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QSlider" name="sl_gra_screenres" > - <property name="maximum" > - <number>10</number> - </property> - <property name="pageStep" > - <number>1</number> - </property> - <property name="sliderPosition" > - <number>0</number> - </property> - <property name="tracking" > - <bool>false</bool> - </property> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="tickPosition" > - <enum>QSlider::TicksBelow</enum> - </property> - <property name="tickInterval" > - <number>1</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="lb_screenres" > - <property name="text" > - <string>800x600 (4:3)</string> - </property> - <property name="alignment" > - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - </layout> - </widget> - </widget> </widget> <widget class="QWidget" name="tab_audio" > <attribute name="title" > This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-24 20:40:50
|
Revision: 70 http://pymoul.svn.sourceforge.net/pymoul/?rev=70&view=rev Author: tiran Date: 2007-01-24 12:40:47 -0800 (Wed, 24 Jan 2007) Log Message: ----------- Minor fixes for brain bug Modified Paths: -------------- pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.py Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-24 18:26:59 UTC (rev 69) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-24 20:40:47 UTC (rev 70) @@ -309,14 +309,27 @@ _filename = None def __init__(self): + self._filedata = {} + self._newdata = {} + self._order = [] self.clear() self._fpath = None def clear(self): - self._filedata = {} - self._newdata = {} - self._order = [] + """Clear all informations + """ + self._filedata.clear() + self._newdata.clear() + self._order[:] = [] + def reset(self): + """Reset state of the ini parser + + Copies file data to new data + """ + self._newdata.clear() + self._newdata.update(self._filedata.copy()) + def open(self, path): """Open encrypted file at 'path' """ @@ -388,14 +401,14 @@ if not found: raise ValueError(line) - self._newdata = self._filedata.copy() + self.reset() self.parserDoneHook() def parserDoneHook(self): """Hook called after the data is read and parsed """ pass - + def isChanged(self): """Check if the data was changed """ Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-24 18:26:59 UTC (rev 69) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-24 20:40:47 UTC (rev 70) @@ -132,6 +132,7 @@ self.on_graphicsini_loaded(gini) # XXX: hard coded for testing purpose + @signalLogDecorator(LOG) def on_graphicsini_loaded(self, gini): """SIGNAL: graphicsIniLoaded(file) """ @@ -231,6 +232,7 @@ self.on_audioini_loaded(aini) # XXX: hard coded for testing purpose + @signalLogDecorator(LOG) def on_audioini_loaded(self, aini): """SIGNAL: graphicsIniLoaded(file) """ Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-24 18:26:59 UTC (rev 69) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-24 20:40:47 UTC (rev 70) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Wed Jan 24 19:25:53 2007 +# Created: Wed Jan 24 19:26:57 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-24 23:17:08
|
Revision: 72 http://pymoul.svn.sourceforge.net/pymoul/?rev=72&view=rev Author: tiran Date: 2007-01-24 15:17:08 -0800 (Wed, 24 Jan 2007) Log Message: ----------- Fixed bug in wdys crypt module. It failed when the data was aligned at 8 bytes. First version that actually writes graphics and audio ini Modified Paths: -------------- pymoul/trunk/src/moul/crypt/whatdoyousee.py pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/qt/mainwindow.py Modified: pymoul/trunk/src/moul/crypt/whatdoyousee.py =================================================================== --- pymoul/trunk/src/moul/crypt/whatdoyousee.py 2007-01-24 22:11:48 UTC (rev 71) +++ pymoul/trunk/src/moul/crypt/whatdoyousee.py 2007-01-24 23:17:08 UTC (rev 72) @@ -32,12 +32,15 @@ from moul.crypt.xtea import xtea_decrypt from moul.crypt.xtea import xtea_encrypt +from moul.log import getLogger HEADER = "whatdoyousee" CROSS_REF = (0x6c0a5452, 0x03827d0f, 0x3a170b92, 0x16db7fc2) CROSS_KEY = struct.pack("<4L", *CROSS_REF) ENDIAN="<" # little endian (not network/big endian) +LOG = getLogger('moul.crypt.whatdoyousee') + def decryptWDYS(fin): """Decrypt whatdoyousee files @@ -54,9 +57,15 @@ out = [] pos = 0 - while fin: + while True: block = fin.read(8) - block = xtea_decrypt(CROSS_KEY, block, endian=ENDIAN) + if not block: + break + try: + block = xtea_decrypt(CROSS_KEY, block, endian=ENDIAN) + except: + LOG.exception("xTEA failure at block %r" % block) + raise if length - pos < 8: out.append(block[:length-pos]) break @@ -91,6 +100,10 @@ if len(block) < 8: block = block + '\0' * (8-len(block)) assert len(block) == 8 - block = xtea_encrypt(CROSS_KEY, block, endian=ENDIAN) + try: + block = xtea_encrypt(CROSS_KEY, block, endian=ENDIAN) + except: + LOG.exception("xTEA failure at block %r" % block) + raise fout.write(block) pos += 8 Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-24 22:11:48 UTC (rev 71) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-24 23:17:08 UTC (rev 72) @@ -168,7 +168,7 @@ def __init__(self, *args, **kwargs): pass - def __call__(self, value): + def __call__(self, value, debug="unknown"): return value class MinMax(Constrain): @@ -197,13 +197,13 @@ self._min = min self._max = max - def __call__(self, value): + def __call__(self, value, debug="unknown"): if not isinstance(value, (int, float)): - raise ConstrainError(type(value)) + raise ConstrainError("%s: %s" % (debug,type(value))) if value < self._min: - raise ConstrainError("%s < min %s" % (value, self._min)) + raise ConstrainError("%s: %s < min %s" % (debug, value, self._min)) if value > self._max: - raise ConstrainError("%s > max %s" % (value, self._max)) + raise ConstrainError("%s: %s > max %s" % (debug, value, self._max)) return value class VideoConstrain(MinMax): @@ -240,9 +240,10 @@ def __init__(self, values): self._values = values - def __call__(self, value): + def __call__(self, value, debug="unknown"): if not value in self._values: - raise ConstrainError("%s not in %s" % (value, str(self._values))) + raise ConstrainError("%s: %s not in %s" % + (debug, value, str(self._values))) return value class _VideoModes(object): @@ -312,7 +313,6 @@ self._filedata = {} self._newdata = {} self._order = [] - self.clear() self._fpath = None def clear(self): @@ -353,10 +353,13 @@ raise ValueError("Full path not set") bak = orig + ".bak" new = orig + ".new" - shutils.copyfile(orig, bak) # make backup + shutil.copyfile(orig, bak) # make backup self.writeEncFile(new) # write new os.unlink(orig) # stupid windows can't perform an atomic rename os.rename(new, orig) # move new to orig + + # reread the file again + self.parseEncFile(self._fpath) def parseEncFile(self, fd_name): """Read and parse file (fd or file name) @@ -395,7 +398,11 @@ newkey = key self._order.append(newkey) value = line[len(key)+1:].strip() - value = constrain(convert(value)) + try: + value = constrain(convert(value), debug=key) + except: # catch all + LOG.exception("convert/constrain error") + raise self._filedata[newkey] = value break if not found: @@ -427,7 +434,11 @@ #key = newkey.replace('__', ' ') #key = key.replace('_', '.') convert, constrain = self._options[key] - value = constrain(convert(value)) + try: + value = constrain(convert(value), debug=key) + except: # catch all + LOG.exception("convert/constrain error") + raise out.append("%s %s" % (key, value)) out.append('') # new line at EOF return '\n'.join(out) @@ -445,6 +456,9 @@ encryptWDYS(data, fd) if close: fd.close() + else: + fd.flush() + fd.seek(0) def _get(self, name): """get descriptor helper @@ -467,6 +481,11 @@ """set descriptor helper for % sliders """ self._newdata[name] = float(value / 100.0) + + def _setboolint(self, name, value): + """ + """ + self._newdata[name] = int(bool(value)) class AudioIni(ConfFile): _filename = 'audio.ini' @@ -484,7 +503,7 @@ 'Audio.SetChannelVolume GUI' : (FloatString, MinMax(0.0, 1.0)), # 0-100%, no ui # microphon missing -> OS mixer } - _devices = ['Generic Software', 'Generic Hardware'] + _devices = ['"Generic Software"', '"Generic Hardware"'] # plus maybe a custom OpenAL v1.1 device def parserDoneHook(self): @@ -533,13 +552,13 @@ lambda self, v: self._set('Audio.UseEAX', v), ) mute = property(lambda self: self._get('Audio.MuteAll'), - lambda self, v: self._set('Audio.MuteAll', v), + lambda self, v: self._setboolint('Audio.MuteAll', v), ) priority = property(lambda self: self._get('Audio.SetPriorityCutoff'), lambda self, v: self._set('Audio.SetPriorityCutoff', v), ) enablevoice = property(lambda self: self._get('Audio.EnableVoiceRecording'), - lambda self, v: self._set('Audio.EnableVoiceRecording', v), + lambda self, v: self._setboolint('Audio.EnableVoiceRecording', v), ) device = property(_getDevice, _setDevice) fx = property(lambda self: self._getp('Audio.SetChannelVolume SoundFX'), @@ -600,7 +619,7 @@ lambda self, v: self._set('Quality.Level', v), ) shadow_enabled = property(lambda self: self._get('Graphics.Shadow.Enable'), - lambda self, v: self._set('Graphics.Shadow.Enable', v), + lambda self, v: self._setboolint('Graphics.Shadow.Enable', v), ) shadow = property(lambda self: self._getp('Graphics.Shadow.VisibleDistance'), lambda self, v: self._setp('Graphics.Shadow.VisibleDistance', v), Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-24 22:11:48 UTC (rev 71) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-24 23:17:08 UTC (rev 72) @@ -79,9 +79,9 @@ @param event close event (QCloseEvent) """ - if self._dirty: - event.reject() - return False + #if self._dirty: + # event.reject() + # return False self._systray_close() event.accept() @@ -158,7 +158,9 @@ def on_graphicsini_save(self): """SIGNAL graphicsini_save() """ - self._notimplemented() + #self._notimplemented() + self._graphics_ini.write() + self.setDirty(False) def _graphicsini_setstate(self): """Set sliders according to graphics ini settings @@ -185,6 +187,7 @@ # XXX: fixme txt = videoModes.getVidModeHuman(idx) self.lb_screenres.setText(QtCore.QString(txt)) + self._graphics_ini.screenres = idx @signalLogDecorator(LOG) @pyqtSignature("int") @@ -199,47 +202,56 @@ def on_sl_gra_quality_valueChanged(self, idx): """SIGNAL: valueChanged (int) """ + self._graphics_ini.quality = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_texture_valueChanged(self, idx): """SIGNAL: valueChanged (int) """ + self._graphics_ini.texture = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_antialias_valueChanged(self, idx): """SIGNAL: valueChanged (int) """ + self._graphics_ini.antialias = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_anisotropic_valueChanged(self, idx): """SIGNAL: valueChanged (int) """ + self._graphics_ini.anisotropic = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_shadow_valueChanged(self, idx): """SIGNAL: valueChanged (int) """ + self._graphics_ini.shadow = idx + @signalLogDecorator(LOG) @pyqtSignature("int") - def on_cb_gra_windowed_stateChanged (self, state): + def on_cb_gra_windowed_stateChanged(self, state): """SIGNAL: stateChanged(int) """ + self._graphics_ini.windowed = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_vsync_stateChanged (self, state): """SIGNAL: stateChanged(int) """ + self._graphics_ini.vsync = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_shadow_stateChanged (self, state): """SIGNAL: stateChanged(int) """ + self._graphics_ini.shadow_enabled = state # ************************************************************************ # audio settings @@ -281,13 +293,16 @@ def on_audioini_save(self): """SIGNAL audioini_save() """ - self._notimplemented() + #self._notimplemented() + self._audio_ini.write() + self.setDirty(False) # urks def _audioini_setstate(self): """Set sliders according to audio ini settings """ aini = self._audio_ini self.sl_aud_device.setMaximum(aini.numberOfDevices()-1) + self.sl_aud_npc.setValue(aini.npc) self.sl_aud_music.setValue(aini.music) self.sl_aud_fx.setValue(aini.fx) @@ -303,18 +318,74 @@ def on_sl_aud_device_valueChanged(self, idx): """SIGNAL: valueChanged (int) """ - # TODO: fixme + self._audio_ini.device = idx txt = self._audio_ini.getDeviceName(idx) - self.lb_aud_device.setText(QtCore.QString(txt)) - + self.lb_aud_device.setText(QtCore.QString(txt[1:-1])) + @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_device_sliderMoved(self, idx): """SIGNAL: sliderMoved(int) """ txt = self._audio_ini.getDeviceName(idx) - self.lb_aud_device.setText(QtCore.QString(txt)) + self.lb_aud_device.setText(QtCore.QString(txt[1:-1])) + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_sl_aud_npc_valueChanged(self, idx): + """SIGNAL: valueChanged (int) + """ + self._audio_ini.npc = idx + + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_sl_aud_music_valueChanged(self, idx): + """SIGNAL: valueChanged (int) + """ + self._audio_ini.music = idx + + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_sl_aud_fx_valueChanged(self, idx): + """SIGNAL: valueChanged (int) + """ + self._audio_ini.fx = idx + + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_sl_aud_ambience_valueChanged(self, idx): + """SIGNAL: valueChanged (int) + """ + self._audio_ini.ambience = idx + + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_sl_aud_priority_valueChanged(self, idx): + """SIGNAL: valueChanged (int) + """ + self._audio_ini.priority = idx + + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_cb_aud_eax_stateChanged (self, state): + """SIGNAL: stateChanged(int) + """ + self._audio_ini.eax = state + + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_cb_aud_mute_stateChanged (self, state): + """SIGNAL: stateChanged(int) + """ + self._audio_ini.mute = state + + @signalLogDecorator(LOG) + @pyqtSignature("int") + def on_cb_aud_voicechat_stateChanged (self, state): + """SIGNAL: stateChanged(int) + """ + self._audio_ini.voicechat = state + # ************************************************************************ # time zones This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-25 13:50:47
|
Revision: 74 http://pymoul.svn.sourceforge.net/pymoul/?rev=74&view=rev Author: tiran Date: 2007-01-25 05:50:46 -0800 (Thu, 25 Jan 2007) Log Message: ----------- Logging improvements: Now logs to a file, too Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/darwin/__init__.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/osdependent/win32/__init__.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-01-25 04:05:27 UTC (rev 73) +++ pymoul/trunk/src/moul/config/__init__.py 2007-01-25 13:50:46 UTC (rev 74) @@ -39,30 +39,48 @@ if __WIN32__: from moul.osdependent.win32 import ( getMoulUserDataDir, - getPyMoulIniDir, + getPyMoulDataDir as _getPyMoulDataDir, _startMOUL, EXEC_NAME ) elif __LINUX__: from moul.osdependent.linux import ( getMoulUserDataDir, - getPyMoulIniDir, + getPyMoulDataDir as _getPyMoulDataDir, _startMOUL, EXEC_NAME ) elif __MACOSX__: from moul.osdependent.darwin import ( getMoulUserDataDir, - getPyMoulIniDir, + getPyMoulDataDir as _getPyMoulDataDir, _startMOUL, EXEC_NAME ) else: raise RuntimeError('platform %s not supported' % sys.platform) +def getPyMoulDataDir(check=False): + """Get pyMoul data directory + + The directory contains log files, ini files and other local stuff + """ + datadir = _getPyMoulDataDir() + if check: + if os.path.abspath(datadir) != datadir: + raise ValueError("Datadir is not absolute %s" % datadir) + if not os.path.isdir(datadir): + parent = os.path.abspath(os.path.join(datadir, os.pardir)) + if not os.path.isdir(parent): + raise ValueError("Datadir's parent dir does not exist: %s" + % par) + else: + LOG.debug("Creating pyMoul data dir %s" % datadir) + os.mkdir(datadir, 0750) + LOG.debug("Using pyMoul data dir %s" % datadir) + return datadir + ## configuration - - class Configuration(dict): def __new__(cls, *args, **kwargs): self = dict.__new__(cls, *args, **kwargs) @@ -161,8 +179,8 @@ def getMoulUserDataDir(self): return getMoulUserDataDir() - def getPyMoulIniDir(self): - return getPyMoulIniDir() + def getPyMoulDataDir(self): + return getPyMoulDataDir() def lookupDir(self, name): """Lookup MOUL directory @@ -174,7 +192,7 @@ path = path.replace('/', os.sep) map = {'installdir' : self.getMoulInstallDir(), 'datadir' : self.getMoulUserDataDir(), - 'pymouldir' : self.getPyMoulIniDir(), + 'pymouldir' : self.getPyMoulDataDir(), } fullpath = path % map #self._cache[name] = fullpath Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-25 04:05:27 UTC (rev 73) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-25 13:50:46 UTC (rev 74) @@ -335,6 +335,8 @@ """ if self._fpath is not None: raise ValueError("File already open") + if not os.path.isdir(path): + raise OSError("Directory not found %s" % path) self._fpath = os.path.join(path, self._filename) self.parseEncFile(self._fpath) Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-25 04:05:27 UTC (rev 73) +++ pymoul/trunk/src/moul/log.py 2007-01-25 13:50:46 UTC (rev 74) @@ -24,27 +24,65 @@ __all__ = ['LOG', 'getLogger', 'signalLogDecorator'] import logging +from logging import Formatter +from logging import handlers import os import sys from moul.metadata import __version__ as moul_version +# alias +getLogger = logging.getLogger + # copied from moul.config to prevent circular imports __FROZEN__ = bool(getattr(sys, 'frozen', False)) __LOG_SIGNALS__ = not __FROZEN__ - if __FROZEN__: level = logging.ERROR else: level = logging.DEBUG -logging.basicConfig(level=level, - format='%(asctime)s %(name)-10s %(levelname)-7s %(message)s', - #datefmt='%a, %d %b %Y %H:%M:%S' - datefmt='%m-%d %H:%M:%S' - ) -LOG = logging.getLogger('pyMoul') -getLogger = logging.getLogger +format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', + #'%a, %d %b %Y %H:%M:%S' + '%m-%d %H:%M:%S') +root = getLogger() +root.setLevel(level) +# Add streaming handler for sys.stderr +shdlr = logging.StreamHandler(sys.stderr) +shdlr.setFormatter(format) +shdlr.setLevel(level) +root.addHandler(shdlr) + +# setup a memory handler to store records before we have the infrastructure +# to log events to a file +mhdlr = handlers.MemoryHandler(capacity=16*1024) # MemoryHandler doesn't flush w/o a target +mhdlr.setFormatter(format) +mhdlr.setLevel(logging.DEBUG) +root.addHandler(mhdlr) + +# DEBUG system infos +LOG = getLogger('pyMoul') +LOG.debug("pyMoul version: %s" % moul_version) +LOG.debug("Python: %s" % repr(sys.version_info)) +LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) +LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) + +# now get the pymoul userdata dir +from moul.config import getPyMoulDataDir +logFile = os.path.join(getPyMoulDataDir(check=True), 'pymoul.log') +LOG.debug("Adding file logger: %s" % logFile) +fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) +fhdlr.setFormatter(format) +fhdlr.setLevel(logging.DEBUG) +root.addHandler(fhdlr) +fhdlr.doRollover() + +# flush and remove remove memory handler +mhdlr.setTarget(fhdlr) +mhdlr.flush() +root.removeHandler(mhdlr) +del mhdlr + def signalLogDecorator(__logger__): """Decorator to log signals @@ -65,10 +103,3 @@ else: return func return wrapper - -# DEBUG system infos -LOG.debug("pyMoul version: %s" % moul_version) -LOG.debug("Python: %s" % repr(sys.version_info)) -LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) -LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) - Modified: pymoul/trunk/src/moul/osdependent/darwin/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-25 04:05:27 UTC (rev 73) +++ pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-25 13:50:46 UTC (rev 74) @@ -37,7 +37,7 @@ """ moul_data = os.path.join(HOME, MOUL_DIR) -def getPyMoulIniDir(): +def getPyMoulDataDir(): """Get path to the pyMoul ini directory """ inidir= os.path.join(HOME, '.pymoul') Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-25 04:05:27 UTC (rev 73) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-25 13:50:46 UTC (rev 74) @@ -36,9 +36,9 @@ The MOUL data directory contains log files, chatlogs, KI images and many more things. """ - moul_data = os.path.join(HOME, MOUL_DIR) + return os.path.join(HOME, MOUL_DIR) -def getPyMoulIniDir(): +def getPyMoulDataDir(): """Get path to the pyMoul ini directory """ inidir= os.path.join(HOME, '.pymoul') Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-25 04:05:27 UTC (rev 73) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-25 13:50:46 UTC (rev 74) @@ -41,7 +41,7 @@ moul_data = os.path.join(mydoc, MOUL_DIR) return moul_data -def getPyMoulIniDir(): +def getPyMoulDataDir(): """Get path to the pyMoul ini file """ app_data = get_appdata() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-25 14:21:25
|
Revision: 75 http://pymoul.svn.sourceforge.net/pymoul/?rev=75&view=rev Author: tiran Date: 2007-01-25 06:21:20 -0800 (Thu, 25 Jan 2007) Log Message: ----------- More logging Modified Paths: -------------- pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/win32/__init__.py Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-25 13:50:46 UTC (rev 74) +++ pymoul/trunk/src/moul/log.py 2007-01-25 14:21:20 UTC (rev 75) @@ -23,11 +23,12 @@ __all__ = ['LOG', 'getLogger', 'signalLogDecorator'] +import os +import sys +import platform import logging -from logging import Formatter from logging import handlers -import os -import sys + from moul.metadata import __version__ as moul_version # alias @@ -41,7 +42,7 @@ else: level = logging.DEBUG -format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', +format = logging.Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', #'%a, %d %b %Y %H:%M:%S' '%m-%d %H:%M:%S') root = getLogger() @@ -66,6 +67,9 @@ LOG.debug("Python: %s" % repr(sys.version_info)) LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) +LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" + % platform.uname()) +LOG.debug("platform name: %s" % platform.platform(True)) # now get the pymoul userdata dir from moul.config import getPyMoulDataDir Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-25 13:50:46 UTC (rev 74) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-25 14:21:20 UTC (rev 75) @@ -27,7 +27,6 @@ from moul.osdependent.win32.winpath import get_homedir from moul.osdependent.win32.winpath import get_appdata - MOUL_DIR = "Uru Live" EXEC_NAME = "UruLauncher.exe" This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 02:16:38
|
Revision: 79 http://pymoul.svn.sourceforge.net/pymoul/?rev=79&view=rev Author: tiran Date: 2007-01-25 18:16:36 -0800 (Thu, 25 Jan 2007) Log Message: ----------- Lot's of changes: Cleanup logging New singleapp module added Restrict to one instance of moulqt Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/file/tests/test_localization.py pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/qt/moulqt.py pymoul/trunk/src/moul/qt/ui/mainwindow.py Added Paths: ----------- pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/osdependent/tests/ pymoul/trunk/src/moul/osdependent/tests/__init__.py pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/config/__init__.py 2007-01-26 02:16:36 UTC (rev 79) @@ -19,8 +19,9 @@ """ import os import sys +from logging import getLogger -from moul.log import LOG +LOG = getLogger('pyMoul') # a program under py2exe is sys.frozen __FROZEN__ = bool(getattr(sys, 'frozen', False)) Modified: pymoul/trunk/src/moul/file/tests/test_localization.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_localization.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/file/tests/test_localization.py 2007-01-26 02:16:36 UTC (rev 79) @@ -41,13 +41,13 @@ def test_parseLocDir(self): parseLocDirectory(base) - key = (u'testage', u'testset', u'testelement', u'english') + key = (u'english', u'testage', u'testset', u'testelement') self.failUnless(key in translationRegistry, translationRegistry.keys()) self.failUnlessEqual(len(translationRegistry), 1) def test_parseLoc(self): parseLoc(os.path.join(base, 'test.loc')) - key = (u'testage', u'testset', u'testelement', u'english') + key = (u'english', u'testage', u'testset', u'testelement') self.failUnless(key in translationRegistry, translationRegistry.keys()) self.failUnlessEqual(len(translationRegistry), 1) Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-26 02:16:36 UTC (rev 79) @@ -161,7 +161,7 @@ Constrain() is a NOOP >>> c = Constrain('foo', False, object) - >>> c('dummy') + >>> c('dummy', debug="name") 'dummy' """ __slots__ = () @@ -175,21 +175,21 @@ """Min / max constrain >>> c = MinMax(1, 10) - >>> c(1) + >>> c(1, debug="name") 1 - >>> c(10) + >>> c(10, debug="name") 10 - >>> c(11) + >>> c(11, debug="name") Traceback (most recent call last): ... - ConstrainError: 11 > max 10 - >>> c(-1) + ConstrainError: name: 11 > max 10 + >>> c(-1, debug="name") Traceback (most recent call last): ... - ConstrainError: -1 < min 1 + ConstrainError: name: -1 < min 1 >>> c = MinMax(0, 1) - >>> c(0.5) + >>> c(0.5, debug="name") 0.5 """ __slots__ = ('_min', '_max') @@ -210,16 +210,16 @@ """Constrain for video mode indexes >>> v = VideoConstrain() - >>> v(0) + >>> v(0, debug="name") 0 - >>> v(-1) + >>> v(-1, debug="name") Traceback (most recent call last): ... - ConstrainError: -1 < min 0 - >>> v(11) + ConstrainError: name: -1 < min 0 + >>> v(11, debug="name") Traceback (most recent call last): ... - ConstrainError: 11 > max 10 + ConstrainError: name: 11 > max 10 """ def __init__(self): self._min = 0 @@ -229,12 +229,12 @@ """value in list constrain >>> c = Contains((1, 2, 3)) - >>> c(1) + >>> c(1, debug="name") 1 - >>> c(4) + >>> c(4, debug="name") Traceback (most recent call last): ... - ConstrainError: 4 not in (1, 2, 3) + ConstrainError: name: 4 not in (1, 2, 3) """ __slots__ = ('_values') def __init__(self, values): Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/log.py 2007-01-26 02:16:36 UTC (rev 79) @@ -27,17 +27,23 @@ import sys import platform import logging +from logging import Formatter from logging import handlers - from moul.metadata import __version__ as moul_version -# alias getLogger = logging.getLogger # copied from moul.config to prevent circular imports __FROZEN__ = bool(getattr(sys, 'frozen', False)) __LOG_SIGNALS__ = not __FROZEN__ +format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', + #'%a, %d %b %Y %H:%M:%S' + '%m-%d %H:%M:%S') +root = getLogger() +root.setLevel(logging.DEBUG) +LOG = getLogger('pyMoul') + class LoggingStdout(object): """Replacement for stdout/stderr IO """ @@ -52,18 +58,50 @@ if value: self._logfunc(value) -format = logging.Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', - #'%a, %d %b %Y %H:%M:%S' - '%m-%d %H:%M:%S') -root = getLogger() -root.setLevel(logging.DEBUG) +mhdlr = None +fhdlr = None +def _installMemoryHdlr(): + """setup a memory handler to store records before we have the + infrastructure to log events to a file + """ + global mhdlr + mhdlr = handlers.MemoryHandler(capacity=4*1024) # MemoryHandler doesn't flush w/o a target + mhdlr.setFormatter(format) + root.addHandler(mhdlr) -# setup a memory handler to store records before we have the infrastructure -# to log events to a file -mhdlr = handlers.MemoryHandler(capacity=16*1024) # MemoryHandler doesn't flush w/o a target -mhdlr.setFormatter(format) -root.addHandler(mhdlr) +def _removeMemoryHdlr(): + """Remove memory handler + """ + global mhdlr + global fhdlr + mhdlr.setTarget(fhdlr) + mhdlr.flush() + root.removeHandler(mhdlr) + del mhdlr +def _installFileHdlr(): + """Install a file handler + """ + global fhdlr + from moul.config import getPyMoulDataDir + logFile = os.path.join(getPyMoulDataDir(check=True), 'pymoul.log') + LOG.debug("Adding file logger: %s" % logFile) + fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) + fhdlr.setFormatter(format) + root.addHandler(fhdlr) + fhdlr.doRollover() + +def _systemInfo(): + LOG.debug("pyMoul version: %s" % moul_version) + LOG.debug("Python: %s" % repr(sys.version_info)) + LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) + LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) + LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" + % platform.uname()) + LOG.debug("platform name: %s" % platform.platform(True)) + +# no setup the logging stuff! + if not __FROZEN__: # Add streaming handler to sys.stderr. # Only log to stderr when the program is not frozen! @@ -71,37 +109,14 @@ shdlr.setFormatter(format) root.addHandler(shdlr) else: + _installMemoryHdlr() # Redirect stdout and stderr to logger when running as frozen app sys.stdout = LoggingStdout(getLogger('stdout').info) - print "Stdout redirected" sys.stderr = LoggingStdout(getLogger('stderr').error) - print >>sys.stderr, "Stderr redirected" + _systemInfo() + _installFileHdlr() + _removeMemoryHdlr() -# DEBUG system infos -LOG = getLogger('pyMoul') -LOG.debug("pyMoul version: %s" % moul_version) -LOG.debug("Python: %s" % repr(sys.version_info)) -LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) -LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) -LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" - % platform.uname()) -LOG.debug("platform name: %s" % platform.platform(True)) - -# now get the pymoul userdata dir -from moul.config import getPyMoulDataDir -logFile = os.path.join(getPyMoulDataDir(check=True), 'pymoul.log') -LOG.debug("Adding file logger: %s" % logFile) -fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) -fhdlr.setFormatter(format) -root.addHandler(fhdlr) -fhdlr.doRollover() - -# flush and remove memory handler -mhdlr.setTarget(fhdlr) -mhdlr.flush() -root.removeHandler(mhdlr) -del mhdlr - def signalLogDecorator(__logger__): """Decorator to log signals Added: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 02:16:36 UTC (rev 79) @@ -0,0 +1,184 @@ +# pyMoul - Python interface to Myst Online URU Live +# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> + +# This program 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 program 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +"""Simple single instance application + +Includes portalocker code with minor tweaks for Python 2.4+ + Author: Jonathan Feinberg <jd...@po...> + Version: $Id: portalocker.py,v 1.3 2001/05/29 18:47:55 Administrator Exp $ + http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65203 + +Boiler plate +>>> import sys +>>> from shutil import rmtree +>>> from subprocess import call +>>> tmpdir = tempfile.mkdtemp() +>>> testfile = os.path.join(tmpdir, 'test.lck') +>>> if os.name == 'nt': +... rm = "del" +... else: +... rm = "rm" + +Create a file and lock it for this process +>>> flags = LOCK_SH | LOCK_NB +>>> fd1 = open(testfile, 'w') +>>> fn1 = fd1.fileno() +>>> lock(fd1, flags) +>>> fd1.write('testdata') + +Try to delete the file from another process +>>> try: +... retcode = call("%s %s" % (rm, testfile)) +... except: +... typ, value, tb = sys.exc_info() +... del tb +... else: +... print "Should have raised an error!" + +On Windows the error is WindowsError based on OSError +>>> issubclass(typ, OSError) or typ +True + +Clean up +>>> unlock(fd1) +>>> fd1.close() +>>> rmtree(tmpdir) + +>>> singleapp = SimpleSingleApp('testapp') +>>> lckfile = singleapp.lckfile +>>> if os.path.isfile(lckfile): +... os.unlink(fpath) +>>> path, pid = singleapp.acquire() +>>> path == lckfile +True +>>> os.path.isfile(lckfile) +True +>>> singleapp.checkLocked() is None +True +>>> singleapp.release() +>>> os.path.isfile(lckfile) +False +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import os +import getpass +import tempfile +import atexit + +TEMPDIR = tempfile.gettempdir() +USER = getpass.getuser() +PID = os.getpid() + +if os.name == 'nt': + import win32con + import win32file + import pywintypes + LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK + LOCK_SH = 0 # the default + LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY + lowbits, highbits = 0, -65536 +elif os.name == 'posix': + import fcntl + LOCK_EX = fcntl.LOCK_EX + LOCK_SH = fcntl.LOCK_SH + LOCK_NB = fcntl.LOCK_NB +else: + raise RuntimeError("PortaLocker only defined for nt and posix platforms") + +if os.name == 'nt': + def lock(file, flags): + hfile = win32file._get_osfhandle(file.fileno()) + return win32file.LockFileEx(hfile, flags, lowbits, highbits, pywintypes.OVERLAPPED()) + def unlock(file): + hfile = win32file._get_osfhandle(file.fileno()) + return win32file.UnlockFileEx(hfile, lowbits, highbits, pywintypes.OVERLAPPED()) +elif os.name =='posix': + def lock(file, flags): + return fcntl.flock(file.fileno(), flags) + def unlock(file): + return fcntl.flock(file.fileno(), fcntl.LOCK_UN) + +class SingleAppError(OSError): + pass + +class SimpleSingleApp(object): + """A simple single instance application implemementation + """ + flags = LOCK_SH | LOCK_NB + + def __init__(self, appname, path=TEMPDIR, user=USER, pid=PID, ext='.lck', + *args): + self.appname = appname + self.user = user + self.path = path + self.args = args + self.pid = pid + self.ext = ext + self._fd = None + self.lckfile = self._genFilename() + # register atexit function + atexit.register(self.release) + + def acquire(self): + """Acquire lock + + May raise an OSError + """ + try: + self._fd = open(self.lckfile, 'w') + self._fd.write(str(self.pid)) + self._fd.flush() + lock(self._fd, self.flags) + except (OSError, IOError): + self._fd.close() + self._fd = None + raise SingleAppError("Another instance is already running") + return self.lckfile, self.pid + + def release(self): + """Release lock + """ + try: + unlock(self._fd) + except (SystemError, SyntaxError): + raise + except: + pass + if self._fd: + self._fd.close() + if os.path.isfile(self.lckfile): + os.unlink(self.lckfile) + + def checkLocked(self): + """Check if another process has a lock + """ + try: + fd = open(self.lckfile, 'a+') + fd.close() + except OSError: + return True + else: + if self._fd: + return None + return False + + def _genFilename(self): + fname = '_'.join((self.appname, self.user,) + self.args) + self.ext + return os.path.join(self.path, fname) Property changes on: pymoul/trunk/src/moul/osdependent/singleapp.py ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/osdependent/tests/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/__init__.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/tests/__init__.py 2007-01-26 02:16:36 UTC (rev 79) @@ -0,0 +1,22 @@ +# pyMoul - Python interface to Myst Online URU Live +# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> + +# This program 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 program 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +""" +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" Property changes on: pymoul/trunk/src/moul/osdependent/tests/__init__.py ___________________________________________________________________ Name: svn:eol-style + native Added: pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py 2007-01-26 02:16:36 UTC (rev 79) @@ -0,0 +1,39 @@ +# pyMoul - Python interface to Myst Online URU Live +# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> + +# This program 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 program 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +"""moul.osdependent.singleapp +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import unittest +from doctest import DocTestSuite + +from moul.osdependent.singleapp import SimpleSingleApp +from moul.osdependent.singleapp import lock +from moul.osdependent.singleapp import unlock +from moul.osdependent.singleapp import LOCK_EX, LOCK_SH, LOCK_NB + +def test_suite(): + return unittest.TestSuite(( + DocTestSuite('moul.osdependent.singleapp'), + )) + +if __name__ == '__main__': + unittest.main(defaultTest="test_suite") + Property changes on: pymoul/trunk/src/moul/osdependent/tests/test_singleapp.py ___________________________________________________________________ Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 02:16:36 UTC (rev 79) @@ -27,9 +27,24 @@ from PyQt4 import QtGui from moul.qt.mainwindow import MainWindow +from moul.osdependent.singleapp import SimpleSingleApp +from moul.config import getPyMoulDataDir def main(*args): app = QtGui.QApplication(*args) + singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir()) + try: + singleapp.acquire() + except OSError: + mb = QtGui.QMessageBox() + mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) + mb.setIcon(QtGui.QMessageBox.Critical) + mb.setWindowTitle(app.trUtf8("Already running")) + mb.setText(app.trUtf8("""An instance of pyMoul QT is already running!""")) + mb.setStandardButtons(QtGui.QMessageBox.Close) + mb.exec_() + sys.exit(1) + mainWindow = MainWindow() mainWindow.show() return app.exec_() Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-25 18:54:52 UTC (rev 78) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-26 02:16:36 UTC (rev 79) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Thu Jan 25 19:53:15 2007 +# Created: Thu Jan 25 19:55:32 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 14:17:52
|
Revision: 80 http://pymoul.svn.sourceforge.net/pymoul/?rev=80&view=rev Author: tiran Date: 2007-01-26 06:17:50 -0800 (Fri, 26 Jan 2007) Log Message: ----------- More cleanups Use WMI (f.... slow) to get process informations under Linux. Memo to me: put it inside a thread Moved os specific stuff around Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/osdependent/processinfo.py pymoul/trunk/src/moul/osdependent/win32/__init__.py pymoul/trunk/src/moul/qt/ui/mainwindow.py Added Paths: ----------- pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py pymoul/trunk/src/moul/osdependent/win32/wmi.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/config/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -18,70 +18,13 @@ """Configuration package """ import os -import sys -from logging import getLogger -LOG = getLogger('pyMoul') +from moul.osdependent import getMoulUserDataDir +from moul.osdependent import getPyMoulDataDir -# a program under py2exe is sys.frozen -__FROZEN__ = bool(getattr(sys, 'frozen', False)) -# OS stuff -__WIN32__ = sys.platform.startswith('win32') # win64, cygwin? -__LINUX__ = sys.platform.startswith('linux2') -__MACOSX__ = sys.platform.startswith('darwin') -__UNIX__ = __LINUX__ or __MACOSX__ - -LOG.debug("sys.frozen status: %s" % __FROZEN__) -LOG.debug("OS detected: win32: %s, Linux: %s, Mac: %s, Un*x: %s" % - (__WIN32__, __LINUX__, __MACOSX__, __UNIX__)) - _marker=object() -# XXX: what about cygwin, bsd and others? -if __WIN32__: - from moul.osdependent.win32 import ( - getMoulUserDataDir, - getPyMoulDataDir as _getPyMoulDataDir, - _startMOUL, - EXEC_NAME - ) -elif __LINUX__: - from moul.osdependent.linux import ( - getMoulUserDataDir, - getPyMoulDataDir as _getPyMoulDataDir, - _startMOUL, - EXEC_NAME - ) -elif __MACOSX__: - from moul.osdependent.darwin import ( - getMoulUserDataDir, - getPyMoulDataDir as _getPyMoulDataDir, - _startMOUL, - EXEC_NAME - ) -else: - raise RuntimeError('platform %s not supported' % sys.platform) -def getPyMoulDataDir(check=False): - """Get pyMoul data directory - - The directory contains log files, ini files and other local stuff - """ - datadir = _getPyMoulDataDir() - if check: - if os.path.abspath(datadir) != datadir: - raise ValueError("Datadir is not absolute %s" % datadir) - if not os.path.isdir(datadir): - parent = os.path.abspath(os.path.join(datadir, os.pardir)) - if not os.path.isdir(parent): - raise ValueError("Datadir's parent dir does not exist: %s" - % par) - else: - LOG.debug("Creating pyMoul data dir %s" % datadir) - os.mkdir(datadir, 0750) - LOG.debug("Using pyMoul data dir %s" % datadir) - return datadir - -## configuration +# configuration class Configuration(dict): def __new__(cls, *args, **kwargs): self = dict.__new__(cls, *args, **kwargs) Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/log.py 2007-01-26 14:17:50 UTC (rev 80) @@ -33,9 +33,7 @@ getLogger = logging.getLogger -# copied from moul.config to prevent circular imports __FROZEN__ = bool(getattr(sys, 'frozen', False)) -__LOG_SIGNALS__ = not __FROZEN__ format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', #'%a, %d %b %Y %H:%M:%S' @@ -92,6 +90,7 @@ fhdlr.doRollover() def _systemInfo(): + from moul.osdependent import __INFO__ LOG.debug("pyMoul version: %s" % moul_version) LOG.debug("Python: %s" % repr(sys.version_info)) LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) @@ -99,6 +98,9 @@ LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" % platform.uname()) LOG.debug("platform name: %s" % platform.platform(True)) + LOG.debug("sys.frozen status: %s" % __FROZEN__) + LOG.debug("OS detected: win32: %r, cygwin: %r, Linux: %r, Mac: %r, BSD: %r, " + "posix/Un*x: %r, NT: %r" % __INFO__) # no setup the logging stuff! @@ -108,6 +110,7 @@ shdlr = logging.StreamHandler(sys.stderr) shdlr.setFormatter(format) root.addHandler(shdlr) + #_systemInfo() else: _installMemoryHdlr() # Redirect stdout and stderr to logger when running as frozen app @@ -117,6 +120,7 @@ _installFileHdlr() _removeMemoryHdlr() +__LOG_SIGNALS__ = not __FROZEN__ def signalLogDecorator(__logger__): """Decorator to log signals Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -15,8 +15,118 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # Temple Place, Suite 330, Boston, MA 02111-1307 USA # +"""OS dependent code for linux, mac and win32 + +>>> pids = getCurrentPids() +>>> len(pids) > 1 +True + +>>> pids = getCurrentPidNames() +>>> found = False +>>> for pid, name in pids.items(): +... if name.lower().startswith('python'): +... found = True +>>> found +True """ -""" __author__ = "Christian Heimes" __version__ = "$Id$" __revision__ = "$Revision$" + +import os +import sys + +# a program under py2exe is sys.frozen +__FROZEN__ = bool(getattr(sys, 'frozen', False)) +# OS stuff +_plat = sys.platform.startswith +__WIN32__ = _plat('win32') # win64, cygwin? +__CYGWIN__ = _plat('cygwin') +__LINUX__ = _plat('linux2') +__MACOSX__ = _plat('darwin') +__BSD__ = _plat('freebsd') or _plat('netbsd') or _plat('openbsd') +__POSIX__ = os.name.lower() == 'posix' +__NT__ = os.name.lower() == 'nt' +__INFO__ = (__WIN32__, __CYGWIN__, __LINUX__, __MACOSX__, __BSD__, + __POSIX__, __NT__) + +# names to import: from moul.osdependent.ID import NAME (as NAME) +NAMES = ('getMoulUserDataDir', + ('getPyMoulDataDir', '_getPyMoulDataDir'), # as + '_startMOUL', 'EXEC_NAME', + 'getCurrentPids', 'getCurrentPidNames', + ) + +_marker = object() + +def _importHelper(modname, names=None, target=None): + """Import a list of variables from a module + + >>> mod = _importHelper('moul.osdependent') + >>> mod == _thismodule or mod + True + >>> vars = _importHelper('moul.osdependent', ('_marker', )) + >>> vars[0] is _marker + True + >>> class Target(object): + ... pass + >>> target = Target() + >>> vars = _importHelper('moul.osdependent', ('_marker', ), target=target) + >>> target._marker is _marker + True + >>> vars[0] is _marker + True + + >>> vars = _importHelper('moul.osdependent', (('_marker', 'another'), ), + ... target=target) + >>> target.another is _marker + True + >>> vars[0] is _marker + True + """ + mod = __import__(modname, globals(), locals(), ['']) + if names is None: + return mod + else: + vars = [] + for name in names: + if isinstance(name, (tuple, list)): + name, nameas = name + else: + nameas = name + var = getattr(mod, name) + vars.append(var) + if target is not None: + setattr(target, nameas, var) + return vars + +# XXX: what about cygwin, bsd and others? +_thismodule = sys.modules[__name__] +if __WIN32__: + _importHelper('moul.osdependent.win32', NAMES, target=_thismodule) +elif __LINUX__: + _importHelper('moul.osdependent.linux', NAMES, target=_thismodule) +elif __MACOSX__: + _importHelper('moul.osdependent.darwin', NAMES, target=_thismodule) +else: + raise RuntimeError('platform %s not supported' % sys.platform) + +def getPyMoulDataDir(check=False): + """Get pyMoul data directory + + The directory contains log files, ini files and other local stuff + """ + datadir = _getPyMoulDataDir() + if check: + if os.path.abspath(datadir) != datadir: + raise ValueError("Datadir is not absolute %s" % datadir) + if not os.path.isdir(datadir): + parent = os.path.abspath(os.path.join(datadir, os.pardir)) + if not os.path.isdir(parent): + raise ValueError("Datadir's parent dir does not exist: %s" + % par) + else: + LOG.debug("Creating pyMoul data dir %s" % datadir) + os.mkdir(datadir, 0750) + LOG.debug("Using pyMoul data dir %s" % datadir) + return datadir Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -53,3 +53,52 @@ path = os.path.join(installdir, EXEC_NAME) args = (EXEC_NAME,) + args return os.spawnv(mode, path, args) + +# process info +# based on http://gelb.bcom.at/trac/misc/browser/processinfo + +def getCurrentPids(): + """Returns current process ids + """ + pids = [] + for fname in os.listdir("/proc"): + if os.path.isdir(os.path.join("/proc", fname)): + try: + pids.append(int(fname)) + except ValueError: + continue + return pids + +def getCurrentPidDetails(): + """Returns mapping pid -> detailed informations + """ + mapping = {} + for pid in getCurrentPids(): + try: + try: + # read entiry file to avoid race condition bugs + fd = open('/proc/%i/status' % pid, 'rb') + status = fd.read().split('\n') + finally: + if fd: + fd.close() + except IoError: + continue + details = {} + for line in status: + try: + key, value = line.split(':\t') + except ValueError: + continue + details[key.lower()] = value.strip() + mapping[pid] = details + + return mapping + +def getCurrentPidNames(): + """Returns mapping pid -> name + """ + mapping = {} + for pid, details in getCurrentPidDetails().items(): + mapping[pid] = details.get('name', None) + return mapping Modified: pymoul/trunk/src/moul/osdependent/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/processinfo.py 2007-01-26 14:17:50 UTC (rev 80) @@ -1,219 +1,219 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-1 -*- -"""Process info - -Based on http://gelb.bcom.at/trac/misc/browser/processinfo - -Modified and optimized by Christian Heimes -""" - -import sys -import os - -__all__ = ['PLATFORM', 'UnsupportedOsError', 'getCurrentPids', - 'getCurrentPidNames', 'getCurrentPidDetails'] - -class UnsupportedOsError(NotImplementedError): - pass - -PLATFORM = None - -_plat = sys.platform.startswith -if _plat('win'): - PLATFORM = 'win' - win32process = None - ctypes = None - import csv - try: - import win32process - except ImportError: - try: - import ctypes - except ImportError: - pass -elif _plat('linux2') or _plat('cygwin'): - PLATFORM = 'linux' # Linux or Cygwin -elif _plat('darwin'): - # XXX: unsupported - PLATFORM = 'mac' # Mac OS X -elif _plat('freebsd') or _plat('netbsd') or _plat('openbsd'): - # XXX: unsupported - PLATFORM = 'bsd' # *BSD -else: - PLATFORM = 'unknown' - raise UnsupportedOsError(sys.platform) - -# **************************************************************************** -# Linux / cygwin implementation - -def _getCurrentPids_linux(): - """ - Returns current process-id's. - - :return: list with process-id's. - """ - pids = [] - for fname in os.listdir("/proc"): - if os.path.isdir(os.path.join("/proc", fname)): - try: - pids.append(int(fname)) - except ValueError: - continue - return pids - -def _getCurrentPidDetails_linux(): - """Returns mapping pid -> detailed informations - """ - mapping = {} - for pid in getCurrentPids(): - try: - try: - # read entiry file to avoid race condition bugs - fd = open('/proc/%i/status' % pid, 'rb') - status = fd.read().split('\n') - finally: - if fd: - fd.close() - except IoError: - continue - details = {} - for line in status: - try: - key, value = line.split(':\t') - except ValueError: - continue - details[key.lower()] = value.strip() - mapping[pid] = details - - return mapping - -# **************************************************************************** -# Windows / win32 implementaton - -def _getCurrentPids_win(): - """ - Returns current process-id's. - - :return: List with process-id's. - """ - if win32process is not None: - return list(win32process.EnumProcesses()) - elif ctypes is not None: - # ctypes is installed --> try psapi.dll - psapi = ct.windll.psapi - arr = ct.c_long * 1024 - process_ids = arr() - cb = ct.sizeof(process_ids) - bytes_returned = ct.c_ulong() - psapi.EnumProcesses(ct.byref(process_ids), cb, ct.byref(bytes_returned)) - return sorted(list(set(process_ids))) - else: - csvlines = [] - current_pids = [] - for line in os.popen("tasklist.exe /fo csv /nh"): - line = line.strip() - if line: - csvlines.append(line) - for line in csv.reader(csvlines): - current_pids.append(int(line[1])) - if not csvlines: - raise NotImplementedError("tasklist.exe not found (>WinXP)") - return current_pids - - -def _getCurrentPidDetails_win(): - """ - Returns processinfos. (pid, name and size_kb) - - On Windows-Systems, it uses ``tasklist.exe`` or WMI to list the processes. - On other platforms, it reads the "/proc"-directory. - - :return: Dictionary with PID's as keys and the infos as values in an - inner dictionary. (It is possible, that "size_kb" doesn't exist.): - { - 123: {"name": "bash", "pid": 123}, - 234: {"name": "mc", "pid": 234, "size_kb": 1000}, - } - """ - - retdict = {} - - # tasklist.exe runs on Windows XP and higher. (To parse the ouput of - # tasklist.exe is faster than WMI.) - import csv - csvlines = [] - for line in os.popen("tasklist.exe /fo csv /nh"): - line = line.strip() - if line: - csvlines.append(line) - for line in csv.reader(csvlines): - pid = int(line[1]) - details = { - "name": line[0].decode("cp850"), # to unicode - "pid": pid, - } - value = "".join( - char for char in line[4] - if char.isdigit() - ) - details["size_kb"] = int(value) - retdict[pid] = details - if not csvlines: - try: - from win32com.client import GetObject - # pywin32 is installed --> use WMI - wmi = GetObject('winmgmts:') - processes = wmi.InstancesOf('Win32_Process') - for process in processes: - pid = int(process.Properties_("ProcessId").value) - details = { - "name": process.Properties_("Name").value, - "pid": pid, - "size_kb": int(process.Properties_("WorkingSetSize").value) / 1000 - } - retdict[pid] = details - except ImportError: - raise NotImplementedError("No tasklist.exe and no WMI.") - return retdict - -# **************************************************************************** -# general - -def unsupported(): - """Platform not supported - """ - raise UnsupportedOsError(PLATFORM) - -def getCurrentPidNames(): - """Returns mapping pid -> name - """ - mapping = {} - for pid, details in getCurrentPidDetails().items(): - mapping[pid] = details.get('name', None) - return mapping - -def _initialize(): - mod = sys.modules[__name__] - for name in ('getCurrentPids','getCurrentPidDetails'): - func = getattr(mod, "_%s_%s" % (name, PLATFORM), unsupported) - #func.__name__ = name - setattr(mod, name, func) -_initialize() - -def main(): - """Testing""" - - from pprint import pformat - # Current PIDs - current_pids = getCurrentPids() - print "Current PIDs: %s" % pformat(current_pids) - print - print "Current PID Count: %s" % len(current_pids) - print - - print "Current PIDs with names: %s" % pformat(getCurrentPidNames()) - print - -if __name__ == "__main__": - main() - +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- +"""Process info + +Based on http://gelb.bcom.at/trac/misc/browser/processinfo + +Modified and optimized by Christian Heimes +""" + +import sys +import os + +__all__ = ['PLATFORM', 'UnsupportedOsError', 'getCurrentPids', + 'getCurrentPidNames', 'getCurrentPidDetails'] + +class UnsupportedOsError(NotImplementedError): + pass + +PLATFORM = None + +_plat = sys.platform.startswith +if _plat('win'): + PLATFORM = 'win' + win32process = None + ctypes = None + import csv + try: + import win32process + except ImportError: + try: + import ctypes + except ImportError: + pass +elif _plat('linux2') or _plat('cygwin'): + PLATFORM = 'linux' # Linux or Cygwin +elif _plat('darwin'): + # XXX: unsupported + PLATFORM = 'mac' # Mac OS X +elif _plat('freebsd') or _plat('netbsd') or _plat('openbsd'): + # XXX: unsupported + PLATFORM = 'bsd' # *BSD +else: + PLATFORM = 'unknown' + raise UnsupportedOsError(sys.platform) + +# **************************************************************************** +# Linux / cygwin implementation + +def _getCurrentPids_linux(): + """ + Returns current process-id's. + + :return: list with process-id's. + """ + pids = [] + for fname in os.listdir("/proc"): + if os.path.isdir(os.path.join("/proc", fname)): + try: + pids.append(int(fname)) + except ValueError: + continue + return pids + +def _getCurrentPidDetails_linux(): + """Returns mapping pid -> detailed informations + """ + mapping = {} + for pid in getCurrentPids(): + try: + try: + # read entiry file to avoid race condition bugs + fd = open('/proc/%i/status' % pid, 'rb') + status = fd.read().split('\n') + finally: + if fd: + fd.close() + except IoError: + continue + details = {} + for line in status: + try: + key, value = line.split(':\t') + except ValueError: + continue + details[key.lower()] = value.strip() + mapping[pid] = details + + return mapping + +def _getCurrentPidNames_linux(): + """Returns mapping pid -> name + """ + mapping = {} + for pid, details in getCurrentPidDetails().items(): + mapping[pid] = details.get('name', None) + return mapping + + +# **************************************************************************** +# Windows / win32 implementaton + +def _getCurrentPids_win(): + """ + Returns current process-id's. + + :return: List with process-id's. + """ + if win32process is not None: + return list(win32process.EnumProcesses()) + elif ctypes is not None: + # ctypes is installed --> try psapi.dll + psapi = ct.windll.psapi + arr = ct.c_long * 1024 + process_ids = arr() + cb = ct.sizeof(process_ids) + bytes_returned = ct.c_ulong() + psapi.EnumProcesses(ct.byref(process_ids), cb, ct.byref(bytes_returned)) + return sorted(list(set(process_ids))) + else: + csvlines = [] + current_pids = [] + for line in os.popen("tasklist.exe /fo csv /nh"): + line = line.strip() + if line: + csvlines.append(line) + for line in csv.reader(csvlines): + current_pids.append(int(line[1])) + if not csvlines: + raise NotImplementedError("tasklist.exe not found (>WinXP)") + return current_pids + +def _getCurrentPidNames_win(): + """Returns mapping pid -> name + """ + mapping = {} + for pid, details in getCurrentPidDetails().items(): + mapping[pid] = details.get('name', None) + return mapping + +def _getCurrentPidDetails_win(): + """ + Returns processinfos. (pid, name and size_kb) + """ + result = {} + + # tasklist.exe runs on Windows XP and higher. (To parse the ouput of + # tasklist.exe is faster than WMI.) + csvlines = [] + for line in os.popen("tasklist.exe /fo csv /nh"): + line = line.strip() + if line: + csvlines.append(line) + for line in csv.reader(csvlines): + pid = int(line[1]) + details = { + "name": line[0].decode("cp850"), # to unicode + "pid": pid, + } + value = "".join( + char for char in line[4] + if char.isdigit() + ) + details["size_kb"] = int(value) + retdict[pid] = details + if not csvlines: + try: + from win32com.client import GetObject + # pywin32 is installed --> use WMI + wmi = GetObject('winmgmts:') + processes = wmi.InstancesOf('Win32_Process') + for process in processes: + pid = int(process.Properties_("ProcessId").value) + details = { + "name": process.Properties_("Name").value, + "pid": pid, + "size_kb": int(process.Properties_("WorkingSetSize").value) / 1000 + } + retdict[pid] = details + except ImportError: + raise NotImplementedError("No tasklist.exe and no WMI.") + return retdict + +# **************************************************************************** +# general + +def unsupported(): + """Platform not supported + """ + raise UnsupportedOsError(PLATFORM) +unsupported.__unsupported__ = True + +def _initialize(): + mod = sys.modules[__name__] + for name in ('getCurrentPids','getCurrentPidDetails', 'getCurrentPidNames'): + func = getattr(mod, "_%s_%s" % (name, PLATFORM), None) + if func is None: + func = unsupported + else: + func.__name__ = name + setattr(mod, name, func) +_initialize() + +def main(): + """Testing""" + + from pprint import pformat + # Current PIDs + current_pids = getCurrentPids() + print "Current PIDs: %s" % pformat(current_pids) + print + print "Current PID Count: %s" % len(current_pids) + print + + print "Current PIDs with names: %s" % pformat(getCurrentPidNames()) + print + +if __name__ == "__main__": + main() + Added: pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py =================================================================== --- pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py 2007-01-26 14:17:50 UTC (rev 80) @@ -0,0 +1,36 @@ +# pyMoul - Python interface to Myst Online URU Live +# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> + +# This program 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 program 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +"""moul.osdependent.singleapp +""" +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + +import unittest +from doctest import DocTestSuite + +import moul.osdependent + +def test_suite(): + return unittest.TestSuite(( + DocTestSuite('moul.osdependent'), + )) + +if __name__ == '__main__': + unittest.main(defaultTest="test_suite") + Property changes on: pymoul/trunk/src/moul/osdependent/tests/test_osdependent.py ___________________________________________________________________ Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 02:16:36 UTC (rev 79) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 14:17:50 UTC (rev 80) @@ -22,29 +22,32 @@ __revision__ = "$Revision$" import os -#from moul.osdependent.win32.miniwinshell import my_documents -#from moul.osdependent.win32.miniwinshell import application_data -from moul.osdependent.win32.winpath import get_homedir -from moul.osdependent.win32.winpath import get_appdata +from moul.osdependent.win32.miniwinshell import my_documents as getMyDocuments +from moul.osdependent.win32.miniwinshell import application_data as getAppdata +#from moul.osdependent.win32.winpath import get_homedir as getMyDocuments +#from moul.osdependent.win32.winpath import get_appdata as getAppdata +from moul.osdependent.win32 import wmi MOUL_DIR = "Uru Live" EXEC_NAME = "UruLauncher.exe" +mycomputer = None +mydocs = getMyDocuments() +myappdata = getAppdata() + def getMoulUserDataDir(): """Get path of MOUL data directory The MOUL data directory contains log files, chatlogs, KI images and many more things. """ - mydoc = get_homedir() - moul_data = os.path.join(mydoc, MOUL_DIR) + moul_data = os.path.join(mydocs, MOUL_DIR) return moul_data def getPyMoulDataDir(): """Get path to the pyMoul ini file """ - app_data = get_appdata() - inidir = os.path.join(app_data, 'pyMoul') + inidir = os.path.join(myappdata , 'pyMoul') return inidir def _startMOUL(installdir, *args): @@ -57,3 +60,22 @@ path = os.path.join(installdir, EXEC_NAME) args = (EXEC_NAME,) + args return os.spawnv(mode, path, args) + +def getCurrentPids(): + """Returns mapping pid -> name + """ + global mycomputer + if mycomputer is None: + # XXX: extremely slow, also see getCurrentPidNames + mycomputer = wmi.WMI() + return [process.ProcessId for process in mycomputer.Win32_Process()] + +def getCurrentPidNames(): + """Returns mapping pid -> name + """ + global mycomputer + if mycomputer is None: + mycomputer = wmi.WMI() + return dict([(process.ProcessId, process.Name) + for process in mycomputer.Win32_Process() + ]) Added: pymoul/trunk/src/moul/osdependent/win32/wmi.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/wmi.py (rev 0) +++ pymoul/trunk/src/moul/osdependent/win32/wmi.py 2007-01-26 14:17:50 UTC (rev 80) @@ -0,0 +1,1246 @@ +## +# wmi - a lightweight Python wrapper around Microsoft's WMI interface +# +# Windows Management Instrumentation (WMI) is Microsoft's answer to +# the DMTF's Common Information Model. It allows you to query just +# about any conceivable piece of information from any computer which +# is running the necessary agent and over which have you the +# necessary authority. +# +# The implementation is by means of COM/DCOM and most of the examples +# assume you're running one of Microsoft's scripting technologies. +# Fortunately, Mark Hammond's pywin32 has pretty much all you need +# for a workable Python adaptation. I haven't tried any of the fancier +# stuff like Async calls and so on, so I don't know if they'd work. +# +# Since the COM implementation doesn't give much away to Python +# programmers, I've wrapped it in some lightweight classes with +# some getattr / setattr magic to ease the way. In particular: +# +# <ul> +# <li> +# The _wmi_namespace object itself will determine its classes +# and allow you to return all instances of any of them by +# using its name as an attribute. As an additional shortcut, +# you needn't specify the Win32_; if the first lookup fails +# it will try again with a Win32_ on the front: +# +# <pre class="code"> +# disks = wmi.WMI ().Win32_LogicalDisk () +# </pre> +# +# In addition, you can specify what would become the WHERE clause +# as keyword parameters: +# +# <pre class="code"> +# fixed_disks = wmi.WMI ().Win32_LogicalDisk (DriveType = 3) +# </pre> +# </li> +# +# <li> +# The objects returned by a WMI lookup are wrapped in a Python +# class which determines their methods and classes and allows +# you to access them as though they were Python classes. The +# methods only allow named parameters. +# +# <pre class="code"> +# for p in wmi.WMI ().Win32_Process (): +# if p.Name.lower () == 'notepad.exe': +# p.Terminate (Result=1) +# </pre> +# </li> +# +# <li> +# Doing a print on one of the WMI objects will result in its +# GetObjectText_ method being called, which usually produces +# a meaningful printout of current values. +# The repr of the object will include its full WMI path, +# which lets you get directly to it if you need to. +# </li> +# +# <li> +# You can get the associators and references of an object as +# a list of python objects by calling the associators () and +# references () methods on a WMI Python object. +# NB Don't do this on a Win32_ComputerSystem object; it will +# take all day and kill your machine! +# +# <pre class="code"> +# for p in wmi.WMI ().Win32_Process (): +# if p.Name.lower () == 'notepad.exe': +# for r in p.references (): +# print r.Name +# </pre> +# </li> +# +# <li> +# WMI classes (as opposed to instances) are first-class +# objects, so you can get hold of a class, and call +# its methods or set up a watch against it. +# +# <pre class="code"> +# process = wmi.WMI ().Win32_Process +# process.Create (CommandLine="notepad.exe") +# </pre> +# +# </li> +# +# <li> +# To make it easier to use in embedded systems and py2exe-style +# executable wrappers, the module will not force early Dispatch. +# To do this, it uses a handy hack by Thomas Heller for easy access +# to constants. +# </li> +# +# <li> +# Typical usage will be: +# +# <pre class="code"> +# import wmi +# +# vodev1 = wmi.WMI ("vodev1") +# for disk in vodev1.Win32_LogicalDisk (): +# if disk.DriveType == 3: +# space = 100 * long (disk.FreeSpace) / long (disk.Size) +# print "%s has %d%% free" % (disk.Name, space) +# </pre> +# </li> +# +# </ul> +# +# Many thanks, obviously to Mark Hammond for creating the win32all +# extensions, but also to Alex Martelli and Roger Upole, whose +# c.l.py postings pointed me in the right direction. +# Thanks especially in release 1.2 to Paul Tiemann for his code +# contributions and robust testing. +# +# (c) Tim Golden - mail at timgolden.me.uk 5th June 2003 +# Licensed under the (GPL-compatible) MIT License: +# http://www.opensource.org/licenses/mit-license.php +# +# For change history see CHANGELOG.TXT +## +try: + True, False +except NameError: + True = 1 + False = 0 + +try: + object +except NameError: + class object: pass + +__VERSION__ = "1.2.1" + +_DEBUG = False + +import sys +import re +from win32com.client import GetObject, Dispatch +import pywintypes + +class ProvideConstants (object): + """ + A class which, when called on a win32com.client.Dispatch object, + provides lazy access to constants defined in the typelib. + + They can be accessed as attributes of the _constants property. + From Thomas Heller on c.l.py + """ + def __init__(self, comobj): + "@param comobj A COM object whose typelib constants are to be exposed" + comobj.__dict__["_constants"] = self + # Get the typelibrary's typecomp interface + self.__typecomp = \ + comobj._oleobj_.GetTypeInfo().GetContainingTypeLib()[0].GetTypeComp() + + def __getattr__(self, name): + if name.startswith("__") and name.endswith("__"): + raise AttributeError, name + result = self.__typecomp.Bind(name) + # Bind returns a 2-tuple, first item is TYPEKIND, + # the second item has the value + if not result[0]: + raise AttributeError, name + return result[1].value + +obj = GetObject ("winmgmts:") +ProvideConstants (obj) + +wbemErrInvalidQuery = obj._constants.wbemErrInvalidQuery +wbemErrTimedout = obj._constants.wbemErrTimedout +wbemFlagReturnImmediately = obj._constants.wbemFlagReturnImmediately +wbemFlagForwardOnly = obj._constants.wbemFlagForwardOnly + +def handle_com_error (error_info): + """Convenience wrapper for displaying all manner of COM errors. + Raises a x_wmi exception with more useful information attached + + @param error_info The structure attached to a pywintypes.com_error + """ + hresult_code, hresult_name, additional_info, parameter_in_error = error_info + exception_string = ["%s - %s" % (hex (hresult_code), hresult_name)] + if additional_info: + wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info + exception_string.append (" Error in: %s" % source_of_error) + exception_string.append (" %s - %s" % (hex (scode), error_description.strip ())) + raise x_wmi, "\n".join (exception_string) + +def from_time (year=None, month=None, day=None, hours=None, minutes=None, seconds=None, microseconds=None, timezone=None): + """ + Convenience wrapper to take a series of date/time elements and return a WMI time + of the form yyyymmddHHMMSS.mmmmmm+UUU. All elements may be int, string or + omitted altogether. If omitted, they will be replaced in the output string + by a series of stars of the appropriate length. + + @param year The year element of the date/time + @param month The month element of the date/time + @param day The day element of the date/time + @param hours The hours element of the date/time + @param minutes The minutes element of the date/time + @param seconds The seconds element of the date/time + @param microseconds The microseconds element of the date/time + @param timezone The timeezone element of the date/time + + @return A WMI datetime string of the form: yyyymmddHHMMSS.mmmmmm+UUU + """ + def str_or_stars (i, length): + if i is None: + return "*" * length + else: + return str (i).rjust (length, "0") + + wmi_time = "" + wmi_time += str_or_stars (year, 4) + wmi_time += str_or_stars (month, 2) + wmi_time += str_or_stars (day, 2) + wmi_time += str_or_stars (hours, 2) + wmi_time += str_or_stars (minutes, 2) + wmi_time += str_or_stars (seconds, 2) + wmi_time += "." + wmi_time += str_or_stars (microseconds, 6) + wmi_time += str_or_stars (timezone, 4) + + return wmi_time + +def to_time (wmi_time): + """ + Convenience wrapper to take a WMI datetime string of the form + yyyymmddHHMMSS.mmmmmm+UUU and return a 9-tuple containing the + individual elements, or None where string contains placeholder + stars. + + @param wmi_time The WMI datetime string in yyyymmddHHMMSS.mmmmmm+UUU format + + @return A 9-tuple of (year, month, day, hours, minutes, seconds, microseconds, timezone) + """ + def int_or_none (s, start, end): + try: + return int (s[start:end]) + except ValueError: + return None + + year = int_or_none (wmi_time, 0, 4) + month = int_or_none (wmi_time, 4, 6) + day = int_or_none (wmi_time, 6, 8) + hours = int_or_none (wmi_time, 8, 10) + minutes = int_or_none (wmi_time, 10, 12) + seconds = int_or_none (wmi_time, 12, 14) + microseconds = int_or_none (wmi_time, 15, 21) + timezone = wmi_time[21:] + + return year, month, day, hours, minutes, seconds, microseconds, timezone + +# +# Exceptions +# +class x_wmi (Exception): + pass + +class x_wmi_invalid_query (x_wmi): + pass + +class x_wmi_timed_out (x_wmi): + pass + +class x_wmi_no_namespace (x_wmi): + pass + +WMI_EXCEPTIONS = { + wbemErrInvalidQuery : x_wmi_invalid_query, + wbemErrTimedout : x_wmi_timed_out +} + +def _set (obj, attribute, value): + """ + Helper function to add an attribute directly into the instance + dictionary, bypassing possible __getattr__ calls + + @param obj Any python object + @param attribute String containing attribute name + @param value Any python object + """ + obj.__dict__[attribute] = value + +class _wmi_method: + """ + A currying sort of wrapper around a WMI method name. It + abstract's the method's parameters and can be called like + a normal Python object passing in the parameter values. + + Output parameters are returned from the call as a tuple. + In addition, the docstring is set up as the method's + signature, including an indication as to whether any + given parameter is expecting an array, and what + special privileges are required to call the method. + """ + + def __init__ (self, ole_object, method_name): + """ + @param ole_object The WMI class/instance whose method is to be called + @param method_name The name of the method to be called + """ + try: + self.ole_object = Dispatch (ole_object) + self.method = ole_object.Methods_ (method_name) + self.qualifiers = {} + for q in self.method.Qualifiers_: + self.qualifiers[q.Name] = q.Value + self.provenance = "\n".join (self.qualifiers.get ("MappingStrings", [])) + + self.in_parameters = self.method.InParameters + self.out_parameters = self.method.OutParameters + if self.in_parameters is None: + self.in_parameter_names = [] + else: + self.in_parameter_names = [(i.Name, i.IsArray) for i in self.in_parameters.Properties_] + if self.out_parameters is None: + self.out_parameter_names = [] + else: + self.out_parameter_names = [(i.Name, i.IsArray) for i in self.out_parameters.Properties_] + + doc = "%s (%s) => (%s)" % ( + method_name, + ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.in_parameter_names]), + ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.out_parameter_names]) + ) + privileges = self.qualifiers.get ("Privileges", []) + if privileges: + doc += " | Needs: " + ", ".join (privileges) + self.__doc__ = doc + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __call__ (self, **kwargs): + """ + Execute the call to a WMI method, returning + a tuple (even if is of only one value) containing + the out and return parameters. + """ + try: + if self.in_parameters: + parameter_names = {} + for name, is_array in self.in_parameter_names: + parameter_names[name] = is_array + + parameters = self.in_parameters + for k, v in kwargs.items (): + is_array = parameter_names.get (k) + if is_array is None: + raise AttributeError, "%s is not a valid parameter for %s" % (k, self.__doc__) + else: + if is_array: + try: list (v) + except TypeError: raise TypeError, "%s must be iterable" % k + + parameters.Properties_ (k).Value = v + + result = self.ole_object.ExecMethod_ (self.method.Name, self.in_parameters) + else: + result = self.ole_object.ExecMethod_ (self.method.Name) + + results = [] + for name, is_array in self.out_parameter_names: + value = result.Properties_ (name).Value + if is_array: + # + # Thanks to Jonas Bjering for bug report and path + # + results.append (list (value or [])) + else: + results.append (value) + return tuple (results) + + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __repr__ (self): + return "<function %s>" % self.__doc__ + +# +# class _wmi_object +# +class _wmi_object: + "A lightweight wrapper round an OLE WMI object" + + def __init__ (self, ole_object, instance_of=None, fields=[]): + try: + _set (self, "ole_object", ole_object) + _set (self, "_instance_of", instance_of) + _set (self, "properties", {}) + _set (self, "methods", {}) + + if self._instance_of: + if fields: + for field in fields: + self.properties[field] = None + else: + _set (self, "properties", self._instance_of.properties.copy ()) + _set (self, "methods", self._instance_of.methods) + else: + for p in ole_object.Properties_: + self.properties[p.Name] = None + for m in ole_object.Methods_: + self.methods[m.Name] = None + + _set (self, "_properties", self.properties.keys ()) + _set (self, "_methods", self.methods.keys ()) + + _set (self, "qualifiers", {}) + for q in self.ole_object.Qualifiers_: + self.qualifiers[q.Name] = q.Value + _set (self, "is_association", self.qualifiers.has_key ("Association")) + + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __str__ (self): + """ + For a call to print [object] return the OLE description + of the properties / values of the object + """ + try: + return self.ole_object.GetObjectText_ () + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __repr__ (self): + """ + Indicate both the fact that this is a wrapped WMI object + and the WMI object's own identifying class. + """ + try: + return "<%s: %s>" % (self.__class__.__name__, str (self.Path_.Path)) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def _cached_properties (self, attribute): + if self.properties[attribute] is None: + self.properties[attribute] = self.ole_object.Properties_ (attribute) + return self.properties[attribute] + + def _cached_methods (self, attribute): + if self.methods[attribute] is None: + self.methods[attribute] = _wmi_method (self.ole_object, attribute) + return self.methods[attribute] + + def __getattr__ (self, attribute): + """ + Attempt to pass attribute calls to the proxied COM object. + If the attribute is recognised as a property, return its value; + if it is recognised as a method, return a method wrapper which + can then be called with parameters; otherwise pass the lookup + on to the underlying object. + """ + try: + if self.properties.has_key (attribute): + value = self._cached_properties (attribute).Value + # + # If this is an association, its properties are + # actually the paths to the two aspects of the + # association, so translate them automatically + # into WMI objects. + # + if self.is_association: + return WMI (moniker=value) + else: + return value + elif self.methods.has_key (attribute): + return self._cached_methods (attribute) + else: + return getattr (self.ole_object, attribute) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __setattr__ (self, attribute, value): + """ + If the attribute to be set is valid for the proxied + COM object, set that objects's parameter value; if not, + raise an exception. + """ + try: + if self.properties.has_key (attribute): + self._cached_properties (attribute).Value = value + if self.ole_object.Path_.Path: + self.ole_object.Put_ () + else: + raise AttributeError, attribute + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __eq__ (self, other): + """ + Use WMI's CompareTo_ to compare this object with + another. Don't try to do anything if the other + object is not a wmi object. It might be possible + to compare this object's unique key with a string + or something, but this doesn't seem to be universal + enough to merit a special case. + """ + if isinstance (other, self.__class__): + return self.ole_object.CompareTo_ (other.ole_object) + else: + raise x_wmi, "Can't compare a WMI object with something else" + + def put (self): + self.ole_object.Put_ () + + def set (self, **kwargs): + """ + Set several properties of the underlying object + at one go. This is particularly useful in combination + with the new () method below. However, an instance + which has been spawned in this way won't have enough + information to write pack, so only try if the + instance has a path. + """ + if kwargs: + try: + for attribute, value in kwargs.items (): + if self.properties.has_key (attribute): + self._cached_properties (attribute).Value = value + else: + raise AttributeError, attribute + # + # Only try to write the attributes + # back if the object exists. + # + if self.ole_object.Path_.Path: + self.ole_object.Put_ () + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def path (self): + """ + Return the WMI URI to this object. Can be used to + determine the path relative to the parent namespace. eg, + + <pre class="code"> + pp0 = wmi.WMI ().Win32_ParallelPort ()[0] + print pp0.path ().RelPath + </pre> + """ + try: + return self.ole_object.Path_ + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def derivation (self): + """Return a tuple representing the object derivation for + this object, with the most specific object first. eg, + + pp0 = wmi.WMI ().Win32_ParallelPort ()[0] + print ' <- '.join (pp0.derivation ()) + """ + try: + return self.ole_object.Derivation_ + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def associators (self, wmi_association_class="", wmi_result_class=""): + """Return a list of objects related to this one, optionally limited + either by association class (ie the name of the class which relates + them) or by result class (ie the name of the class which would be + retrieved) + + <pre class="code"> +c = wmi.WMI () +pp = c.Win32_ParallelPort ()[0] + +for i in pp.associators (wmi_association_class="Win32_PortResource"): + print i + +for i in pp.associators (wmi_result_class="Win32_PnPEntity"): + print i + </pre> + """ + try: + return [ + _wmi_object (i) for i in \ + self.ole_object.Associators_ ( + strAssocClass=wmi_association_class, + strResultClass=wmi_result_class + ) + ] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def references (self, wmi_class=""): + """Return a list of associations involving this object, optionally + limited by the result class (the name of the association class). + + NB Associations are treated specially; although WMI only returns + the string corresponding to the instance of each associated object, + this module will automatically convert that to the object itself. + + <pre class="code"> + c = wmi.WMI () + sp = c.Win32_SerialPort ()[0] + + for i in sp.references (): + print i + + for i in sp.references (wmi_class="Win32_SerialPortSetting"): + print i + </pre> + """ + try: + return [_wmi_object (i) for i in self.ole_object.References_ (strResultClass=wmi_class)] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + +# +# class _wmi_class +# +class _wmi_class (_wmi_object): + """Currying class to assist in issuing queries against + a WMI namespace. The idea is that when someone issues + an otherwise unknown method against the WMI object, if + it matches a known WMI class a query object will be + returned which may then be called with one or more params + which will form the WHERE clause. eg, + + <pre class="code"> + c = wmi.WMI () + c_drive = c.Win32_LogicalDisk (Name='C:') + </pre> + """ + def __init__ (self, namespace, wmi_class): + _wmi_object.__init__ (self, wmi_class) + _set (self, "_namespace", namespace) + _set (self, "_class_name", wmi_class.Path_.Class) + + def query (self, fields=[], **where_clause): + """Make it slightly easier to query against the class, + by calling the namespace's query with the class preset. + Won't work if the class has been instantiated directly. + """ + if self._namespace is None: + raise x_wmi_no_namespace, "You cannot query directly from a WMI class" + + try: + field_list = ", ".join (fields) or "*" + wql = "SELECT " + field_list + " FROM " + self._class_name + if where_clause: + wql += " WHERE " + " AND ". join (["%s = '%s'" % (k, v) for k, v in where_clause.items ()]) + return self._namespace.query (wql, self, fields) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + __call__ = query + + def watch_for ( + self, + notification_type=None, + delay_secs=1, + **where_clause + ): + if self._namespace is None: + raise x_wmi_no_namespace, "You cannot watch directly from a WMI class" + + return self._namespace.watch_for ( + notification_type=notification_type, + wmi_class=self._class_name, + delay_secs=delay_secs, + **where_clause + ) + + def instances (self): + """Return a list of instances of the WMI class + """ + try: + return [_wmi_object (instance, self) for instance in self.Instances_ ()] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def new (self, **kwargs): + """This is the equivalent to the raw-WMI SpawnInstance_ + method. Note that there are relatively few uses for + this, certainly fewer than you might imagine. Most + classes which need to create a new *real* instance + of themselves, eg Win32_Process, offer a .Create + method. SpawnInstance_ is generally reserved for + instances which are passed as parameters to such + .Create methods, a common example being the + Win32_SecurityDescriptor, passed to Win32_Share.Create + and other instances which need security. + + The example here is Win32_ProcessStartup, which + controls the shown/hidden state etc. of a new + Win32_Process instance. + + <pre class="code"> + import win32con + import wmi + c = wmi.WMI () + startup = c.Win32_ProcessStartup.new (ShowWindow=win32con.SW_SHOWMINIMIZED) + pid, retval = c.Win32_Process.Create ( + CommandLine="notepad.exe", + ProcessStartupInformation=startup + ) + </pre> + + NB previous versions of this module, used this function + to create new process. This is *not* a good example + of its use; it is better handled with something like + the example above. + """ + try: + obj = _wmi_object (self.SpawnInstance_ (), self) + obj.set (**kwargs) + return obj + except pywintypes.com_error, error_info: + handle_com_error (error_info) + +# +# class _wmi_result +# +class _wmi_result: + """Simple, data only result for targeted WMI queries which request + data only result classes via fetch_as_classes. + """ + def __init__(self, obj, attributes): + if attributes: + for attr in attributes: + self.__dict__[attr] = obj.Properties_ (attr).Value + else: + for p in obj.Properties_: + attr = p.Name + self.__dict__[attr] = obj.Properties_(attr).Value + +# +# class WMI +# +class _wmi_namespace: + """A WMI root of a computer system. The classes attribute holds a list + of the classes on offer. This means you can explore a bit with + things like this: + + <pre class="code"> + c = wmi.WMI () + for i in c.classes: + if "user" in i.lower (): + print i + </pre> + """ + def __init__ (self, namespace, find_classes): + _set (self, "_namespace", namespace) + # + # wmi attribute preserved for backwards compatibility + # + _set (self, "wmi", namespace) + + # Initialise the "classes" attribute, to avoid infinite recursion in the + # __getattr__ method (which uses it). + self.classes = {} + # + # Pick up the list of classes under this namespace + # so that they can be queried, and used as though + # properties of the namespace by means of the __getattr__ + # hook below. + # If the namespace does not support SubclassesOf, carry on + # regardless + # + if find_classes: + try: + self.classes.update (self.subclasses_of ()) + except AttributeError: + pass + + def __repr__ (self): + return "<_wmi_namespace: %s>" % self.wmi + + def __str__ (self): + return repr (self) + + def get (self, moniker): + try: + return _wmi_object (self.wmi.Get (moniker)) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def handle (self): + """The raw OLE object representing the WMI namespace""" + return self._namespace + + def subclasses_of (self, root="", regex=r".*"): + classes = {} + for c in self._namespace.SubclassesOf (root): + klass = c.Path_.Class + if re.match (regex, klass): + classes[klass] = None + return classes + + def instances (self, class_name): + """Return a list of instances of the WMI class. This is + (probably) equivalent to querying with no qualifiers. + + <pre class="code"> + system.instances ("Win32_LogicalDisk") + # should be the same as + system.Win32_LogicalDisk () + </pre> + """ + try: + return [_wmi_object (obj) for obj in self._namespace.InstancesOf (class_name)] + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def new (self, wmi_class, **kwargs): + """This is now implemented by a call to _wmi_namespace.new (qv)""" + return getattr (self, wmi_class).new (**kwargs) + + new_instance_of = new + + def _raw_query (self, wql): + """Execute a WQL query and return its raw results. Use the flags + recommended by Microsoft to achieve a read-only, semi-synchronous + query where the time is taken while looping through. Should really + be a generator, but ... + NB Backslashes need to be doubled up. + """ + flags = wbemFlagReturnImmediately | wbemFlagForwardOnly + wql = wql.replace ("\\", "\\\\") + if _DEBUG: print "_raw_query(wql):", wql + try: + return self._namespace.ExecQuery (strQuery=wql, iFlags=flags) + except pywintypes.com_error, (hresult, hresult_text, additional, param_in_error): + raise WMI_EXCEPTIONS.get (hresult, x_wmi (hresult)) + + def query (self, wql, instance_of=None, fields=[]): + """Perform an arbitrary query against a WMI object, and return + a list of _wmi_object representations of the results. + """ + return [ _wmi_object (obj, instance_of, fields) for obj in self._raw_query(wql) ] + + def fetch_as_classes (self, wmi_classname, fields=(), **where_clause): + """Build and execute a wql query to fetch the specified list of fields from + the specified wmi_classname + where_clause, then return the results as + a list of simple class instances with attributes matching fields_list. + + If fields is left empty, select * and pre-load all class attributes for + each class returned. + """ + wql = "SELECT %s FROM %s" % (fields and ", ".join (fields) or "*", wmi_classname) + if where_clause: + wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) + return [_wmi_result (obj, fields) for obj in self._raw_query(wql)] + + def fetch_as_lists (self, wmi_classname, fields, **where_clause): + """Build and execute a wql query to fetch the specified list of fields from + the specified wmi_classname + where_clause, then return the results as + a list of lists whose values correspond fields_list. + """ + wql = "SELECT %s FROM %s" % (", ".join (fields), wmi_classname) + if where_clause: + wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) + results = [] + for obj in self._raw_query(wql): + results.append ([obj.Properties_ (field).Value for field in fields]) + return results + + def watch_for ( + self, + raw_wql=None, + notification_type=None, + wmi_class=None, + delay_secs=1, + **where_clause + ): + """Set up an event tracker on a WMI event. This function + returns an wmi_watcher which can be called to get the + next event. eg, + + <pre class="code"> + c = wmi.WMI () + + raw_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'" + watcher = c.watch_for (raw_wql=raw_wql) + while 1: + process_created = watcher () + print process_created.Name + + # or + + watcher = c.watch_for ( + notification_type="Creation", + wmi_class="Win32_Process", + delay_secs=2, + Name='calc.exe' + ) + calc_created = watcher () + </pre> + + Now supports timeout on the call to watcher, eg: + + <pre class="code"> + import pythoncom + import wmi + c = wmi.WMI (privileges=["Security"]) + watcher1 = c.watch_for ( + notification_type="Creation", + wmi_class="Win32_NTLogEvent", + Type="error" + ) + watcher2 = c.watch_for ( + notification_type="Creation", + wmi_class="Win32_NTLogEvent", + Type="warning" + ) + + while 1: + try: + error_log = watcher1 (500) + except wmi.x_wmi_timed_out: + pythoncom.PumpWaitingMessages () + else: + print error_log + + try: + warning_log = watcher2 (500) + except wmi.x_wmi_timed_out: + pythoncom.PumpWaitingMessages () + else: + print warning_log + </pre> + """ + class_name = wmi_class + if raw_wql: + wql = raw_wql + else: + if where_clause: + where = " AND " + " AND ".join (["TargetInstance.%s = '%s'" % (k, v) for k, v in where_clause.items ()]) + else: + where = "" + wql = \ + "SELECT * FROM __Instance%sEvent WITHIN %d WHERE TargetInstance ISA '%s' %s" % \ + (notification_type, delay_secs, class_name, where) + + if _DEBUG: print wql + + try: + return _wmi_watcher (self._namespace.ExecNotificationQuery (wql)) + except pywintypes.com_error, error_info: + handle_com_error (error_info) + + def __getattr__ (self, attribute): + """Offer WMI classes as simple attributes. Pass through any untrapped + unattribute to the underlying OLE object. This means that new or + unmapped functionality is still available to the module user. + """ + # + # Don't try to match against known classes as was previously + # done since the list may not have been requested + # (find_classes=False). + # + try: + return self._cached_classes (attribute) + except pywintypes.com_error, error_i... [truncated message content] |
From: <ti...@us...> - 2007-01-26 14:55:56
|
Revision: 81 http://pymoul.svn.sourceforge.net/pymoul/?rev=81&view=rev Author: tiran Date: 2007-01-26 06:55:52 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Added isMoulRunning stuff Enhanced startMoul Added some (disabled) tests for start and is running Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/darwin/__init__.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/osdependent/win32/__init__.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/config/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -16,6 +16,30 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # """Configuration package + +>>> from moul.osdependent import startMoul +>>> from moul.osdependent import isMoulRunning +>>> installDir = lookupDir('install') +>>> from time import sleep + +Start MOUL +#>>> popen = startMoul(installDir) + +Wait a bit before testing the rest +#>>> sleep(0.2) +#>>> bool(popen.pid) +True +#>>> popen.poll() +#>>> popen.returncode is None +True + +Check the running tester +#>>> isMoulRunning() +u'urulauncher.exe' + +#>>> popen.wait() +#>>> popen.returncode +#0 """ import os Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -53,7 +53,7 @@ # names to import: from moul.osdependent.ID import NAME (as NAME) NAMES = ('getMoulUserDataDir', ('getPyMoulDataDir', '_getPyMoulDataDir'), # as - '_startMOUL', 'EXEC_NAME', + 'startMoul', 'isMoulRunning', 'getCurrentPids', 'getCurrentPidNames', ) Modified: pymoul/trunk/src/moul/osdependent/darwin/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/darwin/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -22,9 +22,12 @@ __revision__ = "$Revision$" import os -from moul.log import LOG -LOG.warning('Darwin/Mac support is not tested') +from subprocess import Popen +from moul.log import getLogger +LOG = getLogger('moul.darwin') +LOG.critical('Darwin/Mac support is not tested') + MOUL_DIR = "Uru Live" EXEC_NAME = "UruLauncher" HOME = os.environ['HOME'] @@ -43,12 +46,12 @@ inidir= os.path.join(HOME, '.pymoul') return inidir -def _startMOUL(installdir, *args): - """Start MOUL +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() """ - # P_DETACH is similar to P_NOWAIT, but the new process is detached from - # the console of the calling process. - mode = os.P_DETACH path = os.path.join(installdir, EXEC_NAME) - args = (EXEC_NAME,) + args - return os.spawnv(mode, path, args) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -22,13 +22,17 @@ __revision__ = "$Revision$" import os -from moul.log import LOG -LOG.warning('Linux support is not tested') +from subprocess import Popen +from moul.log import getLogger +LOG = getLogger('moul.linux') +LOG.critical('Darwin/Mac support is not tested') + MOUL_DIR = "Uru Live" INI_FILE = ('pyMoul', 'pymoul.ini') EXEC_NAME = "UruLauncher" HOME = os.environ['HOME'] +PROCESSES = ('urulauncher', 'uruexplorer') def getMoulUserDataDir(): """Get path of MOUL data directory @@ -44,19 +48,26 @@ inidir= os.path.join(HOME, '.pymoul') return inidir -def _startMOUL(installdir, *args): - """Start MOUL +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() """ - # P_DETACH is similar to P_NOWAIT, but the new process is detached from - # the console of the calling process. - mode = os.P_DETACH path = os.path.join(installdir, EXEC_NAME) - args = (EXEC_NAME,) + args - return os.spawnv(mode, path, args) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) +def isMoulRunning(): + """Test if MOUL or the launcher is running + """ + for pid, name in getCurrentPidNames().items(): + if name.lower() in PROCESSES: + return name.lower() + return False + # process info # based on http://gelb.bcom.at/trac/misc/browser/processinfo - def getCurrentPids(): """Returns current process ids """ Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 14:17:50 UTC (rev 80) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 14:55:52 UTC (rev 81) @@ -22,18 +22,25 @@ __revision__ = "$Revision$" import os +from subprocess import Popen + from moul.osdependent.win32.miniwinshell import my_documents as getMyDocuments from moul.osdependent.win32.miniwinshell import application_data as getAppdata #from moul.osdependent.win32.winpath import get_homedir as getMyDocuments #from moul.osdependent.win32.winpath import get_appdata as getAppdata from moul.osdependent.win32 import wmi +from moul.log import getLogger +LOG = getLogger('moul.win') + MOUL_DIR = "Uru Live" -EXEC_NAME = "UruLauncher.exe" +EXEC_NAME = "UruLauncher.exe" +# lower case +PROCESSES = ("urulauncher.exe", "uruexplorer.exe") -mycomputer = None -mydocs = getMyDocuments() -myappdata = getAppdata() +MYCOMPUTER = None # wmi instance +MYDOCS = getMyDocuments() +MYAPPDATA = getAppdata() def getMoulUserDataDir(): """Get path of MOUL data directory @@ -41,41 +48,48 @@ The MOUL data directory contains log files, chatlogs, KI images and many more things. """ - moul_data = os.path.join(mydocs, MOUL_DIR) + moul_data = os.path.join(MYDOCS, MOUL_DIR) return moul_data def getPyMoulDataDir(): """Get path to the pyMoul ini file """ - inidir = os.path.join(myappdata , 'pyMoul') + inidir = os.path.join(MYAPPDATA , 'pyMoul') return inidir -def _startMOUL(installdir, *args): - """Start MOUL +def startMoul(installdir, *args, **kwargs): + """Start MOUL - returns a Popen instance + + args are applied to the program while kwargs are applied to + subprocess.Popen() """ - # TODO: use subprocess module - # P_DETACH is similar to P_NOWAIT, but the new process is detached from - # the console of the calling process. - mode = os.P_DETACH path = os.path.join(installdir, EXEC_NAME) - args = (EXEC_NAME,) + args - return os.spawnv(mode, path, args) + args = ' '.join(args) + return Popen("%s %s" % (path, args), cwd=installdir, **kwargs) +def isMoulRunning(): + """Test if MOUL or the launcher is running + """ + for pid, name in getCurrentPidNames().items(): + if name.lower() in PROCESSES: + return name.lower() + return False + def getCurrentPids(): """Returns mapping pid -> name """ - global mycomputer - if mycomputer is None: + global MYCOMPUTER + if MYCOMPUTER is None: # XXX: extremely slow, also see getCurrentPidNames - mycomputer = wmi.WMI() - return [process.ProcessId for process in mycomputer.Win32_Process()] + MYCOMPUTER = wmi.WMI() + return [process.ProcessId for process in MYCOMPUTER.Win32_Process()] def getCurrentPidNames(): """Returns mapping pid -> name """ - global mycomputer - if mycomputer is None: - mycomputer = wmi.WMI() + global MYCOMPUTER + if MYCOMPUTER is None: + MYCOMPUTER = wmi.WMI() return dict([(process.ProcessId, process.Name) - for process in mycomputer.Win32_Process() + for process in MYCOMPUTER.Win32_Process() ]) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 17:37:54
|
Revision: 85 http://pymoul.svn.sourceforge.net/pymoul/?rev=85&view=rev Author: tiran Date: 2007-01-26 09:37:52 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Finally a fast and working enumProcess function ... :) Modified Paths: -------------- pymoul/trunk/src/moul/osdependent/win32/__init__.py pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py Removed Paths: ------------- pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py pymoul/trunk/src/moul/osdependent/win32/processinfo.py pymoul/trunk/src/moul/osdependent/win32/wmi.py Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-01-26 17:37:52 UTC (rev 85) @@ -24,11 +24,9 @@ import os from subprocess import Popen -from moul.osdependent.win32.miniwinshell import my_documents as getMyDocuments -from moul.osdependent.win32.miniwinshell import application_data as getAppdata -#from moul.osdependent.win32.winpath import get_homedir as getMyDocuments -#from moul.osdependent.win32.winpath import get_appdata as getAppdata -from moul.osdependent.win32 import wmi +from moul.osdependent.win32.winpath import get_homedir as getMyDocuments +from moul.osdependent.win32.winpath import get_appdata as getAppdata +from moul.osdependent.win32.enumprocesses import enumProcesses from moul.log import getLogger LOG = getLogger('moul.win') @@ -38,7 +36,6 @@ # lower case PROCESSES = ("urulauncher.exe", "uruexplorer.exe") -MYCOMPUTER = None # wmi instance MYDOCS = getMyDocuments() MYAPPDATA = getAppdata() @@ -78,18 +75,10 @@ def getCurrentPids(): """Returns mapping pid -> name """ - global MYCOMPUTER - if MYCOMPUTER is None: - # XXX: extremely slow, also see getCurrentPidNames - MYCOMPUTER = wmi.WMI() - return [process.ProcessId for process in MYCOMPUTER.Win32_Process()] + return enumProcesses().keys() + def getCurrentPidNames(): """Returns mapping pid -> name """ - global MYCOMPUTER - if MYCOMPUTER is None: - MYCOMPUTER = wmi.WMI() - return dict([(process.ProcessId, process.Name) - for process in MYCOMPUTER.Win32_Process() - ]) + return enumProcesses() Modified: pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/enumprocesses.py 2007-01-26 17:37:52 UTC (rev 85) @@ -7,57 +7,60 @@ By Eric Koome email ek...@ya... license GPL + +http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305279 +Title: getting process information on windows +Last Updated: 2004/09/22 +Version no: 1.3 + +Changed by Christian Heimes """ -#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/305279 -#Title: getting process information on windows -#Submitter: Eric Koome (other recipes) -#Last Updated: 2004/09/22 -#Version no: 1.3 -#Category: -from ctypes import * +from ctypes import windll, c_ulong, sizeof, c_buffer, byref -#PSAPI.DLL -psapi = windll.psapi -#Kernel32.DLL -kernel = windll.kernel32 +PSAPI = windll.psapi +KERNEL = windll.kernel32 +PROCESS_QUERY_INFORMATION = 0x0400 +PROCESS_VM_READ = 0x0010 +PROCESS_FLAGS = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ +NULL = '\x00' -def EnumProcesses(): +def enumProcesses(): + """Enumerate processes on Windows using psapi.dll + + @return: A mapping of pid(long) -> process name(unicode) + """ + result = {} arr = c_ulong * 256 - lpidProcess= arr() + lpidProcess = arr() cb = sizeof(lpidProcess) cbNeeded = c_ulong() hModule = c_ulong() count = c_ulong() - modname = c_buffer(30) - PROCESS_QUERY_INFORMATION = 0x0400 - PROCESS_VM_READ = 0x0010 + modname = c_buffer(51) - #Call Enumprocesses to get hold of process id's - psapi.EnumProcesses(byref(lpidProcess), - cb, - byref(cbNeeded)) + # Call Enumprocesses to get hold of process id's + PSAPI.EnumProcesses(byref(lpidProcess), cb, byref(cbNeeded)) + nReturned = cbNeeded.value/sizeof(c_ulong()) # number of processes returned + pidProcess = [pid for pid in lpidProcess][:nReturned] - #Number of processes returned - nReturned = cbNeeded.value/sizeof(c_ulong()) - - pidProcess = [i for i in lpidProcess][:nReturned] - for pid in pidProcess: - - #Get handle to the process based on PID - hProcess = kernel.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, - False, pid) + # Get handle to the process based on PID + hProcess = KERNEL.OpenProcess(PROCESS_FLAGS, False, pid) if hProcess: - psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count)) - psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname)) - print "".join([ i for i in modname if i != '\x00']) + PSAPI.EnumProcessModules(hProcess, byref(hModule), + sizeof(hModule), byref(count)) + PSAPI.GetModuleBaseNameA(hProcess, hModule.value, modname, + sizeof(modname)) + + name = u"".join([c for c in modname if c != NULL]) + result[pid] = name - #-- Clean up - for i in range(modname._length_): - modname[i]='\x00' - - kernel.CloseHandle(hProcess) + modname[:] = sizeof(modname) * NULL + KERNEL.CloseHandle(hProcess) + return result + if __name__ == '__main__': - EnumProcesses() \ No newline at end of file + from pprint import pprint + pprint(EnumProcesses()) Deleted: pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/miniwinshell.py 2007-01-26 17:37:52 UTC (rev 85) @@ -1,141 +0,0 @@ -"""winshell - convenience functions to access Windows shell functionality - -Certain aspects of the Windows user interface are grouped by - Microsoft as Shell functions. These include the Desktop, shortcut - icons, special folders (such as My Documents) and a few other things. - -These are mostly available via the shell module of the win32all - extensions, but whenever I need to use them, I've forgotten the - various constants and so on. - -Several of the shell items have two variants: personal and common, - or User and All Users. These refer to systems with profiles in use: - anything from NT upwards, and 9x with Profiles turned on. Where - relevant, the Personal/User version refers to that owned by the - logged-on user and visible only to that user; the Common/All Users - version refers to that maintained by an Administrator and visible - to all users of the system. - -(c) Tim Golden <win...@ti...> 25th November 2003 -Licensed under the (GPL-compatible) MIT License: -http://www.opensource.org/licenses/mit-license.php - -9th Nov 2005 0.2 . License changed to MIT - . Added functionality using SHFileOperation -25th Nov 2003 0.1 . Initial release by Tim Golden - - -THIS IS A STRIPPED DOWN VERSION OF WINSHELL -It contains only small subset to keep the build small -""" - -__VERSION__ = "0.2small" - -from win32com.shell import shell, shellcon -#import pythoncom - -# -# Although this can be done in one call, Win9x didn't -# support it, so I added this workaround. -# -def get_path (folder_id): - return shell.SHGetPathFromIDList (shell.SHGetSpecialFolderLocation (0, folder_id)) - -def desktop (common=0): - "What folder is equivalent to the current desktop?" - return get_path ((shellcon.CSIDL_DESKTOP, shellcon.CSIDL_COMMON_DESKTOPDIRECTORY)[common]) - -def common_desktop (): -# -# Only here because already used in code -# - return desktop (common=1) - -def application_data (common=0): - "What folder holds application configuration files?" - return get_path ((shellcon.CSIDL_APPDATA, shellcon.CSIDL_COMMON_APPDATA)[common]) - -def favourites (common=0): - "What folder holds the Explorer favourites shortcuts?" - return get_path ((shellcon.CSIDL_FAVORITES, shellcon.CSIDL_COMMON_FAVORITES)[common]) -bookmarks = favourites - -def start_menu (common=0): - "What folder holds the Start Menu shortcuts?" - return get_path ((shellcon.CSIDL_STARTMENU, shellcon.CSIDL_COMMON_STARTMENU)[common]) - -def programs (common=0): - "What folder holds the Programs shortcuts (from the Start Menu)?" - return get_path ((shellcon.CSIDL_PROGRAMS, shellcon.CSIDL_COMMON_PROGRAMS)[common]) - -def startup (common=0): - "What folder holds the Startup shortcuts (from the Start Menu)?" - return get_path ((shellcon.CSIDL_STARTUP, shellcon.CSIDL_COMMON_STARTUP)[common]) - -def personal_folder (): - "What folder holds the My Documents files?" - return get_path (shellcon.CSIDL_PERSONAL) -my_documents = personal_folder - -def recent (): - "What folder holds the Documents shortcuts (from the Start Menu)?" - return get_path (shellcon.CSIDL_RECENT) - -def sendto (): - "What folder holds the SendTo shortcuts (from the Context Menu)?" - return get_path (shellcon.CSIDL_SENDTO) - -def CreateShortcut (Path, Target, Arguments = "", StartIn = "", Icon = ("",0), Description = ""): - """Create a Windows shortcut: - - Path - As what file should the shortcut be created? - Target - What command should the desktop use? - Arguments - What arguments should be supplied to the command? - StartIn - What folder should the command start in? - Icon - (filename, index) What icon should be used for the shortcut? - Description - What description should the shortcut be given? - - eg - CreateShortcut ( - Path=os.path.join (desktop (), "PythonI.lnk"), - Target=r"c:\python\python.exe", - Icon=(r"c:\python\python.exe", 0), - Description="Python Interpreter" - ) - """ - sh = pythoncom.CoCreateInstance ( - shell.CLSID_ShellLink, - None, - pythoncom.CLSCTX_INPROC_SERVER, - shell.IID_IShellLink - ) - - sh.SetPath (Target) - sh.SetDescription (Description) - sh.SetArguments (Arguments) - sh.SetWorkingDirectory (StartIn) - sh.SetIconLocation (Icon[0], Icon[1]) - - persist = sh.QueryInterface (pythoncom.IID_IPersistFile) - persist.Save (Path, 1) - -if __name__ == '__main__': - try: - print 'Desktop =>', desktop () - print 'Common Desktop =>', desktop (1) - print 'Application Data =>', application_data () - print 'Common Application Data =>', application_data (1) - print 'Bookmarks =>', bookmarks () - print 'Common Bookmarks =>', bookmarks (1) - print 'Start Menu =>', start_menu () - print 'Common Start Menu =>', start_menu (1) - print 'Programs =>', programs () - print 'Common Programs =>', programs (1) - print 'Startup =>', startup () - print 'Common Startup =>', startup (1) - print 'My Documents =>', my_documents () - print 'Recent =>', recent () - print 'SendTo =>', sendto () - finally: - raw_input ("Press enter...") - Deleted: pymoul/trunk/src/moul/osdependent/win32/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/processinfo.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/processinfo.py 2007-01-26 17:37:52 UTC (rev 85) @@ -1,34 +0,0 @@ -#http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/303339 -#Title: getting process information on windows -#Submitter: John Nielsen (other recipes) -#Last Updated: 2004/09/03 -#Version no: 1.0 -#Category: System - -import win32pdh, string, win32api - -def procids(): - #each instance is a process, you can have multiple processes w/same name - junk, instances = win32pdh.EnumObjectItems(None,None,'process', win32pdh.PERF_DETAIL_WIZARD) - proc_ids=[] - proc_dict={} - for instance in instances: - if instance in proc_dict: - proc_dict[instance] = proc_dict[instance] + 1 - else: - proc_dict[instance]=0 - for instance, max_instances in proc_dict.items(): - for inum in xrange(max_instances+1): - hq = win32pdh.OpenQuery() # initializes the query handle - path = win32pdh.MakeCounterPath( (None,'process',instance, None, inum,'ID Process') ) - counter_handle=win32pdh.AddCounter(hq, path) - win32pdh.CollectQueryData(hq) #collects data for the counter - type, val = win32pdh.GetFormattedCounterValue(counter_handle, win32pdh.PDH_FMT_LONG) - proc_ids.append((instance,str(val))) - win32pdh.CloseQuery(hq) - - proc_ids.sort() - return proc_ids - - -print procids() \ No newline at end of file Deleted: pymoul/trunk/src/moul/osdependent/win32/wmi.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/wmi.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/osdependent/win32/wmi.py 2007-01-26 17:37:52 UTC (rev 85) @@ -1,1246 +0,0 @@ -## -# wmi - a lightweight Python wrapper around Microsoft's WMI interface -# -# Windows Management Instrumentation (WMI) is Microsoft's answer to -# the DMTF's Common Information Model. It allows you to query just -# about any conceivable piece of information from any computer which -# is running the necessary agent and over which have you the -# necessary authority. -# -# The implementation is by means of COM/DCOM and most of the examples -# assume you're running one of Microsoft's scripting technologies. -# Fortunately, Mark Hammond's pywin32 has pretty much all you need -# for a workable Python adaptation. I haven't tried any of the fancier -# stuff like Async calls and so on, so I don't know if they'd work. -# -# Since the COM implementation doesn't give much away to Python -# programmers, I've wrapped it in some lightweight classes with -# some getattr / setattr magic to ease the way. In particular: -# -# <ul> -# <li> -# The _wmi_namespace object itself will determine its classes -# and allow you to return all instances of any of them by -# using its name as an attribute. As an additional shortcut, -# you needn't specify the Win32_; if the first lookup fails -# it will try again with a Win32_ on the front: -# -# <pre class="code"> -# disks = wmi.WMI ().Win32_LogicalDisk () -# </pre> -# -# In addition, you can specify what would become the WHERE clause -# as keyword parameters: -# -# <pre class="code"> -# fixed_disks = wmi.WMI ().Win32_LogicalDisk (DriveType = 3) -# </pre> -# </li> -# -# <li> -# The objects returned by a WMI lookup are wrapped in a Python -# class which determines their methods and classes and allows -# you to access them as though they were Python classes. The -# methods only allow named parameters. -# -# <pre class="code"> -# for p in wmi.WMI ().Win32_Process (): -# if p.Name.lower () == 'notepad.exe': -# p.Terminate (Result=1) -# </pre> -# </li> -# -# <li> -# Doing a print on one of the WMI objects will result in its -# GetObjectText_ method being called, which usually produces -# a meaningful printout of current values. -# The repr of the object will include its full WMI path, -# which lets you get directly to it if you need to. -# </li> -# -# <li> -# You can get the associators and references of an object as -# a list of python objects by calling the associators () and -# references () methods on a WMI Python object. -# NB Don't do this on a Win32_ComputerSystem object; it will -# take all day and kill your machine! -# -# <pre class="code"> -# for p in wmi.WMI ().Win32_Process (): -# if p.Name.lower () == 'notepad.exe': -# for r in p.references (): -# print r.Name -# </pre> -# </li> -# -# <li> -# WMI classes (as opposed to instances) are first-class -# objects, so you can get hold of a class, and call -# its methods or set up a watch against it. -# -# <pre class="code"> -# process = wmi.WMI ().Win32_Process -# process.Create (CommandLine="notepad.exe") -# </pre> -# -# </li> -# -# <li> -# To make it easier to use in embedded systems and py2exe-style -# executable wrappers, the module will not force early Dispatch. -# To do this, it uses a handy hack by Thomas Heller for easy access -# to constants. -# </li> -# -# <li> -# Typical usage will be: -# -# <pre class="code"> -# import wmi -# -# vodev1 = wmi.WMI ("vodev1") -# for disk in vodev1.Win32_LogicalDisk (): -# if disk.DriveType == 3: -# space = 100 * long (disk.FreeSpace) / long (disk.Size) -# print "%s has %d%% free" % (disk.Name, space) -# </pre> -# </li> -# -# </ul> -# -# Many thanks, obviously to Mark Hammond for creating the win32all -# extensions, but also to Alex Martelli and Roger Upole, whose -# c.l.py postings pointed me in the right direction. -# Thanks especially in release 1.2 to Paul Tiemann for his code -# contributions and robust testing. -# -# (c) Tim Golden - mail at timgolden.me.uk 5th June 2003 -# Licensed under the (GPL-compatible) MIT License: -# http://www.opensource.org/licenses/mit-license.php -# -# For change history see CHANGELOG.TXT -## -try: - True, False -except NameError: - True = 1 - False = 0 - -try: - object -except NameError: - class object: pass - -__VERSION__ = "1.2.1" - -_DEBUG = False - -import sys -import re -from win32com.client import GetObject, Dispatch -import pywintypes - -class ProvideConstants (object): - """ - A class which, when called on a win32com.client.Dispatch object, - provides lazy access to constants defined in the typelib. - - They can be accessed as attributes of the _constants property. - From Thomas Heller on c.l.py - """ - def __init__(self, comobj): - "@param comobj A COM object whose typelib constants are to be exposed" - comobj.__dict__["_constants"] = self - # Get the typelibrary's typecomp interface - self.__typecomp = \ - comobj._oleobj_.GetTypeInfo().GetContainingTypeLib()[0].GetTypeComp() - - def __getattr__(self, name): - if name.startswith("__") and name.endswith("__"): - raise AttributeError, name - result = self.__typecomp.Bind(name) - # Bind returns a 2-tuple, first item is TYPEKIND, - # the second item has the value - if not result[0]: - raise AttributeError, name - return result[1].value - -obj = GetObject ("winmgmts:") -ProvideConstants (obj) - -wbemErrInvalidQuery = obj._constants.wbemErrInvalidQuery -wbemErrTimedout = obj._constants.wbemErrTimedout -wbemFlagReturnImmediately = obj._constants.wbemFlagReturnImmediately -wbemFlagForwardOnly = obj._constants.wbemFlagForwardOnly - -def handle_com_error (error_info): - """Convenience wrapper for displaying all manner of COM errors. - Raises a x_wmi exception with more useful information attached - - @param error_info The structure attached to a pywintypes.com_error - """ - hresult_code, hresult_name, additional_info, parameter_in_error = error_info - exception_string = ["%s - %s" % (hex (hresult_code), hresult_name)] - if additional_info: - wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info - exception_string.append (" Error in: %s" % source_of_error) - exception_string.append (" %s - %s" % (hex (scode), error_description.strip ())) - raise x_wmi, "\n".join (exception_string) - -def from_time (year=None, month=None, day=None, hours=None, minutes=None, seconds=None, microseconds=None, timezone=None): - """ - Convenience wrapper to take a series of date/time elements and return a WMI time - of the form yyyymmddHHMMSS.mmmmmm+UUU. All elements may be int, string or - omitted altogether. If omitted, they will be replaced in the output string - by a series of stars of the appropriate length. - - @param year The year element of the date/time - @param month The month element of the date/time - @param day The day element of the date/time - @param hours The hours element of the date/time - @param minutes The minutes element of the date/time - @param seconds The seconds element of the date/time - @param microseconds The microseconds element of the date/time - @param timezone The timeezone element of the date/time - - @return A WMI datetime string of the form: yyyymmddHHMMSS.mmmmmm+UUU - """ - def str_or_stars (i, length): - if i is None: - return "*" * length - else: - return str (i).rjust (length, "0") - - wmi_time = "" - wmi_time += str_or_stars (year, 4) - wmi_time += str_or_stars (month, 2) - wmi_time += str_or_stars (day, 2) - wmi_time += str_or_stars (hours, 2) - wmi_time += str_or_stars (minutes, 2) - wmi_time += str_or_stars (seconds, 2) - wmi_time += "." - wmi_time += str_or_stars (microseconds, 6) - wmi_time += str_or_stars (timezone, 4) - - return wmi_time - -def to_time (wmi_time): - """ - Convenience wrapper to take a WMI datetime string of the form - yyyymmddHHMMSS.mmmmmm+UUU and return a 9-tuple containing the - individual elements, or None where string contains placeholder - stars. - - @param wmi_time The WMI datetime string in yyyymmddHHMMSS.mmmmmm+UUU format - - @return A 9-tuple of (year, month, day, hours, minutes, seconds, microseconds, timezone) - """ - def int_or_none (s, start, end): - try: - return int (s[start:end]) - except ValueError: - return None - - year = int_or_none (wmi_time, 0, 4) - month = int_or_none (wmi_time, 4, 6) - day = int_or_none (wmi_time, 6, 8) - hours = int_or_none (wmi_time, 8, 10) - minutes = int_or_none (wmi_time, 10, 12) - seconds = int_or_none (wmi_time, 12, 14) - microseconds = int_or_none (wmi_time, 15, 21) - timezone = wmi_time[21:] - - return year, month, day, hours, minutes, seconds, microseconds, timezone - -# -# Exceptions -# -class x_wmi (Exception): - pass - -class x_wmi_invalid_query (x_wmi): - pass - -class x_wmi_timed_out (x_wmi): - pass - -class x_wmi_no_namespace (x_wmi): - pass - -WMI_EXCEPTIONS = { - wbemErrInvalidQuery : x_wmi_invalid_query, - wbemErrTimedout : x_wmi_timed_out -} - -def _set (obj, attribute, value): - """ - Helper function to add an attribute directly into the instance - dictionary, bypassing possible __getattr__ calls - - @param obj Any python object - @param attribute String containing attribute name - @param value Any python object - """ - obj.__dict__[attribute] = value - -class _wmi_method: - """ - A currying sort of wrapper around a WMI method name. It - abstract's the method's parameters and can be called like - a normal Python object passing in the parameter values. - - Output parameters are returned from the call as a tuple. - In addition, the docstring is set up as the method's - signature, including an indication as to whether any - given parameter is expecting an array, and what - special privileges are required to call the method. - """ - - def __init__ (self, ole_object, method_name): - """ - @param ole_object The WMI class/instance whose method is to be called - @param method_name The name of the method to be called - """ - try: - self.ole_object = Dispatch (ole_object) - self.method = ole_object.Methods_ (method_name) - self.qualifiers = {} - for q in self.method.Qualifiers_: - self.qualifiers[q.Name] = q.Value - self.provenance = "\n".join (self.qualifiers.get ("MappingStrings", [])) - - self.in_parameters = self.method.InParameters - self.out_parameters = self.method.OutParameters - if self.in_parameters is None: - self.in_parameter_names = [] - else: - self.in_parameter_names = [(i.Name, i.IsArray) for i in self.in_parameters.Properties_] - if self.out_parameters is None: - self.out_parameter_names = [] - else: - self.out_parameter_names = [(i.Name, i.IsArray) for i in self.out_parameters.Properties_] - - doc = "%s (%s) => (%s)" % ( - method_name, - ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.in_parameter_names]), - ", ".join ([name + ("", "[]")[is_array] for (name, is_array) in self.out_parameter_names]) - ) - privileges = self.qualifiers.get ("Privileges", []) - if privileges: - doc += " | Needs: " + ", ".join (privileges) - self.__doc__ = doc - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __call__ (self, **kwargs): - """ - Execute the call to a WMI method, returning - a tuple (even if is of only one value) containing - the out and return parameters. - """ - try: - if self.in_parameters: - parameter_names = {} - for name, is_array in self.in_parameter_names: - parameter_names[name] = is_array - - parameters = self.in_parameters - for k, v in kwargs.items (): - is_array = parameter_names.get (k) - if is_array is None: - raise AttributeError, "%s is not a valid parameter for %s" % (k, self.__doc__) - else: - if is_array: - try: list (v) - except TypeError: raise TypeError, "%s must be iterable" % k - - parameters.Properties_ (k).Value = v - - result = self.ole_object.ExecMethod_ (self.method.Name, self.in_parameters) - else: - result = self.ole_object.ExecMethod_ (self.method.Name) - - results = [] - for name, is_array in self.out_parameter_names: - value = result.Properties_ (name).Value - if is_array: - # - # Thanks to Jonas Bjering for bug report and path - # - results.append (list (value or [])) - else: - results.append (value) - return tuple (results) - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __repr__ (self): - return "<function %s>" % self.__doc__ - -# -# class _wmi_object -# -class _wmi_object: - "A lightweight wrapper round an OLE WMI object" - - def __init__ (self, ole_object, instance_of=None, fields=[]): - try: - _set (self, "ole_object", ole_object) - _set (self, "_instance_of", instance_of) - _set (self, "properties", {}) - _set (self, "methods", {}) - - if self._instance_of: - if fields: - for field in fields: - self.properties[field] = None - else: - _set (self, "properties", self._instance_of.properties.copy ()) - _set (self, "methods", self._instance_of.methods) - else: - for p in ole_object.Properties_: - self.properties[p.Name] = None - for m in ole_object.Methods_: - self.methods[m.Name] = None - - _set (self, "_properties", self.properties.keys ()) - _set (self, "_methods", self.methods.keys ()) - - _set (self, "qualifiers", {}) - for q in self.ole_object.Qualifiers_: - self.qualifiers[q.Name] = q.Value - _set (self, "is_association", self.qualifiers.has_key ("Association")) - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __str__ (self): - """ - For a call to print [object] return the OLE description - of the properties / values of the object - """ - try: - return self.ole_object.GetObjectText_ () - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __repr__ (self): - """ - Indicate both the fact that this is a wrapped WMI object - and the WMI object's own identifying class. - """ - try: - return "<%s: %s>" % (self.__class__.__name__, str (self.Path_.Path)) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def _cached_properties (self, attribute): - if self.properties[attribute] is None: - self.properties[attribute] = self.ole_object.Properties_ (attribute) - return self.properties[attribute] - - def _cached_methods (self, attribute): - if self.methods[attribute] is None: - self.methods[attribute] = _wmi_method (self.ole_object, attribute) - return self.methods[attribute] - - def __getattr__ (self, attribute): - """ - Attempt to pass attribute calls to the proxied COM object. - If the attribute is recognised as a property, return its value; - if it is recognised as a method, return a method wrapper which - can then be called with parameters; otherwise pass the lookup - on to the underlying object. - """ - try: - if self.properties.has_key (attribute): - value = self._cached_properties (attribute).Value - # - # If this is an association, its properties are - # actually the paths to the two aspects of the - # association, so translate them automatically - # into WMI objects. - # - if self.is_association: - return WMI (moniker=value) - else: - return value - elif self.methods.has_key (attribute): - return self._cached_methods (attribute) - else: - return getattr (self.ole_object, attribute) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __setattr__ (self, attribute, value): - """ - If the attribute to be set is valid for the proxied - COM object, set that objects's parameter value; if not, - raise an exception. - """ - try: - if self.properties.has_key (attribute): - self._cached_properties (attribute).Value = value - if self.ole_object.Path_.Path: - self.ole_object.Put_ () - else: - raise AttributeError, attribute - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __eq__ (self, other): - """ - Use WMI's CompareTo_ to compare this object with - another. Don't try to do anything if the other - object is not a wmi object. It might be possible - to compare this object's unique key with a string - or something, but this doesn't seem to be universal - enough to merit a special case. - """ - if isinstance (other, self.__class__): - return self.ole_object.CompareTo_ (other.ole_object) - else: - raise x_wmi, "Can't compare a WMI object with something else" - - def put (self): - self.ole_object.Put_ () - - def set (self, **kwargs): - """ - Set several properties of the underlying object - at one go. This is particularly useful in combination - with the new () method below. However, an instance - which has been spawned in this way won't have enough - information to write pack, so only try if the - instance has a path. - """ - if kwargs: - try: - for attribute, value in kwargs.items (): - if self.properties.has_key (attribute): - self._cached_properties (attribute).Value = value - else: - raise AttributeError, attribute - # - # Only try to write the attributes - # back if the object exists. - # - if self.ole_object.Path_.Path: - self.ole_object.Put_ () - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def path (self): - """ - Return the WMI URI to this object. Can be used to - determine the path relative to the parent namespace. eg, - - <pre class="code"> - pp0 = wmi.WMI ().Win32_ParallelPort ()[0] - print pp0.path ().RelPath - </pre> - """ - try: - return self.ole_object.Path_ - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def derivation (self): - """Return a tuple representing the object derivation for - this object, with the most specific object first. eg, - - pp0 = wmi.WMI ().Win32_ParallelPort ()[0] - print ' <- '.join (pp0.derivation ()) - """ - try: - return self.ole_object.Derivation_ - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def associators (self, wmi_association_class="", wmi_result_class=""): - """Return a list of objects related to this one, optionally limited - either by association class (ie the name of the class which relates - them) or by result class (ie the name of the class which would be - retrieved) - - <pre class="code"> -c = wmi.WMI () -pp = c.Win32_ParallelPort ()[0] - -for i in pp.associators (wmi_association_class="Win32_PortResource"): - print i - -for i in pp.associators (wmi_result_class="Win32_PnPEntity"): - print i - </pre> - """ - try: - return [ - _wmi_object (i) for i in \ - self.ole_object.Associators_ ( - strAssocClass=wmi_association_class, - strResultClass=wmi_result_class - ) - ] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def references (self, wmi_class=""): - """Return a list of associations involving this object, optionally - limited by the result class (the name of the association class). - - NB Associations are treated specially; although WMI only returns - the string corresponding to the instance of each associated object, - this module will automatically convert that to the object itself. - - <pre class="code"> - c = wmi.WMI () - sp = c.Win32_SerialPort ()[0] - - for i in sp.references (): - print i - - for i in sp.references (wmi_class="Win32_SerialPortSetting"): - print i - </pre> - """ - try: - return [_wmi_object (i) for i in self.ole_object.References_ (strResultClass=wmi_class)] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -# -# class _wmi_class -# -class _wmi_class (_wmi_object): - """Currying class to assist in issuing queries against - a WMI namespace. The idea is that when someone issues - an otherwise unknown method against the WMI object, if - it matches a known WMI class a query object will be - returned which may then be called with one or more params - which will form the WHERE clause. eg, - - <pre class="code"> - c = wmi.WMI () - c_drive = c.Win32_LogicalDisk (Name='C:') - </pre> - """ - def __init__ (self, namespace, wmi_class): - _wmi_object.__init__ (self, wmi_class) - _set (self, "_namespace", namespace) - _set (self, "_class_name", wmi_class.Path_.Class) - - def query (self, fields=[], **where_clause): - """Make it slightly easier to query against the class, - by calling the namespace's query with the class preset. - Won't work if the class has been instantiated directly. - """ - if self._namespace is None: - raise x_wmi_no_namespace, "You cannot query directly from a WMI class" - - try: - field_list = ", ".join (fields) or "*" - wql = "SELECT " + field_list + " FROM " + self._class_name - if where_clause: - wql += " WHERE " + " AND ". join (["%s = '%s'" % (k, v) for k, v in where_clause.items ()]) - return self._namespace.query (wql, self, fields) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - __call__ = query - - def watch_for ( - self, - notification_type=None, - delay_secs=1, - **where_clause - ): - if self._namespace is None: - raise x_wmi_no_namespace, "You cannot watch directly from a WMI class" - - return self._namespace.watch_for ( - notification_type=notification_type, - wmi_class=self._class_name, - delay_secs=delay_secs, - **where_clause - ) - - def instances (self): - """Return a list of instances of the WMI class - """ - try: - return [_wmi_object (instance, self) for instance in self.Instances_ ()] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def new (self, **kwargs): - """This is the equivalent to the raw-WMI SpawnInstance_ - method. Note that there are relatively few uses for - this, certainly fewer than you might imagine. Most - classes which need to create a new *real* instance - of themselves, eg Win32_Process, offer a .Create - method. SpawnInstance_ is generally reserved for - instances which are passed as parameters to such - .Create methods, a common example being the - Win32_SecurityDescriptor, passed to Win32_Share.Create - and other instances which need security. - - The example here is Win32_ProcessStartup, which - controls the shown/hidden state etc. of a new - Win32_Process instance. - - <pre class="code"> - import win32con - import wmi - c = wmi.WMI () - startup = c.Win32_ProcessStartup.new (ShowWindow=win32con.SW_SHOWMINIMIZED) - pid, retval = c.Win32_Process.Create ( - CommandLine="notepad.exe", - ProcessStartupInformation=startup - ) - </pre> - - NB previous versions of this module, used this function - to create new process. This is *not* a good example - of its use; it is better handled with something like - the example above. - """ - try: - obj = _wmi_object (self.SpawnInstance_ (), self) - obj.set (**kwargs) - return obj - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -# -# class _wmi_result -# -class _wmi_result: - """Simple, data only result for targeted WMI queries which request - data only result classes via fetch_as_classes. - """ - def __init__(self, obj, attributes): - if attributes: - for attr in attributes: - self.__dict__[attr] = obj.Properties_ (attr).Value - else: - for p in obj.Properties_: - attr = p.Name - self.__dict__[attr] = obj.Properties_(attr).Value - -# -# class WMI -# -class _wmi_namespace: - """A WMI root of a computer system. The classes attribute holds a list - of the classes on offer. This means you can explore a bit with - things like this: - - <pre class="code"> - c = wmi.WMI () - for i in c.classes: - if "user" in i.lower (): - print i - </pre> - """ - def __init__ (self, namespace, find_classes): - _set (self, "_namespace", namespace) - # - # wmi attribute preserved for backwards compatibility - # - _set (self, "wmi", namespace) - - # Initialise the "classes" attribute, to avoid infinite recursion in the - # __getattr__ method (which uses it). - self.classes = {} - # - # Pick up the list of classes under this namespace - # so that they can be queried, and used as though - # properties of the namespace by means of the __getattr__ - # hook below. - # If the namespace does not support SubclassesOf, carry on - # regardless - # - if find_classes: - try: - self.classes.update (self.subclasses_of ()) - except AttributeError: - pass - - def __repr__ (self): - return "<_wmi_namespace: %s>" % self.wmi - - def __str__ (self): - return repr (self) - - def get (self, moniker): - try: - return _wmi_object (self.wmi.Get (moniker)) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def handle (self): - """The raw OLE object representing the WMI namespace""" - return self._namespace - - def subclasses_of (self, root="", regex=r".*"): - classes = {} - for c in self._namespace.SubclassesOf (root): - klass = c.Path_.Class - if re.match (regex, klass): - classes[klass] = None - return classes - - def instances (self, class_name): - """Return a list of instances of the WMI class. This is - (probably) equivalent to querying with no qualifiers. - - <pre class="code"> - system.instances ("Win32_LogicalDisk") - # should be the same as - system.Win32_LogicalDisk () - </pre> - """ - try: - return [_wmi_object (obj) for obj in self._namespace.InstancesOf (class_name)] - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def new (self, wmi_class, **kwargs): - """This is now implemented by a call to _wmi_namespace.new (qv)""" - return getattr (self, wmi_class).new (**kwargs) - - new_instance_of = new - - def _raw_query (self, wql): - """Execute a WQL query and return its raw results. Use the flags - recommended by Microsoft to achieve a read-only, semi-synchronous - query where the time is taken while looping through. Should really - be a generator, but ... - NB Backslashes need to be doubled up. - """ - flags = wbemFlagReturnImmediately | wbemFlagForwardOnly - wql = wql.replace ("\\", "\\\\") - if _DEBUG: print "_raw_query(wql):", wql - try: - return self._namespace.ExecQuery (strQuery=wql, iFlags=flags) - except pywintypes.com_error, (hresult, hresult_text, additional, param_in_error): - raise WMI_EXCEPTIONS.get (hresult, x_wmi (hresult)) - - def query (self, wql, instance_of=None, fields=[]): - """Perform an arbitrary query against a WMI object, and return - a list of _wmi_object representations of the results. - """ - return [ _wmi_object (obj, instance_of, fields) for obj in self._raw_query(wql) ] - - def fetch_as_classes (self, wmi_classname, fields=(), **where_clause): - """Build and execute a wql query to fetch the specified list of fields from - the specified wmi_classname + where_clause, then return the results as - a list of simple class instances with attributes matching fields_list. - - If fields is left empty, select * and pre-load all class attributes for - each class returned. - """ - wql = "SELECT %s FROM %s" % (fields and ", ".join (fields) or "*", wmi_classname) - if where_clause: - wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) - return [_wmi_result (obj, fields) for obj in self._raw_query(wql)] - - def fetch_as_lists (self, wmi_classname, fields, **where_clause): - """Build and execute a wql query to fetch the specified list of fields from - the specified wmi_classname + where_clause, then return the results as - a list of lists whose values correspond fields_list. - """ - wql = "SELECT %s FROM %s" % (", ".join (fields), wmi_classname) - if where_clause: - wql += " WHERE " + " AND ".join (["%s = '%s'" % (k, v) for k, v in where_clause.items()]) - results = [] - for obj in self._raw_query(wql): - results.append ([obj.Properties_ (field).Value for field in fields]) - return results - - def watch_for ( - self, - raw_wql=None, - notification_type=None, - wmi_class=None, - delay_secs=1, - **where_clause - ): - """Set up an event tracker on a WMI event. This function - returns an wmi_watcher which can be called to get the - next event. eg, - - <pre class="code"> - c = wmi.WMI () - - raw_wql = "SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_Process'" - watcher = c.watch_for (raw_wql=raw_wql) - while 1: - process_created = watcher () - print process_created.Name - - # or - - watcher = c.watch_for ( - notification_type="Creation", - wmi_class="Win32_Process", - delay_secs=2, - Name='calc.exe' - ) - calc_created = watcher () - </pre> - - Now supports timeout on the call to watcher, eg: - - <pre class="code"> - import pythoncom - import wmi - c = wmi.WMI (privileges=["Security"]) - watcher1 = c.watch_for ( - notification_type="Creation", - wmi_class="Win32_NTLogEvent", - Type="error" - ) - watcher2 = c.watch_for ( - notification_type="Creation", - wmi_class="Win32_NTLogEvent", - Type="warning" - ) - - while 1: - try: - error_log = watcher1 (500) - except wmi.x_wmi_timed_out: - pythoncom.PumpWaitingMessages () - else: - print error_log - - try: - warning_log = watcher2 (500) - except wmi.x_wmi_timed_out: - pythoncom.PumpWaitingMessages () - else: - print warning_log - </pre> - """ - class_name = wmi_class - if raw_wql: - wql = raw_wql - else: - if where_clause: - where = " AND " + " AND ".join (["TargetInstance.%s = '%s'" % (k, v) for k, v in where_clause.items ()]) - else: - where = "" - wql = \ - "SELECT * FROM __Instance%sEvent WITHIN %d WHERE TargetInstance ISA '%s' %s" % \ - (notification_type, delay_secs, class_name, where) - - if _DEBUG: print wql - - try: - return _wmi_watcher (self._namespace.ExecNotificationQuery (wql)) - except pywintypes.com_error, error_info: - handle_com_error (error_info) - - def __getattr__ (self, attribute): - """Offer WMI classes as simple attributes. Pass through any untrapped - unattribute to the underlying OLE object. This means that new or - unmapped functionality is still available to the module user. - """ - # - # Don't try to match against known classes as was previously - # done since the list may not have been requested - # (find_classes=False). - # - try: - return self._cached_classes (attribute) - except pywintypes.com_error, error_info: - try: - return self._cached_classes ("Win32_" + attribute) - except pywintypes.com_error, error_info: - return getattr (self._namespace, attribute) - - def _cached_classes (self, class_name): - """Standard caching helper which keeps track of classes - already retrieved by name and returns the existing object - if found. If this is the first retrieval, store it and - pass it back - """ - if self.classes.get (class_name) is None: - self.classes[class_name] = _wmi_class (self, self._namespace.Get (class_name)) - return self.classes[class_name] - -# -# class _wmi_watcher -# -class _wmi_watcher: - """Helper class for WMI.watch_for below (qv)""" - - def __init__ (self, wmi_event): - self.wmi_event = wmi_event - - def __call__ (self, timeout_ms=-1): - """When called, return the instance which caused the event. Supports - timeout in milliseconds (defaulting to infinite). If the watcher - times out, x_wmi_timed_out is raised. This makes it easy to support - watching for multiple objects. - """ - try: - return _wmi_object (self.wmi_event.NextEvent (timeout_ms).Properties_ ("TargetInstance").Value) - except pywintypes.com_error, error_info: - hresult_code, hresult_name, additional_info, parameter_in_error = error_info - if additional_info: - wcode, source_of_error, error_description, whlp_file, whlp_context, scode = additional_info - if scode == wbemErrTimedout: - raise x_wmi_timed_out - handle_com_error (error_info) - -PROTOCOL = "winmgmts:" -IMPERSONATION_LEVEL = "impersonate" -AUTHENTICATION_LEVEL = "default" -NAMESPACE = "root/cimv2" -def connect ( - computer=".", - impersonation_level="", - authentication_level="", - authority="", - privileges="", - moniker="", - wmi=None, - namespace="", - suffix="", - user="", - password="", - find_classes=True, - debug=False -): - """The WMI constructor can either take a ready-made moniker or as many - parts of one as are necessary. Eg, - - <pre class="code"> - c = wmi.WMI (moniker="winmgmts:{impersonationLevel=Delegate}//remote") - - # or - - c = wmi.WMI (computer="remote", privileges=["!RemoteShutdown", "Security"]) - </pre> - - I daren't link to a Microsoft URL; they change so often. Try Googling for - WMI construct moniker and see what it comes back with. - - For complete control, a named argument "wmi" can be supplied, which - should be a SWbemServices object, which you create yourself. Eg, - - <pre class="code"> - loc = win32com.client.Dispatch("WbemScripting.SWbemLocator") - svc = loc.ConnectServer(...) - c = wmi.WMI(wmi=svc) - </pre> - - This is the only way of connecting to a remote computer with a different - username, as the moniker syntax does not allow specification of a user - name. - - If the "wmi" parameter is supplied, all other parameters are ignored. - """ - global _DEBUG - _DEBUG = debug - - # - # If namespace is a blank string, leave - # it unaltered as it might to trying to - # access the root namespace - # - #if namespace is None: - # namespace = NAMESPACE - - try: - if wmi: - obj = wmi - - elif moniker: - if not moniker.startswith (PROTOCOL): - moniker = PROTOCOL + moniker - if _DEBUG: print moniker - obj = GetObject (moniker) - - else: - if user: - if impersonation_level or authentication_level or privileges or suffix: - raise x_wmi, "You can't specify an impersonation, authentication or privilege as well as a username" - else: - obj = connect_server ( - server=computer, - namespace=namespace, - user=user, - password=password, - authority=authority - ) - - else: - moniker = construct_moniker ( - computer=computer, - impersonation_level=impersonation_level or IMPERSONATION_LEVEL, - authentication_level=authentication_level or AUTHENTICATION_LEVEL, - authority=authority, - privileges=privileges, - namespace=namespace, - suffix=suffix - ) - if _DEBUG: print moniker - obj = GetObject (moniker) - - wmi_type = get_wmi_type (obj) - - if wmi_type == "namespace": - return _wmi_namespace (obj, find_classes) - elif wmi_type == "class": - return _wmi_class (None, obj) - elif wmi_type == "instance": - return _wmi_object (obj) - else: - raise x_wmi, "Unknown moniker type" - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -WMI = connect - -def construct_moniker ( - computer=None, - impersonation_level="Impersonate", - authentication_level="Default", - authority=None, - privileges=None, - namespace=None, - suffix=None -): - security = [] - if impersonation_level: security.append ("impersonationLevel=%s" % impersonation_level) - if authentication_level: security.append ("authenticationLevel=%s" % authentication_level) - # - # Use of the authority descriptor is invalid on the local machine - # - if authority and computer: security.append ("authority=%s" % authority) - if privileges: security.append ("(%s)" % ", ".join (privileges)) - - moniker = [PROTOCOL] - if security: moniker.append ("{%s}/" % ",".join (security)) - if computer: moniker.append ("/%s/" % computer) - if namespace: - parts = re.split (r"[/\\]", namespace) - if parts[0] != 'root': - parts.insert (0, "root") - moniker.append ("/".join (parts)) - if suffix: moniker.append (":%s" % suffix) - return "".join (moniker) - -def get_wmi_type (obj): - try: - path = obj.Path_ - except AttributeError: - return "namespace" - else: - if path.IsClass: - return "class" - else: - return "instance" - -def connect_server ( - server, - namespace = "", - user = "", - password = "", - locale = "", - authority = "", - security_flags = 0, - named_value_set = None -): - """Return a remote server running WMI - - server - name of the server - namespace - namespace to connect to: defaults to whatever's defined as default - user - username to connect as, either local or domain (dom\name or user@domain for XP) - password: leave blank to use current context - locale: desired locale in form MS_XXXX (eg MS_409 for Am En) - authority: either "Kerberos:" or an NT domain. Not needed if included in user - security_flags: if 0, connect will wait forever; if 0x80, connect will timeout at 2 mins - named_value_set: typically empty, otherwise a context-specific SWbemNamedValueSet - - <pre class="code"> - c = wmi.WMI (wmi=wmi.connect_server (server="remote_machine", user="myname", password="mypassword")) - </pre> - """ - if _DEBUG: - print server - print namespace - print user - print password - print locale - print authority - print security_flags - print named_value_set - - return Dispatch ("WbemScripting.SWbemLocator").\ - ConnectServer ( - server, - namespace, - user, - password, - locale, - authority, - security_flags, - named_value_set - ) - -def Registry ( - computer=None, - impersonation_level="Impersonate", - authentication_level="Default", - authority=None, - privileges=None, - moniker=None -): - - if not moniker: - moniker = construct_moniker ( - computer=computer, - impersonation_level=impersonation_level, - authentication_level=authentication_level, - authority=authority, - privileges=privileges, - namespace="default", - suffix="StdRegProv" - ) - - try: - return _wmi_object (GetObject (moniker)) - - except pywintypes.com_error, error_info: - handle_com_error (error_info) - -# -# From a post to python-win32 by Sean -# -def machines_in_domain (domain_name): - adsi = Dispatch ("ADsNameSpaces") - nt = adsi.GetObject ("","WinNT:") - result = nt.OpenDSObject ("WinNT://%s" % domain_name, "", "", 0) - result.Filter = ["computer"] - domain = [] - for machine in result: - domain.append (machine.Name) - return domain - -# -# Typical use test -# -if __name__ == '__main__': - system = WMI () - for my_computer in system.Win32_ComputerSystem (): - print "Disks on", my_computer.Name - for disk in system.Win32_LogicalDisk (): - print disk.Caption, disk.Description, disk.ProviderName or "" - Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 17:37:52 UTC (rev 85) @@ -86,7 +86,7 @@ self._moulrunning_thread = MoulRunningThread() self.connect(self._moulrunning_thread, SIGNAL('moulIsRunning(bool)'), self.on_moulIsRunning) - self._moulrunning_thread.startChecker(10.0) # check now and every 10 seconds + self._moulrunning_thread.startChecker(5.0) # check now and every 5 seconds @signalLogDecorator(LOG) def on_moulIsRunning(self, bool): @@ -569,7 +569,7 @@ def run(self): while True: - result = True #isMoulRunning() + result = isMoulRunning() if result: self.emit(SIGNAL('moulIsRunning(bool)'), True) else: Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 16:40:35 UTC (rev 84) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 17:37:52 UTC (rev 85) @@ -43,12 +43,12 @@ """An instance of pyMoul QT is already running!""") mb.exec_() sys.exit(1) - #if isMoulRunning(): - # mb = criticalMessageBox(app, - # "URU is running", - # """URU is running! Please close Uru or Uru Launcher first.""") - # mb.exec_() - # sys.exit(2) + if isMoulRunning(): + mb = criticalMessageBox(app, + "URU is running", + """URU is running! Please close Uru or Uru Launcher first.""") + mb.exec_() + sys.exit(2) mainWindow = MainWindow() mainWindow.show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-26 19:03:25
|
Revision: 87 http://pymoul.svn.sourceforge.net/pymoul/?rev=87&view=rev Author: tiran Date: 2007-01-26 11:03:20 -0800 (Fri, 26 Jan 2007) Log Message: ----------- Status message More log cleanups More logging Modified Paths: -------------- pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/singleapp.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/log.py 2007-01-26 19:03:20 UTC (rev 87) @@ -72,8 +72,9 @@ """ global mhdlr global fhdlr - mhdlr.setTarget(fhdlr) - mhdlr.flush() + if mhdlr: + mhdlr.setTarget(fhdlr) + mhdlr.flush() root.removeHandler(mhdlr) del mhdlr @@ -114,11 +115,15 @@ else: _installMemoryHdlr() _systemInfo() + +def createLogfile(): + """Create log file and redirect stdout/stderr to logfile + """ _installFileHdlr() _removeMemoryHdlr() # Redirect stdout and stderr to logger when running as frozen app - #sys.stdout = LoggingStdout(getLogger('stdout').info) - #sys.stderr = LoggingStdout(getLogger('stderr').error) + sys.stdout = LoggingStdout(getLogger('stdout').info) + sys.stderr = LoggingStdout(getLogger('stderr').error) __LOG_SIGNALS__ = not __FROZEN__ def signalLogDecorator(__logger__): Modified: pymoul/trunk/src/moul/osdependent/singleapp.py =================================================================== --- pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/osdependent/singleapp.py 2007-01-26 19:03:20 UTC (rev 87) @@ -87,11 +87,14 @@ __version__ = "$Id$" __revision__ = "$Revision$" +import atexit import os import getpass +from logging import getLogger import tempfile -import atexit +LOG = getLogger('singleapp') + TEMPDIR = tempfile.gettempdir() USER = getpass.getuser() PID = os.getpid() @@ -170,7 +173,9 @@ self._fd.close() self._fd = None raise SingleAppError("Another instance is already running") - return self.lckfile, self.pid + else: + LOG.info("Create lock file %s for PID %i" % (self.lckfile, self.pid)) + return self.lckfile, self.pid def release(self): """Release lock @@ -184,6 +189,7 @@ if self._fd: self._fd.close() if os.path.isfile(self.lckfile): + LOG.info("Remove lock file %s" % self.lckfile) os.unlink(self.lckfile) def checkLocked(self): Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-26 19:03:20 UTC (rev 87) @@ -83,15 +83,32 @@ self._documents_init() # run checker + self._moulrunning = None self._moulrunning_thread = MoulRunningThread() self.connect(self._moulrunning_thread, SIGNAL('moulIsRunning(bool)'), self.on_moulIsRunning) self._moulrunning_thread.startChecker(5.0) # check now and every 5 seconds @signalLogDecorator(LOG) - def on_moulIsRunning(self, bool): - pass - + def on_moulIsRunning(self, boolean): + sb = self.statusbar + boolean = bool(boolean) + if boolean is not self._moulrunning: + self._moulrunning = boolean + self.systemtray.setToolTip + if boolean: + msg = self.trUtf8("MOUL is running") + sb.showMessage(msg) + self.systemtray.setToolTip(msg) + self.systemtray.showMessage(self.trUtf8('MOUL'), msg, + QtGui.QSystemTrayIcon.Information, 10000) + else: + msg = self.trUtf8("MOUL is not running") + sb.showMessage(msg) + self.systemtray.setToolTip(msg) + self.systemtray.showMessage(self.trUtf8('MOUL'), msg, + QtGui.QSystemTrayIcon.Information, 10000) + def _notimplemented(self): """TODO: remove me """ Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-01-26 19:03:20 UTC (rev 87) @@ -31,8 +31,24 @@ from moul.osdependent.singleapp import SimpleSingleApp from moul.config import getPyMoulDataDir from moul.osdependent import isMoulRunning +from moul.log import createLogfile +from moul.log import getLogger +LOG = getLogger('moul.qt') + def main(*args): + """Main application + + Flow diagram: + * create app + * check if other instance of pymoulqt is running + o exit app if another instance is running + * create log file handler + * check if URU is running + o exit if URU is running + * Show the main window + """ + LOG.info("Starting PyMoul QT UI with argv %s" % repr(args)) app = QtGui.QApplication(*args) singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir()) try: @@ -43,16 +59,22 @@ """An instance of pyMoul QT is already running!""") mb.exec_() sys.exit(1) - if isMoulRunning(): - mb = criticalMessageBox(app, - "URU is running", - """URU is running! Please close Uru or Uru Launcher first.""") - mb.exec_() - sys.exit(2) + + createLogfile() + +# if isMoulRunning(): +# mb = criticalMessageBox(app, +# "URU is running", +# """URU is running! Please close Uru or Uru Launcher first.""") +# mb.exec_() +# sys.exit(2) + LOG.info("Invoking PyMoul QT MainWindow") mainWindow = MainWindow() mainWindow.show() - return app.exec_() + err = app.exec_() + LOG.info("Exiting PyMoul QT UI with status %i" % err) + return err if __name__ == '__main__': err = main(sys.argv) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-26 19:03:20 UTC (rev 87) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src\moul\qt\ui\mainwindow.ui' # -# Created: Fri Jan 26 14:28:09 2007 +# Created: Fri Jan 26 19:48:46 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -14,7 +14,7 @@ def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.setWindowModality(QtCore.Qt.NonModal) - MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,460,530).size()).expandedTo(MainWindow.minimumSizeHint())) + MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,460,534).size()).expandedTo(MainWindow.minimumSizeHint())) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(0),QtGui.QSizePolicy.Policy(0)) sizePolicy.setHorizontalStretch(0) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-26 18:30:56 UTC (rev 86) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-01-26 19:03:20 UTC (rev 87) @@ -10,7 +10,7 @@ <x>0</x> <y>0</y> <width>460</width> - <height>530</height> + <height>534</height> </rect> </property> <property name="sizePolicy" > This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-28 17:15:46
|
Revision: 93 http://pymoul.svn.sourceforge.net/pymoul/?rev=93&view=rev Author: tiran Date: 2007-01-28 09:15:47 -0800 (Sun, 28 Jan 2007) Log Message: ----------- Changed log level Modified Paths: -------------- pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/ui/moulqt_rc.py Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-01-28 17:15:47 UTC (rev 93) @@ -369,7 +369,7 @@ self.clear() if isinstance(fd_name, basestring): fd = open(fd_name, 'rb') - LOG.debug("Parsing encrypted file %s" % fd_name) + LOG.info("Parsing encrypted file %s" % fd_name) close = True else: fd = fd_name @@ -514,7 +514,7 @@ # check for OpenAL device name = self._get('Audio.SetDeviceName') if name not in self._devices: - LOG.debug("Device added: %s" % name) + LOG.info("Device added: %s" % name) self._devices.append(name) def getDeviceIdx(self, name): Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/log.py 2007-01-28 17:15:47 UTC (rev 93) @@ -84,7 +84,7 @@ global fhdlr from moul.config import getPyMoulDataDir logFile = os.path.join(getPyMoulDataDir(check=True), 'pymoul.log') - LOG.debug("Adding file logger: %s" % logFile) + LOG.info("Adding file logger: %s" % logFile) fhdlr = handlers.RotatingFileHandler(logFile, backupCount=9) fhdlr.setFormatter(format) root.addHandler(fhdlr) @@ -92,15 +92,15 @@ def _systemInfo(): from moul.osdependent import __INFO__ - LOG.debug("pyMoul version: %s" % moul_version) - LOG.debug("Python: %s" % repr(sys.version_info)) - LOG.debug("Python: %s" % sys.version.replace('\n', ' ')) - LOG.debug("Platform: %s, OS name: %s" % (sys.platform, os.name)) - LOG.debug("system %r, node %r, release %r, version %r, machine %r, processor %r" - % platform.uname()) - LOG.debug("platform name: %s" % platform.platform(True)) - LOG.debug("sys.frozen status: %s" % __FROZEN__) - LOG.debug("OS detected: win32: %r, cygwin: %r, Linux: %r, Mac: %r, BSD: %r, " + LOG.info("pyMoul version: %s" % moul_version) + LOG.info("Python: %s" % repr(sys.version_info)) + LOG.info("Python: %s" % sys.version.replace('\n', ' ')) + LOG.info("Platform: %s, OS name: %s" % (sys.platform, os.name)) + LOG.info("system %r, node %r, release %r, version %r, machine %r, processor %r" + % platform.uname()) + LOG.info("platform name: %s" % platform.platform(True)) + LOG.info("sys.frozen status: %s" % __FROZEN__) + LOG.info("OS detected: win32: %r, cygwin: %r, Linux: %r, Mac: %r, BSD: %r, " "posix/Un*x: %r, NT: %r" % __INFO__) # no setup the logging stuff! Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-01-28 17:15:47 UTC (rev 93) @@ -142,7 +142,8 @@ raise ValueError("Datadir's parent dir does not exist: %s" % par) else: - LOG.debug("Creating pyMoul data dir %s" % datadir) + LOG.info("Creating pyMoul data dir %s" % datadir) os.mkdir(datadir, 0750) - LOG.debug("Using pyMoul data dir %s" % datadir) + LOG.info("Using pyMoul data dir %s" % datadir) return datadir + Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-28 17:15:47 UTC (rev 93) @@ -520,11 +520,11 @@ self.text_ping.insertPlainText("PING: %0.3f\n" % time) def on_pingthread_dnserror(self, name, errcode, errmsg): - LOG.debug('dns error: %s, %i, %s' % (name, errcode, errmsg)) + LOG.error('dns error: %s, %i, %s' % (name, errcode, errmsg)) self.text_ping.insertPlainText("%s ... DNS error: %s\n" % (name, errmsg)) def on_pingthread_pingerror(self, name, errcode, errmsg): - LOG.debug('ping error: %s, %i, %s' % (name, errcode, errmsg)) + LOG.error('ping error: %s, %i, %s' % (name, errcode, errmsg)) self.text_ping.insertPlainText("PING error: %s\n" % errmsg) @pyqtSignature("bool") Modified: pymoul/trunk/src/moul/qt/ui/moulqt_rc.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/moulqt_rc.py 2007-01-28 16:43:16 UTC (rev 92) +++ pymoul/trunk/src/moul/qt/ui/moulqt_rc.py 2007-01-28 17:15:47 UTC (rev 93) @@ -2,8 +2,8 @@ # Resource object code # -# Created: Mi 17. Jan 17:01:45 2007 -# by: The Resource Compiler for PyQt (Qt v4.2.2) +# Created: So Jan 28 18:10:39 2007 +# by: The Resource Compiler for PyQt (Qt v4.2.0) # # WARNING! All changes made in this file will be lost! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-01-30 14:39:11
|
Revision: 101 http://pymoul.svn.sourceforge.net/pymoul/?rev=101&view=rev Author: tiran Date: 2007-01-30 06:39:03 -0800 (Tue, 30 Jan 2007) Log Message: ----------- Rework of the UI Modified Paths: -------------- pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-01-30 01:20:56 UTC (rev 100) +++ pymoul/trunk/src/moul/log.py 2007-01-30 14:39:03 UTC (rev 101) @@ -122,8 +122,8 @@ _installFileHdlr() _removeMemoryHdlr() # Redirect stdout and stderr to logger when running as frozen app - sys.stdout = LoggingStdout(getLogger('stdout').info) - sys.stderr = LoggingStdout(getLogger('stderr').error) + #sys.stdout = LoggingStdout(getLogger('stdout').info) + #sys.stderr = LoggingStdout(getLogger('stderr').error) __LOG_SIGNALS__ = not __FROZEN__ def signalLogDecorator(__logger__): Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-30 01:20:56 UTC (rev 100) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-01-30 14:39:03 UTC (rev 101) @@ -81,7 +81,7 @@ self._audio_init() self._ping_init() self._systray_init() - self.tab_documents.setEnabled(False) + self.tab_sub_journals.setEnabled(False) self._documents_init() # run checker Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-30 01:20:56 UTC (rev 100) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-30 14:39:03 UTC (rev 101) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src/moul/qt/ui/mainwindow.ui' # -# Created: Sun Jan 28 15:25:00 2007 +# Created: Tue Jan 30 15:36:49 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -13,116 +13,73 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.setWindowModality(QtCore.Qt.NonModal) - MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,460,534).size()).expandedTo(MainWindow.minimumSizeHint())) - - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(0),QtGui.QSizePolicy.Policy(0)) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) - MainWindow.setSizePolicy(sizePolicy) + MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,492,595).size()).expandedTo(MainWindow.minimumSizeHint())) + MainWindow.setMinimumSize(QtCore.QSize(492,595)) + MainWindow.setMaximumSize(QtCore.QSize(492,595)) MainWindow.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) self.centralwidget = QtGui.QWidget(MainWindow) - self.centralwidget.setEnabled(True) self.centralwidget.setObjectName("centralwidget") - self.lb_top_image = QtGui.QLabel(self.centralwidget) - self.lb_top_image.setGeometry(QtCore.QRect(15,10,430,58)) - self.lb_top_image.setFrameShape(QtGui.QFrame.StyledPanel) - self.lb_top_image.setFrameShadow(QtGui.QFrame.Sunken) - self.lb_top_image.setPixmap(QtGui.QPixmap(":/resources/moul_logo.png")) - self.lb_top_image.setObjectName("lb_top_image") + self.tabwidget = QtGui.QTabWidget(self.centralwidget) + self.tabwidget.setGeometry(QtCore.QRect(0,100,491,434)) + self.tabwidget.setTabPosition(QtGui.QTabWidget.North) + self.tabwidget.setObjectName("tabwidget") - self.horizontalLayout = QtGui.QWidget(self.centralwidget) - self.horizontalLayout.setGeometry(QtCore.QRect(60,70,341,31)) - self.horizontalLayout.setObjectName("horizontalLayout") + self.tab_tasks = QtGui.QWidget() + self.tab_tasks.setObjectName("tab_tasks") - self.hboxlayout = QtGui.QHBoxLayout(self.horizontalLayout) - self.hboxlayout.setMargin(0) - self.hboxlayout.setSpacing(6) - self.hboxlayout.setObjectName("hboxlayout") + self.groupBox_3 = QtGui.QGroupBox(self.tab_tasks) + self.groupBox_3.setGeometry(QtCore.QRect(10,240,471,161)) + self.groupBox_3.setObjectName("groupBox_3") - self.comboBox = QtGui.QComboBox(self.horizontalLayout) - self.comboBox.setEnabled(False) + self.groupBox_2 = QtGui.QGroupBox(self.tab_tasks) + self.groupBox_2.setGeometry(QtCore.QRect(10,110,471,131)) + self.groupBox_2.setObjectName("groupBox_2") - font = QtGui.QFont(self.comboBox.font()) - font.setPointSize(6) - self.comboBox.setFont(font) - self.comboBox.setObjectName("comboBox") - self.hboxlayout.addWidget(self.comboBox) + self.groupBox = QtGui.QGroupBox(self.tab_tasks) + self.groupBox.setGeometry(QtCore.QRect(10,0,471,111)) + self.groupBox.setObjectName("groupBox") + self.tabwidget.addTab(self.tab_tasks,"") - self.pushButton = QtGui.QPushButton(self.horizontalLayout) - self.pushButton.setEnabled(False) + self.tab_settings = QtGui.QWidget() + self.tab_settings.setObjectName("tab_settings") - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(0),QtGui.QSizePolicy.Policy(0)) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) - self.pushButton.setSizePolicy(sizePolicy) - self.pushButton.setMaximumSize(QtCore.QSize(16777215,20)) - self.pushButton.setBaseSize(QtCore.QSize(0,20)) + self.tab_sub_settings = QtGui.QTabWidget(self.tab_settings) + self.tab_sub_settings.setGeometry(QtCore.QRect(0,0,491,411)) + self.tab_sub_settings.setObjectName("tab_sub_settings") - font = QtGui.QFont(self.pushButton.font()) - font.setPointSize(8) - self.pushButton.setFont(font) - self.pushButton.setObjectName("pushButton") - self.hboxlayout.addWidget(self.pushButton) + self.tab_graphics = QtGui.QWidget() + self.tab_graphics.setObjectName("tab_graphics") - self.main_buttonbox = QtGui.QDialogButtonBox(self.centralwidget) - self.main_buttonbox.setGeometry(QtCore.QRect(10,480,441,32)) - self.main_buttonbox.setOrientation(QtCore.Qt.Horizontal) - self.main_buttonbox.setStandardButtons(QtGui.QDialogButtonBox.Close|QtGui.QDialogButtonBox.NoButton|QtGui.QDialogButtonBox.Reset|QtGui.QDialogButtonBox.Save) - self.main_buttonbox.setObjectName("main_buttonbox") + self.horizontalLayout_4 = QtGui.QWidget(self.tab_graphics) + self.horizontalLayout_4.setGeometry(QtCore.QRect(10,10,471,81)) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.tabwidget = QtGui.QTabWidget(self.centralwidget) - self.tabwidget.setGeometry(QtCore.QRect(5,100,450,375)) - self.tabwidget.setTabPosition(QtGui.QTabWidget.North) - self.tabwidget.setObjectName("tabwidget") + self.hboxlayout = QtGui.QHBoxLayout(self.horizontalLayout_4) + self.hboxlayout.setMargin(0) + self.hboxlayout.setSpacing(6) + self.hboxlayout.setObjectName("hboxlayout") - self.tab_graphics = QtGui.QWidget() - self.tab_graphics.setObjectName("tab_graphics") + self.groupBox_screenres = QtGui.QGroupBox(self.horizontalLayout_4) - self.groupBox_gra_checkboxes = QtGui.QGroupBox(self.tab_graphics) - self.groupBox_gra_checkboxes.setEnabled(True) - self.groupBox_gra_checkboxes.setGeometry(QtCore.QRect(240,10,201,71)) - self.groupBox_gra_checkboxes.setObjectName("groupBox_gra_checkboxes") + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(1),QtGui.QSizePolicy.Policy(1)) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.groupBox_screenres.sizePolicy().hasHeightForWidth()) + self.groupBox_screenres.setSizePolicy(sizePolicy) + self.groupBox_screenres.setObjectName("groupBox_screenres") - self.verticalLayout = QtGui.QWidget(self.groupBox_gra_checkboxes) - self.verticalLayout.setGeometry(QtCore.QRect(10,0,160,71)) - self.verticalLayout.setObjectName("verticalLayout") + self.verticalLayout_46 = QtGui.QWidget(self.groupBox_screenres) + self.verticalLayout_46.setGeometry(QtCore.QRect(20,20,181,54)) + self.verticalLayout_46.setObjectName("verticalLayout_46") - self.vboxlayout = QtGui.QVBoxLayout(self.verticalLayout) + self.vboxlayout = QtGui.QVBoxLayout(self.verticalLayout_46) self.vboxlayout.setMargin(0) self.vboxlayout.setSpacing(6) self.vboxlayout.setObjectName("vboxlayout") - self.cb_gra_windowed = QtGui.QCheckBox(self.verticalLayout) - self.cb_gra_windowed.setObjectName("cb_gra_windowed") - self.vboxlayout.addWidget(self.cb_gra_windowed) - - self.cb_gra_vsync = QtGui.QCheckBox(self.verticalLayout) - self.cb_gra_vsync.setObjectName("cb_gra_vsync") - self.vboxlayout.addWidget(self.cb_gra_vsync) - - self.cb_gra_shadow = QtGui.QCheckBox(self.verticalLayout) - self.cb_gra_shadow.setObjectName("cb_gra_shadow") - self.vboxlayout.addWidget(self.cb_gra_shadow) - - self.groupBox_screenres = QtGui.QGroupBox(self.tab_graphics) - self.groupBox_screenres.setGeometry(QtCore.QRect(10,0,220,81)) - self.groupBox_screenres.setObjectName("groupBox_screenres") - - self.verticalLayout_2 = QtGui.QWidget(self.groupBox_screenres) - self.verticalLayout_2.setGeometry(QtCore.QRect(20,20,181,51)) - self.verticalLayout_2.setObjectName("verticalLayout_2") - - self.vboxlayout1 = QtGui.QVBoxLayout(self.verticalLayout_2) - self.vboxlayout1.setMargin(0) - self.vboxlayout1.setSpacing(6) - self.vboxlayout1.setObjectName("vboxlayout1") - - self.sl_gra_screenres = QtGui.QSlider(self.verticalLayout_2) + self.sl_gra_screenres = QtGui.QSlider(self.verticalLayout_46) self.sl_gra_screenres.setMaximum(10) self.sl_gra_screenres.setPageStep(1) self.sl_gra_screenres.setSliderPosition(0) @@ -131,118 +88,71 @@ self.sl_gra_screenres.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_gra_screenres.setTickInterval(1) self.sl_gra_screenres.setObjectName("sl_gra_screenres") - self.vboxlayout1.addWidget(self.sl_gra_screenres) + self.vboxlayout.addWidget(self.sl_gra_screenres) - self.lb_screenres = QtGui.QLabel(self.verticalLayout_2) + self.lb_screenres = QtGui.QLabel(self.verticalLayout_46) self.lb_screenres.setAlignment(QtCore.Qt.AlignCenter) self.lb_screenres.setObjectName("lb_screenres") - self.vboxlayout1.addWidget(self.lb_screenres) + self.vboxlayout.addWidget(self.lb_screenres) + self.hboxlayout.addWidget(self.groupBox_screenres) - self.groupBox_gra_quality = QtGui.QGroupBox(self.tab_graphics) - self.groupBox_gra_quality.setEnabled(True) - self.groupBox_gra_quality.setGeometry(QtCore.QRect(10,79,430,261)) - self.groupBox_gra_quality.setObjectName("groupBox_gra_quality") + self.groupBox_gra_checkboxes = QtGui.QGroupBox(self.horizontalLayout_4) + self.groupBox_gra_checkboxes.setEnabled(True) + self.groupBox_gra_checkboxes.setObjectName("groupBox_gra_checkboxes") - self.verticalLayout_7 = QtGui.QWidget(self.groupBox_gra_quality) - self.verticalLayout_7.setGeometry(QtCore.QRect(230,20,179,71)) - self.verticalLayout_7.setObjectName("verticalLayout_7") + self.verticalLayout_28 = QtGui.QWidget(self.groupBox_gra_checkboxes) + self.verticalLayout_28.setGeometry(QtCore.QRect(10,10,201,61)) + self.verticalLayout_28.setObjectName("verticalLayout_28") - self.vboxlayout2 = QtGui.QVBoxLayout(self.verticalLayout_7) - self.vboxlayout2.setMargin(0) - self.vboxlayout2.setSpacing(6) - self.vboxlayout2.setObjectName("vboxlayout2") + self.vboxlayout1 = QtGui.QVBoxLayout(self.verticalLayout_28) + self.vboxlayout1.setMargin(0) + self.vboxlayout1.setSpacing(6) + self.vboxlayout1.setObjectName("vboxlayout1") - self.lb_gra_tq = QtGui.QLabel(self.verticalLayout_7) - self.lb_gra_tq.setAlignment(QtCore.Qt.AlignCenter) - self.lb_gra_tq.setObjectName("lb_gra_tq") - self.vboxlayout2.addWidget(self.lb_gra_tq) - - self.sl_gra_texture = QtGui.QSlider(self.verticalLayout_7) - self.sl_gra_texture.setMinimum(0) - self.sl_gra_texture.setMaximum(2) - self.sl_gra_texture.setPageStep(1) - self.sl_gra_texture.setProperty("value",QtCore.QVariant(0)) - self.sl_gra_texture.setSliderPosition(0) - self.sl_gra_texture.setTracking(False) - self.sl_gra_texture.setOrientation(QtCore.Qt.Horizontal) - self.sl_gra_texture.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_gra_texture.setTickInterval(1) - self.sl_gra_texture.setObjectName("sl_gra_texture") - self.vboxlayout2.addWidget(self.sl_gra_texture) - self.hboxlayout1 = QtGui.QHBoxLayout() self.hboxlayout1.setMargin(0) self.hboxlayout1.setSpacing(6) self.hboxlayout1.setObjectName("hboxlayout1") - self.lb_gra_tq_low = QtGui.QLabel(self.verticalLayout_7) - self.lb_gra_tq_low.setObjectName("lb_gra_tq_low") - self.hboxlayout1.addWidget(self.lb_gra_tq_low) + self.cb_gra_windowed = QtGui.QCheckBox(self.verticalLayout_28) + self.cb_gra_windowed.setObjectName("cb_gra_windowed") + self.hboxlayout1.addWidget(self.cb_gra_windowed) - self.lb_gra_tq_high = QtGui.QLabel(self.verticalLayout_7) - self.lb_gra_tq_high.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.lb_gra_tq_high.setObjectName("lb_gra_tq_high") - self.hboxlayout1.addWidget(self.lb_gra_tq_high) - self.vboxlayout2.addLayout(self.hboxlayout1) + self.cb_gra_vsync = QtGui.QCheckBox(self.verticalLayout_28) + self.cb_gra_vsync.setObjectName("cb_gra_vsync") + self.hboxlayout1.addWidget(self.cb_gra_vsync) + self.vboxlayout1.addLayout(self.hboxlayout1) - self.verticalLayout_5 = QtGui.QWidget(self.groupBox_gra_quality) - self.verticalLayout_5.setGeometry(QtCore.QRect(20,100,179,71)) - self.verticalLayout_5.setObjectName("verticalLayout_5") + self.cb_gra_shadow = QtGui.QCheckBox(self.verticalLayout_28) + self.cb_gra_shadow.setObjectName("cb_gra_shadow") + self.vboxlayout1.addWidget(self.cb_gra_shadow) + self.hboxlayout.addWidget(self.groupBox_gra_checkboxes) - self.vboxlayout3 = QtGui.QVBoxLayout(self.verticalLayout_5) + self.groupBox_gra_quality = QtGui.QGroupBox(self.tab_graphics) + self.groupBox_gra_quality.setEnabled(True) + self.groupBox_gra_quality.setGeometry(QtCore.QRect(10,90,471,281)) + self.groupBox_gra_quality.setObjectName("groupBox_gra_quality") + + self.verticalLayout_47 = QtGui.QWidget(self.groupBox_gra_quality) + self.verticalLayout_47.setGeometry(QtCore.QRect(20,20,201,251)) + self.verticalLayout_47.setObjectName("verticalLayout_47") + + self.vboxlayout2 = QtGui.QVBoxLayout(self.verticalLayout_47) + self.vboxlayout2.setMargin(0) + self.vboxlayout2.setSpacing(6) + self.vboxlayout2.setObjectName("vboxlayout2") + + self.vboxlayout3 = QtGui.QVBoxLayout() self.vboxlayout3.setMargin(0) self.vboxlayout3.setSpacing(6) self.vboxlayout3.setObjectName("vboxlayout3") - self.lb_gra_aa = QtGui.QLabel(self.verticalLayout_5) - self.lb_gra_aa.setAlignment(QtCore.Qt.AlignCenter) - self.lb_gra_aa.setObjectName("lb_gra_aa") - self.vboxlayout3.addWidget(self.lb_gra_aa) - - self.sl_gra_antialias = QtGui.QSlider(self.verticalLayout_5) - self.sl_gra_antialias.setMinimum(0) - self.sl_gra_antialias.setMaximum(6) - self.sl_gra_antialias.setSingleStep(2) - self.sl_gra_antialias.setPageStep(2) - self.sl_gra_antialias.setProperty("value",QtCore.QVariant(0)) - self.sl_gra_antialias.setSliderPosition(0) - self.sl_gra_antialias.setTracking(False) - self.sl_gra_antialias.setOrientation(QtCore.Qt.Horizontal) - self.sl_gra_antialias.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_gra_antialias.setTickInterval(2) - self.sl_gra_antialias.setObjectName("sl_gra_antialias") - self.vboxlayout3.addWidget(self.sl_gra_antialias) - - self.hboxlayout2 = QtGui.QHBoxLayout() - self.hboxlayout2.setMargin(0) - self.hboxlayout2.setSpacing(6) - self.hboxlayout2.setObjectName("hboxlayout2") - - self.lb_gra_aa_low = QtGui.QLabel(self.verticalLayout_5) - self.lb_gra_aa_low.setObjectName("lb_gra_aa_low") - self.hboxlayout2.addWidget(self.lb_gra_aa_low) - - self.lb_gra_aa_low1 = QtGui.QLabel(self.verticalLayout_5) - self.lb_gra_aa_low1.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.lb_gra_aa_low1.setObjectName("lb_gra_aa_low1") - self.hboxlayout2.addWidget(self.lb_gra_aa_low1) - self.vboxlayout3.addLayout(self.hboxlayout2) - - self.verticalLayout_3 = QtGui.QWidget(self.groupBox_gra_quality) - self.verticalLayout_3.setGeometry(QtCore.QRect(20,20,179,71)) - self.verticalLayout_3.setObjectName("verticalLayout_3") - - self.vboxlayout4 = QtGui.QVBoxLayout(self.verticalLayout_3) - self.vboxlayout4.setMargin(0) - self.vboxlayout4.setSpacing(6) - self.vboxlayout4.setObjectName("vboxlayout4") - - self.lb_gra_quality = QtGui.QLabel(self.verticalLayout_3) + self.lb_gra_quality = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_quality.setAlignment(QtCore.Qt.AlignCenter) self.lb_gra_quality.setObjectName("lb_gra_quality") - self.vboxlayout4.addWidget(self.lb_gra_quality) + self.vboxlayout3.addWidget(self.lb_gra_quality) - self.sl_gra_quality = QtGui.QSlider(self.verticalLayout_3) + self.sl_gra_quality = QtGui.QSlider(self.verticalLayout_47) self.sl_gra_quality.setMinimum(0) self.sl_gra_quality.setMaximum(3) self.sl_gra_quality.setPageStep(1) @@ -253,48 +163,85 @@ self.sl_gra_quality.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_gra_quality.setTickInterval(1) self.sl_gra_quality.setObjectName("sl_gra_quality") - self.vboxlayout4.addWidget(self.sl_gra_quality) + self.vboxlayout3.addWidget(self.sl_gra_quality) - self.hboxlayout3 = QtGui.QHBoxLayout() - self.hboxlayout3.setMargin(0) - self.hboxlayout3.setSpacing(6) - self.hboxlayout3.setObjectName("hboxlayout3") + self.hboxlayout2 = QtGui.QHBoxLayout() + self.hboxlayout2.setMargin(0) + self.hboxlayout2.setSpacing(6) + self.hboxlayout2.setObjectName("hboxlayout2") - self.lb_gra_quality_low = QtGui.QLabel(self.verticalLayout_3) + self.lb_gra_quality_low = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_quality_low.setObjectName("lb_gra_quality_low") - self.hboxlayout3.addWidget(self.lb_gra_quality_low) + self.hboxlayout2.addWidget(self.lb_gra_quality_low) - self.lb_gra_quality_medium = QtGui.QLabel(self.verticalLayout_3) + self.lb_gra_quality_medium = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_quality_medium.setAlignment(QtCore.Qt.AlignCenter) self.lb_gra_quality_medium.setObjectName("lb_gra_quality_medium") - self.hboxlayout3.addWidget(self.lb_gra_quality_medium) + self.hboxlayout2.addWidget(self.lb_gra_quality_medium) - self.lb_gra_quality_high = QtGui.QLabel(self.verticalLayout_3) + self.lb_gra_quality_high = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_quality_high.setAlignment(QtCore.Qt.AlignCenter) self.lb_gra_quality_high.setObjectName("lb_gra_quality_high") - self.hboxlayout3.addWidget(self.lb_gra_quality_high) + self.hboxlayout2.addWidget(self.lb_gra_quality_high) - self.lb_gra_quality_ultra = QtGui.QLabel(self.verticalLayout_3) + self.lb_gra_quality_ultra = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_quality_ultra.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lb_gra_quality_ultra.setObjectName("lb_gra_quality_ultra") - self.hboxlayout3.addWidget(self.lb_gra_quality_ultra) + self.hboxlayout2.addWidget(self.lb_gra_quality_ultra) + self.vboxlayout3.addLayout(self.hboxlayout2) + self.vboxlayout2.addLayout(self.vboxlayout3) + + self.vboxlayout4 = QtGui.QVBoxLayout() + self.vboxlayout4.setMargin(0) + self.vboxlayout4.setSpacing(6) + self.vboxlayout4.setObjectName("vboxlayout4") + + self.lb_gra_aa = QtGui.QLabel(self.verticalLayout_47) + self.lb_gra_aa.setAlignment(QtCore.Qt.AlignCenter) + self.lb_gra_aa.setObjectName("lb_gra_aa") + self.vboxlayout4.addWidget(self.lb_gra_aa) + + self.sl_gra_antialias = QtGui.QSlider(self.verticalLayout_47) + self.sl_gra_antialias.setMinimum(0) + self.sl_gra_antialias.setMaximum(6) + self.sl_gra_antialias.setSingleStep(2) + self.sl_gra_antialias.setPageStep(2) + self.sl_gra_antialias.setProperty("value",QtCore.QVariant(0)) + self.sl_gra_antialias.setSliderPosition(0) + self.sl_gra_antialias.setTracking(False) + self.sl_gra_antialias.setOrientation(QtCore.Qt.Horizontal) + self.sl_gra_antialias.setTickPosition(QtGui.QSlider.TicksBelow) + self.sl_gra_antialias.setTickInterval(2) + self.sl_gra_antialias.setObjectName("sl_gra_antialias") + self.vboxlayout4.addWidget(self.sl_gra_antialias) + + self.hboxlayout3 = QtGui.QHBoxLayout() + self.hboxlayout3.setMargin(0) + self.hboxlayout3.setSpacing(6) + self.hboxlayout3.setObjectName("hboxlayout3") + + self.lb_gra_aa_low = QtGui.QLabel(self.verticalLayout_47) + self.lb_gra_aa_low.setObjectName("lb_gra_aa_low") + self.hboxlayout3.addWidget(self.lb_gra_aa_low) + + self.lb_gra_aa_low1 = QtGui.QLabel(self.verticalLayout_47) + self.lb_gra_aa_low1.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lb_gra_aa_low1.setObjectName("lb_gra_aa_low1") + self.hboxlayout3.addWidget(self.lb_gra_aa_low1) self.vboxlayout4.addLayout(self.hboxlayout3) + self.vboxlayout2.addLayout(self.vboxlayout4) - self.verticalLayout_8 = QtGui.QWidget(self.groupBox_gra_quality) - self.verticalLayout_8.setGeometry(QtCore.QRect(20,180,179,71)) - self.verticalLayout_8.setObjectName("verticalLayout_8") - - self.vboxlayout5 = QtGui.QVBoxLayout(self.verticalLayout_8) + self.vboxlayout5 = QtGui.QVBoxLayout() self.vboxlayout5.setMargin(0) self.vboxlayout5.setSpacing(6) self.vboxlayout5.setObjectName("vboxlayout5") - self.lb_gra_sq = QtGui.QLabel(self.verticalLayout_8) + self.lb_gra_sq = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_sq.setAlignment(QtCore.Qt.AlignCenter) self.lb_gra_sq.setObjectName("lb_gra_sq") self.vboxlayout5.addWidget(self.lb_gra_sq) - self.sl_gra_shadow = QtGui.QSlider(self.verticalLayout_8) + self.sl_gra_shadow = QtGui.QSlider(self.verticalLayout_47) self.sl_gra_shadow.setMinimum(0) self.sl_gra_shadow.setMaximum(100) self.sl_gra_shadow.setPageStep(10) @@ -312,31 +259,76 @@ self.hboxlayout4.setSpacing(6) self.hboxlayout4.setObjectName("hboxlayout4") - self.lb_gra_sq_low = QtGui.QLabel(self.verticalLayout_8) + self.lb_gra_sq_low = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_sq_low.setObjectName("lb_gra_sq_low") self.hboxlayout4.addWidget(self.lb_gra_sq_low) - self.lb_gra_sq_high = QtGui.QLabel(self.verticalLayout_8) + self.lb_gra_sq_high = QtGui.QLabel(self.verticalLayout_47) self.lb_gra_sq_high.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lb_gra_sq_high.setObjectName("lb_gra_sq_high") self.hboxlayout4.addWidget(self.lb_gra_sq_high) self.vboxlayout5.addLayout(self.hboxlayout4) + self.vboxlayout2.addLayout(self.vboxlayout5) - self.verticalLayout_6 = QtGui.QWidget(self.groupBox_gra_quality) - self.verticalLayout_6.setGeometry(QtCore.QRect(230,100,179,73)) - self.verticalLayout_6.setObjectName("verticalLayout_6") + self.verticalLayout_48 = QtGui.QWidget(self.groupBox_gra_quality) + self.verticalLayout_48.setGeometry(QtCore.QRect(250,20,201,166)) + self.verticalLayout_48.setObjectName("verticalLayout_48") - self.vboxlayout6 = QtGui.QVBoxLayout(self.verticalLayout_6) + self.vboxlayout6 = QtGui.QVBoxLayout(self.verticalLayout_48) self.vboxlayout6.setMargin(0) self.vboxlayout6.setSpacing(6) self.vboxlayout6.setObjectName("vboxlayout6") - self.lb_gra_af = QtGui.QLabel(self.verticalLayout_6) + self.vboxlayout7 = QtGui.QVBoxLayout() + self.vboxlayout7.setMargin(0) + self.vboxlayout7.setSpacing(6) + self.vboxlayout7.setObjectName("vboxlayout7") + + self.lb_gra_tq = QtGui.QLabel(self.verticalLayout_48) + self.lb_gra_tq.setAlignment(QtCore.Qt.AlignCenter) + self.lb_gra_tq.setObjectName("lb_gra_tq") + self.vboxlayout7.addWidget(self.lb_gra_tq) + + self.sl_gra_texture = QtGui.QSlider(self.verticalLayout_48) + self.sl_gra_texture.setMinimum(0) + self.sl_gra_texture.setMaximum(2) + self.sl_gra_texture.setPageStep(1) + self.sl_gra_texture.setProperty("value",QtCore.QVariant(0)) + self.sl_gra_texture.setSliderPosition(0) + self.sl_gra_texture.setTracking(False) + self.sl_gra_texture.setOrientation(QtCore.Qt.Horizontal) + self.sl_gra_texture.setTickPosition(QtGui.QSlider.TicksBelow) + self.sl_gra_texture.setTickInterval(1) + self.sl_gra_texture.setObjectName("sl_gra_texture") + self.vboxlayout7.addWidget(self.sl_gra_texture) + + self.hboxlayout5 = QtGui.QHBoxLayout() + self.hboxlayout5.setMargin(0) + self.hboxlayout5.setSpacing(6) + self.hboxlayout5.setObjectName("hboxlayout5") + + self.lb_gra_tq_low = QtGui.QLabel(self.verticalLayout_48) + self.lb_gra_tq_low.setObjectName("lb_gra_tq_low") + self.hboxlayout5.addWidget(self.lb_gra_tq_low) + + self.lb_gra_tq_high = QtGui.QLabel(self.verticalLayout_48) + self.lb_gra_tq_high.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lb_gra_tq_high.setObjectName("lb_gra_tq_high") + self.hboxlayout5.addWidget(self.lb_gra_tq_high) + self.vboxlayout7.addLayout(self.hboxlayout5) + self.vboxlayout6.addLayout(self.vboxlayout7) + + self.vboxlayout8 = QtGui.QVBoxLayout() + self.vboxlayout8.setMargin(0) + self.vboxlayout8.setSpacing(6) + self.vboxlayout8.setObjectName("vboxlayout8") + + self.lb_gra_af = QtGui.QLabel(self.verticalLayout_48) self.lb_gra_af.setAlignment(QtCore.Qt.AlignCenter) self.lb_gra_af.setObjectName("lb_gra_af") - self.vboxlayout6.addWidget(self.lb_gra_af) + self.vboxlayout8.addWidget(self.lb_gra_af) - self.sl_gra_anisotropic = QtGui.QSlider(self.verticalLayout_6) + self.sl_gra_anisotropic = QtGui.QSlider(self.verticalLayout_48) self.sl_gra_anisotropic.setMinimum(1) self.sl_gra_anisotropic.setMaximum(16) self.sl_gra_anisotropic.setSingleStep(3) @@ -347,47 +339,185 @@ self.sl_gra_anisotropic.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_gra_anisotropic.setTickInterval(5) self.sl_gra_anisotropic.setObjectName("sl_gra_anisotropic") - self.vboxlayout6.addWidget(self.sl_gra_anisotropic) + self.vboxlayout8.addWidget(self.sl_gra_anisotropic) - self.hboxlayout5 = QtGui.QHBoxLayout() - self.hboxlayout5.setMargin(0) - self.hboxlayout5.setSpacing(6) - self.hboxlayout5.setObjectName("hboxlayout5") + self.hboxlayout6 = QtGui.QHBoxLayout() + self.hboxlayout6.setMargin(0) + self.hboxlayout6.setSpacing(6) + self.hboxlayout6.setObjectName("hboxlayout6") - self.lb_gra_af_low = QtGui.QLabel(self.verticalLayout_6) + self.lb_gra_af_low = QtGui.QLabel(self.verticalLayout_48) self.lb_gra_af_low.setObjectName("lb_gra_af_low") - self.hboxlayout5.addWidget(self.lb_gra_af_low) + self.hboxlayout6.addWidget(self.lb_gra_af_low) - self.lb_gra_af_high = QtGui.QLabel(self.verticalLayout_6) + self.lb_gra_af_high = QtGui.QLabel(self.verticalLayout_48) self.lb_gra_af_high.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lb_gra_af_high.setObjectName("lb_gra_af_high") - self.hboxlayout5.addWidget(self.lb_gra_af_high) - self.vboxlayout6.addLayout(self.hboxlayout5) - self.tabwidget.addTab(self.tab_graphics,"") + self.hboxlayout6.addWidget(self.lb_gra_af_high) + self.vboxlayout8.addLayout(self.hboxlayout6) + self.vboxlayout6.addLayout(self.vboxlayout8) + self.tab_sub_settings.addTab(self.tab_graphics,"") self.tab_audio = QtGui.QWidget() self.tab_audio.setObjectName("tab_audio") + self.groupBox_aud_hardware = QtGui.QGroupBox(self.tab_audio) + self.groupBox_aud_hardware.setEnabled(True) + self.groupBox_aud_hardware.setGeometry(QtCore.QRect(10,260,471,111)) + self.groupBox_aud_hardware.setObjectName("groupBox_aud_hardware") + + self.verticalLayout_61 = QtGui.QWidget(self.groupBox_aud_hardware) + self.verticalLayout_61.setGeometry(QtCore.QRect(20,20,191,75)) + self.verticalLayout_61.setObjectName("verticalLayout_61") + + self.vboxlayout9 = QtGui.QVBoxLayout(self.verticalLayout_61) + self.vboxlayout9.setMargin(0) + self.vboxlayout9.setSpacing(6) + self.vboxlayout9.setObjectName("vboxlayout9") + + self.lb_aud_device_modes = QtGui.QLabel(self.verticalLayout_61) + self.lb_aud_device_modes.setAlignment(QtCore.Qt.AlignCenter) + self.lb_aud_device_modes.setObjectName("lb_aud_device_modes") + self.vboxlayout9.addWidget(self.lb_aud_device_modes) + + self.lb_aud_device = QtGui.QLabel(self.verticalLayout_61) + self.lb_aud_device.setAlignment(QtCore.Qt.AlignCenter) + self.lb_aud_device.setObjectName("lb_aud_device") + self.vboxlayout9.addWidget(self.lb_aud_device) + + self.sl_aud_device = QtGui.QSlider(self.verticalLayout_61) + self.sl_aud_device.setMaximum(2) + self.sl_aud_device.setPageStep(1) + self.sl_aud_device.setSliderPosition(0) + self.sl_aud_device.setTracking(False) + self.sl_aud_device.setOrientation(QtCore.Qt.Horizontal) + self.sl_aud_device.setTickPosition(QtGui.QSlider.TicksBelow) + self.sl_aud_device.setTickInterval(1) + self.sl_aud_device.setObjectName("sl_aud_device") + self.vboxlayout9.addWidget(self.sl_aud_device) + + self.verticalLayout_60 = QtGui.QWidget(self.groupBox_aud_hardware) + self.verticalLayout_60.setGeometry(QtCore.QRect(250,15,191,79)) + self.verticalLayout_60.setObjectName("verticalLayout_60") + + self.vboxlayout10 = QtGui.QVBoxLayout(self.verticalLayout_60) + self.vboxlayout10.setMargin(0) + self.vboxlayout10.setSpacing(6) + self.vboxlayout10.setObjectName("vboxlayout10") + + self.cb_aud_eax = QtGui.QCheckBox(self.verticalLayout_60) + self.cb_aud_eax.setObjectName("cb_aud_eax") + self.vboxlayout10.addWidget(self.cb_aud_eax) + + self.lb_aud_priority_3 = QtGui.QLabel(self.verticalLayout_60) + self.lb_aud_priority_3.setAlignment(QtCore.Qt.AlignCenter) + self.lb_aud_priority_3.setObjectName("lb_aud_priority_3") + self.vboxlayout10.addWidget(self.lb_aud_priority_3) + + self.sl_aud_priority = QtGui.QSlider(self.verticalLayout_60) + self.sl_aud_priority.setMaximum(9) + self.sl_aud_priority.setPageStep(1) + self.sl_aud_priority.setSliderPosition(0) + self.sl_aud_priority.setTracking(False) + self.sl_aud_priority.setOrientation(QtCore.Qt.Horizontal) + self.sl_aud_priority.setTickPosition(QtGui.QSlider.TicksBelow) + self.sl_aud_priority.setTickInterval(3) + self.sl_aud_priority.setObjectName("sl_aud_priority") + self.vboxlayout10.addWidget(self.sl_aud_priority) + + self.groupBox_voicechat = QtGui.QGroupBox(self.tab_audio) + self.groupBox_voicechat.setEnabled(True) + self.groupBox_voicechat.setGeometry(QtCore.QRect(10,170,471,91)) + self.groupBox_voicechat.setObjectName("groupBox_voicechat") + + self.cb_aud_voicechat = QtGui.QCheckBox(self.groupBox_voicechat) + self.cb_aud_voicechat.setGeometry(QtCore.QRect(250,40,171,19)) + self.cb_aud_voicechat.setObjectName("cb_aud_voicechat") + + self.verticalLayout_62 = QtGui.QWidget(self.groupBox_voicechat) + self.verticalLayout_62.setGeometry(QtCore.QRect(20,20,191,54)) + self.verticalLayout_62.setObjectName("verticalLayout_62") + + self.vboxlayout11 = QtGui.QVBoxLayout(self.verticalLayout_62) + self.vboxlayout11.setMargin(0) + self.vboxlayout11.setSpacing(6) + self.vboxlayout11.setObjectName("vboxlayout11") + + self.lb_aud_microphon = QtGui.QLabel(self.verticalLayout_62) + self.lb_aud_microphon.setEnabled(False) + self.lb_aud_microphon.setAlignment(QtCore.Qt.AlignCenter) + self.lb_aud_microphon.setObjectName("lb_aud_microphon") + self.vboxlayout11.addWidget(self.lb_aud_microphon) + + self.sl_aud_microphon = QtGui.QSlider(self.verticalLayout_62) + self.sl_aud_microphon.setEnabled(False) + self.sl_aud_microphon.setMinimum(0) + self.sl_aud_microphon.setMaximum(100) + self.sl_aud_microphon.setPageStep(10) + self.sl_aud_microphon.setProperty("value",QtCore.QVariant(0)) + self.sl_aud_microphon.setSliderPosition(0) + self.sl_aud_microphon.setTracking(False) + self.sl_aud_microphon.setOrientation(QtCore.Qt.Horizontal) + self.sl_aud_microphon.setTickPosition(QtGui.QSlider.TicksBelow) + self.sl_aud_microphon.setTickInterval(25) + self.sl_aud_microphon.setObjectName("sl_aud_microphon") + self.vboxlayout11.addWidget(self.sl_aud_microphon) + self.groupBox_aud_level = QtGui.QGroupBox(self.tab_audio) self.groupBox_aud_level.setEnabled(True) - self.groupBox_aud_level.setGeometry(QtCore.QRect(10,10,431,141)) + self.groupBox_aud_level.setGeometry(QtCore.QRect(10,0,471,171)) self.groupBox_aud_level.setObjectName("groupBox_aud_level") - self.verticalLayout_12 = QtGui.QWidget(self.groupBox_aud_level) - self.verticalLayout_12.setGeometry(QtCore.QRect(230,80,179,43)) - self.verticalLayout_12.setObjectName("verticalLayout_12") + self.widget = QtGui.QWidget(self.groupBox_aud_level) + self.widget.setGeometry(QtCore.QRect(250,20,191,139)) + self.widget.setObjectName("widget") - self.vboxlayout7 = QtGui.QVBoxLayout(self.verticalLayout_12) - self.vboxlayout7.setMargin(0) - self.vboxlayout7.setSpacing(6) - self.vboxlayout7.setObjectName("vboxlayout7") + self.vboxlayout12 = QtGui.QVBoxLayout(self.widget) + self.vboxlayout12.setMargin(0) + self.vboxlayout12.setSpacing(6) + self.vboxlayout12.setObjectName("vboxlayout12") - self.lb_aud_npc = QtGui.QLabel(self.verticalLayout_12) + self.verticalLayout_58 = QtGui.QWidget(self.widget) + self.verticalLayout_58.setObjectName("verticalLayout_58") + + self.vboxlayout13 = QtGui.QVBoxLayout(self.verticalLayout_58) + self.vboxlayout13.setMargin(0) + self.vboxlayout13.setSpacing(6) + self.vboxlayout13.setObjectName("vboxlayout13") + + self.lb_aud_ambience = QtGui.QLabel(self.verticalLayout_58) + self.lb_aud_ambience.setAlignment(QtCore.Qt.AlignCenter) + self.lb_aud_ambience.setObjectName("lb_aud_ambience") + self.vboxlayout13.addWidget(self.lb_aud_ambience) + + self.sl_aud_ambience = QtGui.QSlider(self.verticalLayout_58) + self.sl_aud_ambience.setMinimum(0) + self.sl_aud_ambience.setMaximum(100) + self.sl_aud_ambience.setPageStep(10) + self.sl_aud_ambience.setProperty("value",QtCore.QVariant(0)) + self.sl_aud_ambience.setSliderPosition(0) + self.sl_aud_ambience.setTracking(False) + self.sl_aud_ambience.setOrientation(QtCore.Qt.Horizontal) + self.sl_aud_ambience.setTickPosition(QtGui.QSlider.TicksBelow) + self.sl_aud_ambience.setTickInterval(25) + self.sl_aud_ambience.setObjectName("sl_aud_ambience") + self.vboxlayout13.addWidget(self.sl_aud_ambience) + self.vboxlayout12.addWidget(self.verticalLayout_58) + + self.verticalLayout_56 = QtGui.QWidget(self.widget) + self.verticalLayout_56.setObjectName("verticalLayout_56") + + self.vboxlayout14 = QtGui.QVBoxLayout(self.verticalLayout_56) + self.vboxlayout14.setMargin(0) + self.vboxlayout14.setSpacing(6) + self.vboxlayout14.setObjectName("vboxlayout14") + + self.lb_aud_npc = QtGui.QLabel(self.verticalLayout_56) self.lb_aud_npc.setAlignment(QtCore.Qt.AlignCenter) self.lb_aud_npc.setObjectName("lb_aud_npc") - self.vboxlayout7.addWidget(self.lb_aud_npc) + self.vboxlayout14.addWidget(self.lb_aud_npc) - self.sl_aud_npc = QtGui.QSlider(self.verticalLayout_12) + self.sl_aud_npc = QtGui.QSlider(self.verticalLayout_56) self.sl_aud_npc.setMinimum(0) self.sl_aud_npc.setMaximum(100) self.sl_aud_npc.setPageStep(10) @@ -398,23 +528,36 @@ self.sl_aud_npc.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_aud_npc.setTickInterval(25) self.sl_aud_npc.setObjectName("sl_aud_npc") - self.vboxlayout7.addWidget(self.sl_aud_npc) + self.vboxlayout14.addWidget(self.sl_aud_npc) + self.vboxlayout12.addWidget(self.verticalLayout_56) - self.verticalLayout_9 = QtGui.QWidget(self.groupBox_aud_level) - self.verticalLayout_9.setGeometry(QtCore.QRect(20,30,179,43)) - self.verticalLayout_9.setObjectName("verticalLayout_9") + self.cb_aud_mute = QtGui.QCheckBox(self.widget) + self.cb_aud_mute.setObjectName("cb_aud_mute") + self.vboxlayout12.addWidget(self.cb_aud_mute) - self.vboxlayout8 = QtGui.QVBoxLayout(self.verticalLayout_9) - self.vboxlayout8.setMargin(0) - self.vboxlayout8.setSpacing(6) - self.vboxlayout8.setObjectName("vboxlayout8") + self.widget1 = QtGui.QWidget(self.groupBox_aud_level) + self.widget1.setGeometry(QtCore.QRect(20,20,191,112)) + self.widget1.setObjectName("widget1") - self.lb_aud_fx = QtGui.QLabel(self.verticalLayout_9) - self.lb_aud_fx.setAlignment(QtCore.Qt.AlignCenter) - self.lb_aud_fx.setObjectName("lb_aud_fx") - self.vboxlayout8.addWidget(self.lb_aud_fx) + self.vboxlayout15 = QtGui.QVBoxLayout(self.widget1) + self.vboxlayout15.setMargin(0) + self.vboxlayout15.setSpacing(6) + self.vboxlayout15.setObjectName("vboxlayout15") - self.sl_aud_fx = QtGui.QSlider(self.verticalLayout_9) + self.verticalLayout_57 = QtGui.QWidget(self.widget1) + self.verticalLayout_57.setObjectName("verticalLayout_57") + + self.vboxlayout16 = QtGui.QVBoxLayout(self.verticalLayout_57) + self.vboxlayout16.setMargin(0) + self.vboxlayout16.setSpacing(6) + self.vboxlayout16.setObjectName("vboxlayout16") + + self.lb_aud_fx_3 = QtGui.QLabel(self.verticalLayout_57) + self.lb_aud_fx_3.setAlignment(QtCore.Qt.AlignCenter) + self.lb_aud_fx_3.setObjectName("lb_aud_fx_3") + self.vboxlayout16.addWidget(self.lb_aud_fx_3) + + self.sl_aud_fx = QtGui.QSlider(self.verticalLayout_57) self.sl_aud_fx.setMinimum(0) self.sl_aud_fx.setMaximum(100) self.sl_aud_fx.setPageStep(10) @@ -425,50 +568,23 @@ self.sl_aud_fx.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_aud_fx.setTickInterval(25) self.sl_aud_fx.setObjectName("sl_aud_fx") - self.vboxlayout8.addWidget(self.sl_aud_fx) + self.vboxlayout16.addWidget(self.sl_aud_fx) + self.vboxlayout15.addWidget(self.verticalLayout_57) - self.verticalLayout_10 = QtGui.QWidget(self.groupBox_aud_level) - self.verticalLayout_10.setGeometry(QtCore.QRect(230,30,179,43)) - self.verticalLayout_10.setObjectName("verticalLayout_10") + self.verticalLayout_59 = QtGui.QWidget(self.widget1) + self.verticalLayout_59.setObjectName("verticalLayout_59") - self.vboxlayout9 = QtGui.QVBoxLayout(self.verticalLayout_10) - self.vboxlayout9.setMargin(0) - self.vboxlayout9.setSpacing(6) - self.vboxlayout9.setObjectName("vboxlayout9") + self.vboxlayout17 = QtGui.QVBoxLayout(self.verticalLayout_59) + self.vboxlayout17.setMargin(0) + self.vboxlayout17.setSpacing(6) + self.vboxlayout17.setObjectName("vboxlayout17") - self.lb_aud_ambience = QtGui.QLabel(self.verticalLayout_10) - self.lb_aud_ambience.setAlignment(QtCore.Qt.AlignCenter) - self.lb_aud_ambience.setObjectName("lb_aud_ambience") - self.vboxlayout9.addWidget(self.lb_aud_ambience) - - self.sl_aud_ambience = QtGui.QSlider(self.verticalLayout_10) - self.sl_aud_ambience.setMinimum(0) - self.sl_aud_ambience.setMaximum(100) - self.sl_aud_ambience.setPageStep(10) - self.sl_aud_ambience.setProperty("value",QtCore.QVariant(0)) - self.sl_aud_ambience.setSliderPosition(0) - self.sl_aud_ambience.setTracking(False) - self.sl_aud_ambience.setOrientation(QtCore.Qt.Horizontal) - self.sl_aud_ambience.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_aud_ambience.setTickInterval(25) - self.sl_aud_ambience.setObjectName("sl_aud_ambience") - self.vboxlayout9.addWidget(self.sl_aud_ambience) - - self.verticalLayout_11 = QtGui.QWidget(self.groupBox_aud_level) - self.verticalLayout_11.setGeometry(QtCore.QRect(20,80,179,43)) - self.verticalLayout_11.setObjectName("verticalLayout_11") - - self.vboxlayout10 = QtGui.QVBoxLayout(self.verticalLayout_11) - self.vboxlayout10.setMargin(0) - self.vboxlayout10.setSpacing(6) - self.vboxlayout10.setObjectName("vboxlayout10") - - self.lb_aud_music = QtGui.QLabel(self.verticalLayout_11) + self.lb_aud_music = QtGui.QLabel(self.verticalLayout_59) self.lb_aud_music.setAlignment(QtCore.Qt.AlignCenter) self.lb_aud_music.setObjectName("lb_aud_music") - self.vboxlayout10.addWidget(self.lb_aud_music) + self.vboxlayout17.addWidget(self.lb_aud_music) - self.sl_aud_music = QtGui.QSlider(self.verticalLayout_11) + self.sl_aud_music = QtGui.QSlider(self.verticalLayout_59) self.sl_aud_music.setMinimum(0) self.sl_aud_music.setMaximum(100) self.sl_aud_music.setPageStep(10) @@ -479,124 +595,28 @@ self.sl_aud_music.setTickPosition(QtGui.QSlider.TicksBelow) self.sl_aud_music.setTickInterval(25) self.sl_aud_music.setObjectName("sl_aud_music") - self.vboxlayout10.addWidget(self.sl_aud_music) + self.vboxlayout17.addWidget(self.sl_aud_music) + self.vboxlayout15.addWidget(self.verticalLayout_59) + self.tab_sub_settings.addTab(self.tab_audio,"") - self.cb_aud_mute = QtGui.QCheckBox(self.groupBox_aud_level) - self.cb_aud_mute.setGeometry(QtCore.QRect(180,10,70,19)) - self.cb_aud_mute.setObjectName("cb_aud_mute") + self.tab_pymoul = QtGui.QWidget() + self.tab_pymoul.setObjectName("tab_pymoul") - self.groupBox_aud_hardware = QtGui.QGroupBox(self.tab_audio) - self.groupBox_aud_hardware.setEnabled(True) - self.groupBox_aud_hardware.setGeometry(QtCore.QRect(10,230,431,101)) - self.groupBox_aud_hardware.setObjectName("groupBox_aud_hardware") + self.groupBox_4 = QtGui.QGroupBox(self.tab_pymoul) + self.groupBox_4.setGeometry(QtCore.QRect(10,0,471,371)) + self.groupBox_4.setObjectName("groupBox_4") + self.tab_sub_settings.addTab(self.tab_pymoul,"") + self.tabwidget.addTab(self.tab_settings,"") - self.verticalLayout_14 = QtGui.QWidget(self.groupBox_aud_hardware) - self.verticalLayout_14.setGeometry(QtCore.QRect(230,40,179,43)) - self.verticalLayout_14.setObjectName("verticalLayout_14") - - self.vboxlayout11 = QtGui.QVBoxLayout(self.verticalLayout_14) - self.vboxlayout11.setMargin(0) - self.vboxlayout11.setSpacing(6) - self.vboxlayout11.setObjectName("vboxlayout11") - - self.lb_aud_priority = QtGui.QLabel(self.verticalLayout_14) - self.lb_aud_priority.setAlignment(QtCore.Qt.AlignCenter) - self.lb_aud_priority.setObjectName("lb_aud_priority") - self.vboxlayout11.addWidget(self.lb_aud_priority) - - self.sl_aud_priority = QtGui.QSlider(self.verticalLayout_14) - self.sl_aud_priority.setMaximum(9) - self.sl_aud_priority.setPageStep(1) - self.sl_aud_priority.setSliderPosition(0) - self.sl_aud_priority.setTracking(False) - self.sl_aud_priority.setOrientation(QtCore.Qt.Horizontal) - self.sl_aud_priority.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_aud_priority.setTickInterval(3) - self.sl_aud_priority.setObjectName("sl_aud_priority") - self.vboxlayout11.addWidget(self.sl_aud_priority) - - self.verticalLayout_15 = QtGui.QWidget(self.groupBox_aud_hardware) - self.verticalLayout_15.setGeometry(QtCore.QRect(20,20,179,63)) - self.verticalLayout_15.setObjectName("verticalLayout_15") - - self.vboxlayout12 = QtGui.QVBoxLayout(self.verticalLayout_15) - self.vboxlayout12.setMargin(0) - self.vboxlayout12.setSpacing(6) - self.vboxlayout12.setObjectName("vboxlayout12") - - self.lb_aud_device_modes = QtGui.QLabel(self.verticalLayout_15) - self.lb_aud_device_modes.setAlignment(QtCore.Qt.AlignCenter) - self.lb_aud_device_modes.setObjectName("lb_aud_device_modes") - self.vboxlayout12.addWidget(self.lb_aud_device_modes) - - self.lb_aud_device = QtGui.QLabel(self.verticalLayout_15) - self.lb_aud_device.setAlignment(QtCore.Qt.AlignCenter) - self.lb_aud_device.setObjectName("lb_aud_device") - self.vboxlayout12.addWidget(self.lb_aud_device) - - self.sl_aud_device = QtGui.QSlider(self.verticalLayout_15) - self.sl_aud_device.setMaximum(2) - self.sl_aud_device.setPageStep(1) - self.sl_aud_device.setSliderPosition(0) - self.sl_aud_device.setTracking(False) - self.sl_aud_device.setOrientation(QtCore.Qt.Horizontal) - self.sl_aud_device.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_aud_device.setTickInterval(1) - self.sl_aud_device.setObjectName("sl_aud_device") - self.vboxlayout12.addWidget(self.sl_aud_device) - - self.cb_aud_eax = QtGui.QCheckBox(self.groupBox_aud_hardware) - self.cb_aud_eax.setGeometry(QtCore.QRect(260,10,111,19)) - self.cb_aud_eax.setObjectName("cb_aud_eax") - - self.groupBox_voicechat = QtGui.QGroupBox(self.tab_audio) - self.groupBox_voicechat.setEnabled(True) - self.groupBox_voicechat.setGeometry(QtCore.QRect(10,150,431,71)) - self.groupBox_voicechat.setObjectName("groupBox_voicechat") - - self.verticalLayout_13 = QtGui.QWidget(self.groupBox_voicechat) - self.verticalLayout_13.setGeometry(QtCore.QRect(20,20,179,43)) - self.verticalLayout_13.setObjectName("verticalLayout_13") - - self.vboxlayout13 = QtGui.QVBoxLayout(self.verticalLayout_13) - self.vboxlayout13.setMargin(0) - self.vboxlayout13.setSpacing(6) - self.vboxlayout13.setObjectName("vboxlayout13") - - self.lb_aud_microphon = QtGui.QLabel(self.verticalLayout_13) - self.lb_aud_microphon.setEnabled(False) - self.lb_aud_microphon.setAlignment(QtCore.Qt.AlignCenter) - self.lb_aud_microphon.setObjectName("lb_aud_microphon") - self.vboxlayout13.addWidget(self.lb_aud_microphon) - - self.sl_aud_microphon = QtGui.QSlider(self.verticalLayout_13) - self.sl_aud_microphon.setEnabled(False) - self.sl_aud_microphon.setMinimum(0) - self.sl_aud_microphon.setMaximum(100) - self.sl_aud_microphon.setPageStep(10) - self.sl_aud_microphon.setProperty("value",QtCore.QVariant(0)) - self.sl_aud_microphon.setSliderPosition(0) - self.sl_aud_microphon.setTracking(False) - self.sl_aud_microphon.setOrientation(QtCore.Qt.Horizontal) - self.sl_aud_microphon.setTickPosition(QtGui.QSlider.TicksBelow) - self.sl_aud_microphon.setTickInterval(25) - self.sl_aud_microphon.setObjectName("sl_aud_microphon") - self.vboxlayout13.addWidget(self.sl_aud_microphon) - - self.cb_aud_voicechat = QtGui.QCheckBox(self.groupBox_voicechat) - self.cb_aud_voicechat.setGeometry(QtCore.QRect(250,30,171,19)) - self.cb_aud_voicechat.setObjectName("cb_aud_voicechat") - self.tabwidget.addTab(self.tab_audio,"") - self.tab_time = QtGui.QWidget() self.tab_time.setObjectName("tab_time") self.gb_caverntime = QtGui.QGroupBox(self.tab_time) - self.gb_caverntime.setGeometry(QtCore.QRect(10,10,431,101)) + self.gb_caverntime.setGeometry(QtCore.QRect(10,10,471,101)) self.gb_caverntime.setObjectName("gb_caverntime") self.gridLayout = QtGui.QWidget(self.gb_caverntime) - self.gridLayout.setGeometry(QtCore.QRect(10,20,411,71)) + self.gridLayout.setGeometry(QtCore.QRect(10,20,476,74)) self.gridLayout.setObjectName("gridLayout") self.gridlayout = QtGui.QGridLayout(self.gridLayout) @@ -649,17 +669,9 @@ self.lb_cavern_utc.setObjectName("lb_cavern_utc") self.gridlayout.addWidget(self.lb_cavern_utc,0,2,1,1) - self.label_11 = QtGui.QLabel(self.gridLayout) - self.label_11.setObjectName("label_11") - self.gridlayout.addWidget(self.label_11,0,3,1,1) - - self.label_12 = QtGui.QLabel(self.gridLayout) - self.label_12.setObjectName("label_12") - self.gridlayout.addWidget(self.label_12,1,3,1,1) - self.gb_dnitime = QtGui.QGroupBox(self.tab_time) self.gb_dnitime.setEnabled(False) - self.gb_dnitime.setGeometry(QtCore.QRect(10,120,431,221)) + self.gb_dnitime.setGeometry(QtCore.QRect(10,110,471,291)) self.gb_dnitime.setObjectName("gb_dnitime") self.tabwidget.addTab(self.tab_time,"") @@ -667,30 +679,37 @@ self.tab_ping.setObjectName("tab_ping") self.gb_servers = QtGui.QGroupBox(self.tab_ping) - self.gb_servers.setGeometry(QtCore.QRect(10,0,421,341)) + self.gb_servers.setGeometry(QtCore.QRect(10,0,471,401)) self.gb_servers.setObjectName("gb_servers") self.button_ping = QtGui.QPushButton(self.gb_servers) - self.button_ping.setGeometry(QtCore.QRect(330,310,75,24)) + self.button_ping.setGeometry(QtCore.QRect(380,370,75,24)) self.button_ping.setObjectName("button_ping") self.text_ping = QtGui.QTextEdit(self.gb_servers) - self.text_ping.setGeometry(QtCore.QRect(10,20,401,281)) - self.text_ping.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.text_ping.setGeometry(QtCore.QRect(10,20,451,341)) + self.text_ping.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) self.text_ping.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.text_ping.setReadOnly(True) self.text_ping.setObjectName("text_ping") self.tabwidget.addTab(self.tab_ping,"") - self.tab_documents = QtGui.QWidget() - self.tab_documents.setObjectName("tab_documents") + self.tab_browse = QtGui.QWidget() + self.tab_browse.setObjectName("tab_browse") - self.gb_documents = QtGui.QGroupBox(self.tab_documents) - self.gb_documents.setGeometry(QtCore.QRect(10,0,431,341)) + self.tabWidget = QtGui.QTabWidget(self.tab_browse) + self.tabWidget.setGeometry(QtCore.QRect(0,0,491,411)) + self.tabWidget.setObjectName("tabWidget") + + self.tab_sub_journals = QtGui.QWidget() + self.tab_sub_journals.setObjectName("tab_sub_journals") + + self.gb_documents = QtGui.QGroupBox(self.tab_sub_journals) + self.gb_documents.setGeometry(QtCore.QRect(10,0,471,371)) self.gb_documents.setObjectName("gb_documents") self.gridLayout_2 = QtGui.QWidget(self.gb_documents) - self.gridLayout_2.setGeometry(QtCore.QRect(10,20,411,100)) + self.gridLayout_2.setGeometry(QtCore.QRect(30,20,411,108)) self.gridLayout_2.setObjectName("gridLayout_2") self.gridlayout1 = QtGui.QGridLayout(self.gridLayout_2) @@ -738,19 +757,91 @@ self.gridlayout1.addWidget(self.cb_doc_element,3,1,1,1) self.te_doc_view = QtGui.QTextEdit(self.gb_documents) - self.te_doc_view.setGeometry(QtCore.QRect(10,130,411,201)) + self.te_doc_view.setGeometry(QtCore.QRect(10,130,451,231)) self.te_doc_view.setReadOnly(True) self.te_doc_view.setObjectName("te_doc_view") - self.tabwidget.addTab(self.tab_documents,"") + self.tabWidget.addTab(self.tab_sub_journals,"") + self.tab_sub_chatlogs = QtGui.QWidget() + self.tab_sub_chatlogs.setObjectName("tab_sub_chatlogs") + + self.groupBox_5 = QtGui.QGroupBox(self.tab_sub_chatlogs) + self.groupBox_5.setGeometry(QtCore.QRect(10,0,471,371)) + self.groupBox_5.setObjectName("groupBox_5") + + self.cb_chatlog = QtGui.QComboBox(self.groupBox_5) + self.cb_chatlog.setGeometry(QtCore.QRect(80,20,323,22)) + + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(7),QtGui.QSizePolicy.Policy(0)) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.cb_chatlog.sizePolicy().hasHeightForWidth()) + self.cb_chatlog.setSizePolicy(sizePolicy) + self.cb_chatlog.setObjectName("cb_chatlog") + + self.te_chatlog_view = QtGui.QTextEdit(self.groupBox_5) + self.te_chatlog_view.setGeometry(QtCore.QRect(10,50,451,311)) + self.te_chatlog_view.setReadOnly(True) + self.te_chatlog_view.setObjectName("te_chatlog_view") + self.tabWidget.addTab(self.tab_sub_chatlogs,"") + self.tabwidget.addTab(self.tab_browse,"") + self.tab_about = QtGui.QWidget() self.tab_about.setObjectName("tab_about") self.label_6 = QtGui.QLabel(self.tab_about) - self.label_6.setGeometry(QtCore.QRect(120,170,181,20)) + self.label_6.setGeometry(QtCore.QRect(180,210,181,20)) self.label_6.setAlignment(QtCore.Qt.AlignCenter) self.label_6.setObjectName("label_6") self.tabwidget.addTab(self.tab_about,"") + + self.main_buttonbox = QtGui.QDialogButtonBox(self.centralwidget) + self.main_buttonbox.setGeometry(QtCore.QRect(10,540,471,32)) + self.main_buttonbox.setOrientation(QtCore.Qt.Horizontal) + self.main_buttonbox.setStandardButtons(QtGui.QDialogButtonBox.Close|QtGui.QDialogButtonBox.NoButton|QtGui.QDialogButtonBox.Reset|QtGui.QDialogButtonBox.Save) + self.main_buttonbox.setObjectName("main_buttonbox") + + self.horizontalLayout = QtGui.QWidget(self.centralwidget) + self.horizontalLayout.setGeometry(QtCore.QRect(0,2,491,71)) + self.horizontalLayout.setObjectName("horizontalLayout") + + self.hboxlayout7 = QtGui.QHBoxLayout(self.horizontalLayout) + self.hboxlayout7.setMargin(0) + self.hboxlayout7.setSpacing(6) + self.hboxlayout7.setObjectName("hboxlayout7") + + spacerItem = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) + self.hboxlayout7.addItem(spacerItem) + + self.lb_top_image = QtGui.QLabel(self.horizontalLayout) + self.lb_top_image.setMinimumSize(QtCore.QSize(434,61)) + self.lb_top_image.setMaximumSize(QtCore.QSize(434,61)) + self.lb_top_image.setFrameShape(QtGui.QFrame.StyledPanel) + self.lb_top_image.setFrameShadow(QtGui.QFrame.Sunken) + self.lb_top_image.setPixmap(QtGui.QPixmap(":/resources/moul_logo.png")) + self.lb_top_image.setObjectName("lb_top_image") + self.hboxlayout7.addWidget(self.lb_top_image) + + spacerItem1 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) + self.hboxlayout7.addItem(spacerItem1) + + self.horizontalLayout_3 = QtGui.QWidget(self.centralwidget) + self.horizontalLayout_3.setGeometry(QtCore.QRect(100,70,301,31)) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + + self.hboxlayout8 = QtGui.QHBoxLayout(self.horizontalLayout_3) + self.hboxlayout8.setMargin(0) + self.hboxlayout8.setSpacing(6) + self.hboxlayout8.setObjectName("hboxlayout8") + + self.comboBox = QtGui.QComboBox(self.horizontalLayout_3) + self.comboBox.setEnabled(False) + + font = QtGui.QFont(self.comboBox.font()) + font.setPointSize(6) + self.comboBox.setFont(font) + self.comboBox.setObjectName("comboBox") + self.hboxlayout8.addWidget(self.comboBox) MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtGui.QStatusBar(MainWindow) @@ -758,74 +849,84 @@ MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) - self.tabwidget.setCurrentIndex(0) + self.tabwidget.setCurrentIndex(4) + self.tab_sub_settings.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(0) QtCore.QObject.connect(self.main_buttonbox,QtCore.SIGNAL("rejected()"),MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "Tool for Myst Online", None, QtGui.QApplication.UnicodeUTF8)) - self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "Configure", None, QtGui.QApplication.UnicodeUTF8)) + MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox_3.setTitle(QtGui.QApplication.translate("MainWindow", "GroupBox", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox_2.setTitle(QtGui.QApplication.translate("MainWindow", "GroupBox", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "GroupBox", None, QtGui.QApplication.UnicodeUTF8)) + self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_tasks), QtGui.QApplication.translate("MainWindow", "Tasks", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox_screenres.setTitle(QtGui.QApplication.translate("MainWindow", "Screen Resolution", None, QtGui.QApplication.UnicodeUTF8)) + self.lb_screenres.setText(QtGui.QApplication.translate("MainWindow... [truncated message content] |
From: <ti...@us...> - 2007-01-30 16:43:56
|
Revision: 102 http://pymoul.svn.sourceforge.net/pymoul/?rev=102&view=rev Author: tiran Date: 2007-01-30 08:43:51 -0800 (Tue, 30 Jan 2007) Log Message: ----------- Disabled moulcli Added chatview and directoryview Modified Paths: -------------- pymoul/trunk/src/moul/cli/moullauncher.py pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/tests/test_plasmalog.py pymoul/trunk/src/moul/qt/ui/mainwindow.py Modified: pymoul/trunk/src/moul/cli/moullauncher.py =================================================================== --- pymoul/trunk/src/moul/cli/moullauncher.py 2007-01-30 14:39:03 UTC (rev 101) +++ pymoul/trunk/src/moul/cli/moullauncher.py 2007-01-30 16:43:51 UTC (rev 102) @@ -102,5 +102,5 @@ ml() if __name__ == '__main__': - main(sys.argv) - + #main(sys.argv) + raise NotImplementedError("Moul Launcher disabled!") Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-01-30 14:39:03 UTC (rev 101) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-01-30 16:43:51 UTC (rev 102) @@ -41,28 +41,40 @@ from moul.log import getLogger +RE_FLAGS = re.LOCALE CHAT_RE = re.compile( r"^\((?P<M>\d{1,2})/(?P<D>\d{1,2})\ " # MM/DD r"(?P<h>\d{1,2}):(?P<m>\d\d{1,2}):(?P<s>\d{1,2})\)" # hh:mm:ss - r"(?P<space>\ {1,2})(?P<msg>.*)$") # text + r"(?P<space>\s{1,2})(?P<msg>.*)$", # text + RE_FLAGS) +CHAT_SIMPLE_RE = re.compile( + r"^\((?P<date>[\d/]*)\ (?P<time>[\d:]*)\)" # (date time) + r"(?P<space>\s{1,2})" # spaces + r"(?P<msg>.*)$", # message + RE_FLAGS) CHATLOG_STARTED = "Chat.log started..." CHATLOG_STOPPED = "...Chat.log stopped." -TEXT_MSGFROM = re.compile( - r"From (?P<user>.*) in (?P<location>.*): (?P<msg>.*)" +TEXT_MSGFROM_RE = re.compile( # From USER in LOCATION: msg + r"From (?P<user>.*) in (?P<location>.*): (?P<msg>.*)", + RE_FLAGS) +TEXT_MSGTO_RE = re.compile( + r"To (?P<user>.*): (?P<msg>.*)", # From USER in LOCATION: msg + RE_FLAGS) +TEXT_ERROR_RE = re.compile( + r"Error: (?P<msg>.*)", # Error: message + RE_FLAGS) +TEXT_RE = re.compile( + r"(?P<user>.*): (?P<msg>.*)", # User: message + RE_FLAGS) +CHATLOG_DATE_FNAME_RE = re.compile( + r"chatlog_(?P<Y>\d{4})(?P<M>\d{2})(?P<D>\d{2})_" # chatlog_YYMMDD_ + r"(?P<ch>\d{2})(?P<cm>\d{2})_(?P<sh>\d{2})(?P<sm>\d{2})\.txt", # hhmm_hhmm.txt + RE_FLAGS ) -TEXT_MSGTO = re.compile( - r"To (?P<user>.*): (?P<msg>.*)" - # From USER in LOCATION: msg - ) -TEXT_ERROR = re.compile( - r"Error: (?P<msg>.*)" - # Error: message - ) -TEXT = re.compile( - r"(?P<user>.*): (?P<msg>.*)" - # User: message - ) +#CHATLOG_FNAME_RE = re.compile( +# r"[cC]hat.*\.log", # chat*.log +# RE_FLAGS) LOG = getLogger('moul.chat') @@ -162,3 +174,95 @@ def __call__(self): self.findLogs() self.moveChatlogs() + +class ChatlogDirectoryView(object): + """A view of a chat log directory + + Lists all chat logs in the directory + """ + def __init__(self, logdir): + self._logdir = logdir + self._logfiles = [] # list of ChatlogViews + + if not os.path.isdir(logdir): + LOG.critical("%s is not a directory" % logdir) + self._findChatlogs() + + def _findChatlogs(self): + """Find chat logs in logdir directory + """ + for name in os.listdir(self._logdir): + fname = os.path.join(self._logdir, name) + if not os.path.isfile(fname): + continue + chatlog = ChatlogView(fname) + if chatlog.date is not None: + self._logfiles.append(chatlog) + + @property + def names(self): + return [clv.name for clv in self] + + def __iter__(self): + return iter(self._logfiles) + +class ChatlogView(object): + """A view of a single chat log file + """ + + def __init__(self, fname): + self._fname = fname + self._name = os.path.basename(fname) + self._opened = False + + self._parsed = None + self._fd = None + self._date = None + + if not os.path.isfile(fname): + LOG.critical("%s is not a file" % fname) + + @property + def name(self): + """Plain file name + """ + return self._name + + @property + def date(self): + """Date + """ + if self._date: + return self._date + mo = CHATLOG_DATE_FNAME_RE.match(self.name) + if not mo: + # urks + return None + d = mo.groupdict() + self._date = d + return d + + def open(self): + """Open fhe file + """ + if not self._opened: + self._fd = open(self._fname, 'r') + self._opened = True + + def close(self): + """Close the file + """ + if self._opened: + self._fd.close() + self._fd = None + self._parsed = None + self._opened = False + + def view(self): + """View the file + + Returns an iterator which iterates over the lines of the file + """ + self.open() + # TODO: add parser, currently simply iterates over the file + return iter(self._fd) Modified: pymoul/trunk/src/moul/file/tests/test_plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-01-30 14:39:03 UTC (rev 101) +++ pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-01-30 16:43:51 UTC (rev 102) @@ -30,6 +30,8 @@ from moul.file.plasmalog import PlasmalogZipper from moul.file.chatlog import ChatlogMover +from moul.file.chatlog import ChatlogDirectoryView +from moul.file.chatlog import ChatlogView from moul.file.kiimage import KIImageFixer from moul.file.kiimage import KIImage @@ -124,7 +126,17 @@ self.failUnless(c.startswith("chatlog_")) self.failUnless(c.endswith(".txt")) self.failUnlessEqual(len(c), length, c) + + def test_chatlogview(self): + clm = ChatlogMover(self._logdir, self._chatdest) + clm.findLogs() + clm.moveChatlogs() + cdv = ChatlogDirectoryView(self._chatdest) + names = cdv.names + self.failUnlessEqual(len(names), 1, names) + self.failUnless(names[0].startswith("chatlog_")) + def test_kiImageMover(self): kif = KIImageFixer(self._kidir, self._kidest) self.failUnless(os.path.isdir(self._kidest), self._kidest) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-30 14:39:03 UTC (rev 101) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-01-30 16:43:51 UTC (rev 102) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src/moul/qt/ui/mainwindow.ui' # -# Created: Tue Jan 30 15:36:49 2007 +# Created: Tue Jan 30 17:23:46 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -849,7 +849,7 @@ MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) - self.tabwidget.setCurrentIndex(4) + self.tabwidget.setCurrentIndex(0) self.tab_sub_settings.setCurrentIndex(0) self.tabWidget.setCurrentIndex(0) QtCore.QObject.connect(self.main_buttonbox,QtCore.SIGNAL("rejected()"),MainWindow.close) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-01 03:07:31
|
Revision: 113 http://pymoul.svn.sourceforge.net/pymoul/?rev=113&view=rev Author: tiran Date: 2007-01-31 19:07:31 -0800 (Wed, 31 Jan 2007) Log Message: ----------- Moved stuff from config to *Directory classes Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/file/directory.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-02-01 02:39:34 UTC (rev 112) +++ pymoul/trunk/src/moul/config/__init__.py 2007-02-01 03:07:31 UTC (rev 113) @@ -69,7 +69,7 @@ return value elif default is _marker: raise KeyError(section) - + def setOption(self, section, name=None, value=_marker): """Set configuratin option """ @@ -82,15 +82,15 @@ del sec[name] else: sec[name] = value - + def addSection(self, section): """Add a new configuration section """ return self.setdefault(section, {}) - + def listConfig(self): """List - + >>> cfg = listConfig() >>> len(cfg) > 0 True @@ -115,35 +115,15 @@ ## directories class Directories(object): - - _dirmapping = { - 'install' : "%(installdir)s", - 'loc' : "%(installdir)s/dat", - 'dat' : "%(installdir)s/dat", - 'sound' : "%(installdir)s/sfx", - 'soundwav' : "%(installdir)s/sfx/streamingCache", - 'video' : "%(installdir)s/avi", - - 'userdata' : "%(datadir)s", - 'log' : "%(datadir)s/Log", - 'kiimages' : "%(datadir)s/KIimages", - 'avatars' : "%(datadir)s/Avatars", - 'chatlogs' : "%(datadir)s/chatlogs", - 'ini' : "%(datadir)s/init", - - 'pymoul.ini' : "%(pymouldir)s/pymoul.ini", - } - + """TODO: to be replaced or removed + """ + def __init__(self, config): - self._cache = {} self._config = config - - def clearCache(self): - self._cache.clear() def getMoulInstallDir(self): return self._config.getOption('moul.installdir') - + def getMoulUserDataDir(self): return getMoulUserDataDir() @@ -153,31 +133,11 @@ def lookupDir(self, name): """Lookup MOUL directory """ - cached = self._cache.get(name, None) - if cached: - return cached - path = self._dirmapping.get(name) - path = path.replace('/', os.sep) - map = {'installdir' : self.getMoulInstallDir(), - 'datadir' : self.getMoulUserDataDir(), - 'pymouldir' : self.getPyMoulDataDir(), + map = {'install' : self.getMoulInstallDir, + 'userdata' : self.getMoulUserDataDir, + 'pymouldir' : self.getPyMoulDataDir, } - fullpath = path % map - #self._cache[name] = fullpath - return fullpath - - def listDirs(self): - """List all MOUL dirs - - >>> dirs = listDirs() - >>> len(dirs) - 13 - >>> type(dirs) - <type 'dict'> - """ - return dict([(name, self.lookupDir(name)) for name in self._dirmapping]) + return map[name]() _directories = Directories(_configuration) -clearCache = _directories.clearCache lookupDir = _directories.lookupDir -listDirs = _directories.listDirs Modified: pymoul/trunk/src/moul/file/directory.py =================================================================== --- pymoul/trunk/src/moul/file/directory.py 2007-02-01 02:39:34 UTC (rev 112) +++ pymoul/trunk/src/moul/file/directory.py 2007-02-01 03:07:31 UTC (rev 113) @@ -34,6 +34,25 @@ LOG = getLogger('moul.file.directory') +class DirectoryCount(object): + """Counts how many files are inside a directory + """ + + def __init__(self, path): + self._basepath = path + self._count = 0 + if not os.path.isdir(path): + self._count = None + return + # TODO: fnmatch + for name in os.listdir(path): + if os.path.isfile(os.path.join(path, name)): + self._count+=1 + + @property + def count(self): + return self._count + class AbstractUruDirectory(object): """Abstract class for an Uru directory """ @@ -66,6 +85,8 @@ """ args = [] factory, argnames = self._factories[name] + if not self.exists(argnames[0]): + return None for name in argnames: args.append(self.get(name)) return factory(*args) @@ -112,19 +133,27 @@ 'graphics.ini' : (GraphicsIni, ('ini',)), 'audio.ini' : (AudioIni, ('ini',)), 'chatlogs' : (ChatlogDirectoryView, ('chatlogs',)), - 'zipped' : None, - 'fixed' : None, + 'zipped' : (DirectoryCount, ('zipped',)), + 'fixed' : (DirectoryCount, ('fixed',)), } + def create(self, name): + """Create a directory + """ + if not name or name == '.': + raise ValueError("Cannot create() basedir") + path = self.get(name) + os.makedirs(path) + def createTree(self): """Create the directory tree """ created = [] - if self.exists(''): + if not self.exists(''): os.mkdir(self._basepath) created.append(self._basepath) for key in self._dirmapping: if not self.exists(key): - os.mkdir(path) + self.create(key) created.append(path) return created This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-02 00:49:50
|
Revision: 115 http://pymoul.svn.sourceforge.net/pymoul/?rev=115&view=rev Author: tiran Date: 2007-02-01 16:49:08 -0800 (Thu, 01 Feb 2007) Log Message: ----------- Lot's of fixed. The moul.file.* don't break with an OSError/IOError when the files do not exist Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/directory.py pymoul/trunk/src/moul/file/kiimage.py pymoul/trunk/src/moul/file/plasmalog.py pymoul/trunk/src/moul/file/tests/test_directory.py pymoul/trunk/src/moul/file/tests/utils.py pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/qt/localization.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/config/__init__.py 2007-02-02 00:49:08 UTC (rev 115) @@ -111,7 +111,8 @@ listConfig = _configuration.listConfig # hard coded for my system -setOption('moul', 'installdir', 'D:\\games\\MystOnline') +#setOption('moul', 'installdir', 'D:\\games\\MystOnline') +setOption('moul', 'installdir', '/home/heimes/dev/pymoul/MystOnline') ## directories class Directories(object): @@ -136,6 +137,7 @@ map = {'install' : self.getMoulInstallDir, 'userdata' : self.getMoulUserDataDir, 'pymouldir' : self.getPyMoulDataDir, + 'ini' : self.getPyMoulDataDir, } return map[name]() Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-02-02 00:49:08 UTC (rev 115) @@ -94,7 +94,7 @@ self._dest = destdir self._logs = [] if not os.path.isdir(srcdir): - LOG.critical("%s is not a directory" % srcdir) + LOG.warning("%s is not a directory" % srcdir) if not os.path.isdir(destdir): LOG.info("Creating chatlog directory %s" % destdir) os.mkdir(destdir) @@ -185,7 +185,7 @@ self._logfiles = [] # list of ChatlogViews if not os.path.isdir(logdir): - LOG.critical("%s is not a directory" % logdir) + LOG.warning("%s is not a directory" % logdir) self._findChatlogs() def _findChatlogs(self): @@ -220,7 +220,7 @@ self._date = None if not os.path.isfile(fname): - LOG.critical("%s is not a file" % fname) + LOG.warning("%s is not a file" % fname) @property def name(self): Modified: pymoul/trunk/src/moul/file/directory.py =================================================================== --- pymoul/trunk/src/moul/file/directory.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/file/directory.py 2007-02-02 00:49:08 UTC (rev 115) @@ -78,8 +78,11 @@ @param basepath: absolute path to folder @type basepath: str """ - self._basepath = basepath + for key in self._factories: + if key in self.__class__.__dict__: + raise AttributeError("Name %s is reserved and can't be used " + "as a factory name" % name) def exists(self, name=None): """Check if directory with name exists. @@ -99,7 +102,7 @@ @rtype: str """ if name and name != '.': - path = self._dirmapping(name) + path = self._dirmapping[name] else: path = '' return os.path.join(self._basepath, path) @@ -111,14 +114,24 @@ @type name: str @return: Factory instance """ + try: + return getattr(self, name) + except AttributeError: + pass args = [] factory, argnames = self._factories[name] - if not self.exists(argnames[0]): - return None for name in argnames: args.append(self.get(name)) return factory(*args) + def initializeFactories(self): + """Create instance attributes with factory instances + """ + for key in self._factories: + fac = self.factory(key) + if fac is not None: + setattr(self, key, fac) + class UruGameDataDirectory(AbstractUruDirectory): """Uru game directory handler @@ -144,7 +157,7 @@ data. """ _dirmapping = { - 'log' : 'Log', + 'logs' : 'Logs', 'kiimages' : 'KIimages', 'avatars' : 'Avatars', 'ini' : 'init', @@ -154,8 +167,8 @@ } _factories = { - 'logchat' : (ChatlogMover, ('log', 'chatlogs')), - 'logzip' : (PlasmalogZipper, ('log', 'zipped')), + 'logchat' : (ChatlogMover, ('logs', 'chatlogs')), + 'logzip' : (PlasmalogZipper, ('logs', 'zipped')), 'kiimages' : (KIImageFixer, ('kiimages', 'fixed')), 'avatars' : (KIImageFixer, ('avatars', 'fixed')), 'graphicsini' : (GraphicsIni, ('ini',)), @@ -165,6 +178,11 @@ 'fixed' : (DirectoryCount, ('fixed',)), } + def __init__(self, basepath): + AbstractUruDirectory.__init__(self, basepath) + if self.exists(): + self.initializeFactories() + def create(self, name): """Create a directory @@ -175,6 +193,7 @@ raise ValueError("Cannot create() basedir") path = self.get(name) os.makedirs(path) + return path def createTree(self): """Create the directory tree @@ -188,6 +207,6 @@ created.append(self._basepath) for key in self._dirmapping: if not self.exists(key): - self.create(key) + path = self.create(key) created.append(path) return created Modified: pymoul/trunk/src/moul/file/kiimage.py =================================================================== --- pymoul/trunk/src/moul/file/kiimage.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/file/kiimage.py 2007-02-02 00:49:08 UTC (rev 115) @@ -224,8 +224,7 @@ self._fixed = [] # fixed files if not os.path.isdir(srcdir): - LOG.critical("%s is not a directory" % srcdir) - return False + LOG.warning("%s is not a directory" % srcdir) if not os.path.isdir(destdir): LOG.info("Creating chatlog directory %s" % destdir) os.mkdir(destdir) Modified: pymoul/trunk/src/moul/file/plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/plasmalog.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/file/plasmalog.py 2007-02-02 00:49:08 UTC (rev 115) @@ -47,10 +47,10 @@ self._not_removed = [] # files with full path if not os.path.isdir(srcdir): - LOG.critical("%s is not a directory" % srcdir) + LOG.warning("%s is not a directory" % srcdir) if not self.isPlasmaLogDir(): self._ispldir = False - LOG.critical("%s is not a plasma log directory" % srcdir) + LOG.warning("%s is not a plasma log directory" % srcdir) else: self._ispldir = True if not os.path.isdir(destdir): Modified: pymoul/trunk/src/moul/file/tests/test_directory.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_directory.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/file/tests/test_directory.py 2007-02-02 00:49:08 UTC (rev 115) @@ -21,6 +21,7 @@ __version__ = "$Id$" __revision__ = "$Revision$" +import os import unittest from doctest import DocTestSuite @@ -34,27 +35,67 @@ from moul.file.tests.utils import base class AbstractTest(unittest.TestCase): + klass = None + + def setUp(self): + self._tmpdir = mkTempdir() + fakeUruGameDir(self._tmpdir) + self.urudir = self.klass(self._tmpdir) + def tearDown(self): rmTempdir(self._tmpdir) def test_exists(self): - self.failUnless(self.urudir.exists) + self.failUnless(self.urudir.exists()) + for d in self.urudir._dirmapping: + self.urudir.exists(d) + def test_dumbfactorycreate(self): + for name in self.urudir._factories: + f = self.urudir.factory(name) + self.failUnless(f, str((type(f), repr(f), name))) + class UruPersonalDirTest(AbstractTest): - def setUp(self): + klass = UruPersonalDataDirectory + + def test_nodir(self): + # setup a new, empty testing direcotry + rmTempdir(self._tmpdir) self._tmpdir = mkTempdir() - fakeUruPersonalDataDir(self._tmpdir) - self.urudir = UruPersonalDataDirectory(self._tmpdir) + tmpdir = os.path.join(self._tmpdir, 'UruLive') -class UruGameDirTest(AbstractTest): - def setUp(self): + self.urudir = self.klass(tmpdir) + self.failIf(self.urudir.exists()) + self.failIf(self.urudir.factory('audioini').exists()) + self.failIf(self.urudir.factory('graphicsini').exists()) + + self.urudir.createTree() + self.failUnless(self.urudir.exists()) + self.urudir.initializeFactories() + self.failIf(self.urudir.audioini.exists()) + self.failIf(self.urudir.graphicsini.exists()) + + def test_create(self): + # setup a new, empty testing direcotry + rmTempdir(self._tmpdir) self._tmpdir = mkTempdir() - fakeUruGameDir(self._tmpdir) - self.urudir = UruGameDataDirectory(self._tmpdir) - def test_foo(self): - pass + self.urudir = self.klass(self._tmpdir) + #self.urudir.createTree() + self.failUnless(self.urudir.exists()) + self.urudir.initializeFactories() + self.failIf(self.urudir.audioini.exists()) + self.urudir.audioini.create() + self.failUnless(self.urudir.audioini.exists()) + + self.failIf(self.urudir.graphicsini.exists()) + self.urudir.graphicsini.create() + self.failUnless(self.urudir.graphicsini.exists()) + +class UruGameDirTest(AbstractTest): + klass = UruGameDataDirectory + def test_suite(): return unittest.TestSuite(( unittest.makeSuite(UruPersonalDirTest), Modified: pymoul/trunk/src/moul/file/tests/utils.py =================================================================== --- pymoul/trunk/src/moul/file/tests/utils.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/file/tests/utils.py 2007-02-02 00:49:08 UTC (rev 115) @@ -74,7 +74,7 @@ def fakeUruGameDir(path): """Create a fake Uru Live game directory """ - for dname in ('dat', 'sfx', 'avi'): + for dname in ('dat', 'sfx', 'avi', 'sfx' + os.sep + 'streamingCache'): os.mkdir(os.path.join(path, dname)) for fname in ('UruLauncher.exe', 'UruExplorer.exe'): # XXX: win32 fd = open(os.path.join(path, fname), 'wb') Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-02-02 00:49:08 UTC (rev 115) @@ -312,13 +312,18 @@ def __init__(self, path): if not os.path.isdir(path): - raise OSError("Directory not found %s" % path) + LOG.warning("Directory not found %s" % path) self._fpath = os.path.join(path, self._filename) self._filedata = {} self._newdata = {} self._order = [] self._opened = False + def exists(self): + """Check if file exists + """ + return os.path.isfile(self._fpath) + def clear(self): """Clear all informations """ @@ -360,6 +365,10 @@ """ if self._opened: raise ValueError("File already open") + dirname = os.path.dirname(self._fpath) + if not os.path.isdir(dirname): + LOG.info("Creating directory %s" % dirname) + os.mkdir(dirname) # Create a dummy file fd = open(self._fpath, 'w') fd.write("Created by pyMoul") Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-02-01 13:47:36 UTC (rev 114) +++ pymoul/trunk/src/moul/qt/localization.py 2007-02-02 00:49:08 UTC (rev 115) @@ -48,7 +48,8 @@ Mixin for documentation tab """ def _documents_init(self): - locDir = lookupDir('loc') + return + locDir = lookupDir('loc') if not os.path.isdir(locDir): return This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-02 03:32:29
|
Revision: 116 http://pymoul.svn.sourceforge.net/pymoul/?rev=116&view=rev Author: tiran Date: 2007-02-01 19:32:28 -0800 (Thu, 01 Feb 2007) Log Message: ----------- Added error handling and threadlet Modified Paths: -------------- pymoul/trunk/src/moul/file/directory.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py Added Paths: ----------- pymoul/trunk/src/moul/qt/errorhandler.py pymoul/trunk/src/moul/qt/threadlet.py Modified: pymoul/trunk/src/moul/file/directory.py =================================================================== --- pymoul/trunk/src/moul/file/directory.py 2007-02-02 00:49:08 UTC (rev 115) +++ pymoul/trunk/src/moul/file/directory.py 2007-02-02 03:32:28 UTC (rev 116) @@ -145,7 +145,7 @@ 'soundwav' : 'sfx' + os.sep + 'streamingCache', 'video' : 'avi', } - _factory = { + _factories = { 'loc' : (parseLocDirectory, ('loc',)), } Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-02-02 00:49:08 UTC (rev 115) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-02-02 03:32:28 UTC (rev 116) @@ -93,7 +93,7 @@ finally: if fd: fd.close() - except IoError: + except IOError: continue details = {} for line in status: Added: pymoul/trunk/src/moul/qt/errorhandler.py =================================================================== --- pymoul/trunk/src/moul/qt/errorhandler.py (rev 0) +++ pymoul/trunk/src/moul/qt/errorhandler.py 2007-02-02 03:32:28 UTC (rev 116) @@ -0,0 +1,118 @@ +#!/usr/bin/env python2.5 +# pyMoul - Python interface to Myst Online URU Live +# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> + +# This program 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 program 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +"""Error handling for moul qt + +The module installs a custom exception hook that shows unhandled traceback in +the ui. It also contains several functions to create message boxes. +""" +__author__ = "Christian Heimes" +__version__ = "$Id" +__revision__ = "$Revision$" + +import sys +import os +from traceback import format_exception + +from PyQt4 import QtGui +from PyQt4 import QtCore +from PyQt4.QtCore import Qt + +from moul.log import getLogger + +LOG = getLogger('moul.qt.error') + +def trUtf8(s): + return s + +def qtexcepthook(typ, value, traceback): + """ + Custom exception hood to announce error inside the UI + """ + # TODO: translation aware + LOG.critical("UNHANDLED ERROR", exc_info=(typ, value, traceback)) + return # XXX: remove + try: + title = trUtf8("An unhandled error has occured") + msg = (trUtf8("Please report the error:\n\n") + + '\n'.join([line.strip() for line in + format_exception(typ, value, traceback)]) + ) + mb = criticalMB(None, title, msg) + mb.exec_() + except Exception, msg: + print msg + #sys.exit(100) + +def setupQtExceptHook(): + """ + Install Qt exception hook + """ + LOG.info("Qt exception hook installed") + sys.excepthook = qtexcepthook + +def removeQtExceptHook(): + """ + Remove Qt exception hook + """ + LOG.info("Qt exception hook removed") + sys.excepthook = sys.__excepthook__ + +def _mkMessageBox(context, icon='Information'): + """ + Create a message box + """ + assert icon in ('Question', 'Information', 'Warning', 'Critical') + if context: + mb = QtGui.QMessageBox(context) + else: + mb = QtGui.QMessageBox() + mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) + mb.setIcon(getattr(QtGui.QMessageBox, icon)) + mb.setStandardButtons(QtGui.QMessageBox.Close) + return mb + + +def criticalMB(context, title, text): + """ + Critical message box + """ + mb = _mkMessageBox(context, icon='Critical') + mb.setWindowTitle(title) + mb.setText(text) + return mb + +def warningMB(context, title, text): + """ + warning message box + """ + mb = _mkMessageBox(context, icon='Warning') + mb.setWindowTitle(title) + mb.setText(text) + return mb + +def infoMB(context, title, text): + """ + Info message box + """ + mb = _mkMessageBox(context, icon='Info') + mb.setStandardButtons(QtGui.QMessageBox.Ok) + mb.setWindowTitle(title) + mb.setText(text) + return mb Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-02-02 00:49:08 UTC (rev 115) +++ pymoul/trunk/src/moul/qt/localization.py 2007-02-02 03:32:28 UTC (rev 116) @@ -33,7 +33,7 @@ from moul.config import lookupDir from moul.file.localization import translationRegistry as tr -from moul.file.localization import parseLocDirectory +from moul.file.directory import UruGameDataDirectory from moul.log import getLogger from moul.log import signalLogDecorator @@ -48,17 +48,16 @@ Mixin for documentation tab """ def _documents_init(self): - return - locDir = lookupDir('loc') - if not os.path.isdir(locDir): + installDir = lookupDir('install') + self._gamedir = UruGameDataDirectory(installDir) + if not self._gamedir.exists('loc'): return - self.tab_documents.setEnabled(True) - - parseLocDirectory(locDir) - + self._gamedir.factory('loc') + self.tab_sub_journals.setEnabled(True) + self._documents_state = {} - + self.connect(self.cb_doc_language, SIGNAL("currentIndexChanged(int)"), self.on_cb_doc_language_currentIndexChanged) self.connect(self.cb_doc_age, SIGNAL("currentIndexChanged(int)"), Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 00:49:08 UTC (rev 115) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 03:32:28 UTC (rev 116) @@ -48,18 +48,6 @@ LOG = getLogger('moul.qt') -def criticalMessageBox(self, title, text): - """ - Critical warning! - """ - mb = QtGui.QMessageBox() - mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) - mb.setIcon(QtGui.QMessageBox.Critical) - mb.setWindowTitle(self.trUtf8(title)) - mb.setText(self.trUtf8(text)) - mb.setStandardButtons(QtGui.QMessageBox.Close) - return mb - class MainWindow(QtGui.QMainWindow, Ui_MainWindow, LocalizationMixin): def __init__(self): QtGui.QMainWindow.__init__(self) @@ -75,7 +63,8 @@ # dirty flag: unsaved changes self._dirty = False self.setDirty(False) - + self.tab_sub_journals.setEnabled(False) + # init handlers self._timezone_init() self._graphics_init() @@ -84,8 +73,7 @@ self._systray_init() self._about_init() self._documents_init() - self.tab_sub_journals.setEnabled(False) - + # run checker self._moulrunning = None self._moulrunning_thread = MoulRunningThread() @@ -498,9 +486,9 @@ """ self._ping_thread = thread = PingServerThread() - self.connect(thread, SIGNAL("started"), + self.connect(thread, SIGNAL("started()"), self.on_pingthread_started) - self.connect(thread, SIGNAL("done()"), + self.connect(thread, SIGNAL("finished()"), self.on_pingthread_done) self.connect(thread, SIGNAL("server(const QString&)"), self.on_pingthread_server) @@ -563,7 +551,6 @@ def run(self): # TODO: thread safety! - self.emit(SIGNAL("started")) # emit a list of names first for server in self.servers: self.emit(SIGNAL("server(const QString&)"), server.name) @@ -583,8 +570,6 @@ name, ping[0], ping[1]) continue self.emit(SIGNAL("ping(const QString&, float)"), name, ping) - - self.emit(SIGNAL("done()")) class MoulRunningThread(QtCore.QThread): def __init__(self, parent=None): Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-02-02 00:49:08 UTC (rev 115) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-02-02 03:32:28 UTC (rev 116) @@ -28,7 +28,9 @@ from PyQt4 import QtGui from moul.qt.mainwindow import MainWindow -from moul.qt.mainwindow import criticalMessageBox +from moul.qt.errorhandler import criticalMB +from moul.qt.errorhandler import setupQtExceptHook +from moul.qt.errorhandler import removeQtExceptHook from moul.osdependent.singleapp import SimpleSingleApp from moul.config import getPyMoulDataDir from moul.osdependent import isMoulRunning @@ -55,28 +57,24 @@ try: singleapp.acquire() except OSError: - mb = criticalMessageBox(app, - "pyMoul QT already running", - """An instance of pyMoul QT is already running!""") + mb = criticalMB(app, + app.trUtf8("pyMoul QT already running"), + app.trUtf8("""An instance of pyMoul QT is already running!""") + ) mb.exec_() sys.exit(1) - + createLogfile() - -# if isMoulRunning(): -# mb = criticalMessageBox(app, -# "URU is running", -# """URU is running! Please close Uru or Uru Launcher first.""") -# mb.exec_() -# sys.exit(2) + setupQtExceptHook() LOG.info("Invoking PyMoul QT MainWindow") mainWindow = MainWindow() mainWindow.show() err = app.exec_() LOG.info("Exiting PyMoul QT UI with status %i" % err) + removeQtExceptHook() return err - + if __name__ == '__main__': err = main(sys.argv) sys.exit(err) Added: pymoul/trunk/src/moul/qt/threadlet.py =================================================================== --- pymoul/trunk/src/moul/qt/threadlet.py (rev 0) +++ pymoul/trunk/src/moul/qt/threadlet.py 2007-02-02 03:32:28 UTC (rev 116) @@ -0,0 +1,68 @@ +#!/usr/bin/env python2.5 +# pyMoul - Python interface to Myst Online URU Live +# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> + +# This program 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 program 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +"""Threadlet - execute a function in a seperate thread +""" +__author__ = "Christian Heimes" +__version__ = "$Id: moulqt.py 110 2007-01-31 15:40:51Z tiran $" +__revision__ = "$Revision: 110 $" + +import sys + +from PyQt4 import QtCore + +LOG = getLogger('moul.tasklket') + +class Threadlet(QtCore.QThread): + """Threadlet - execute a function in a seperate thread + + @signal started(): Signal is emitted when the thread starts executing. + @signal finished(): Signal is emitted when the thread has finished. + @signal terminated(): Signal is emitted when the thread is terminated. + @signal done(result): Signal is emitted when the function has returned. + The result argument contains the return value of the function. + + >>> def pow(x, y): return x**y + >>> def printer(r): print r + >>> example =Threadlet(pow, parent=None, 2, 6) + >>> connect(example, SIGNAL('done(result)'), printer) + >>> example.start() + + started() + done(result) + finished() + + @warning: The function and all applied arguments must be reentrant or + thread safe! + """ + def __init__(self, func, parent=None, *args, **kwargs): + """ + @param func: a callable + @param parent: Qt parent + @param *args: additional arguments for the function + @param **kwargs: additional keyword arguments for the function + """ + QtCore.QThread.__init__(self, parent) + self._func = func + self._args = args + self._kwargs = kwargs + + def run(self): + result = self._func(*self._args, **self._kwargs) + self.emit(SIGNAL("done(result)"), result) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-02 17:19:05
|
Revision: 120 http://pymoul.svn.sourceforge.net/pymoul/?rev=120&view=rev Author: tiran Date: 2007-02-02 09:13:40 -0800 (Fri, 02 Feb 2007) Log Message: ----------- Disabled non functional UI elements Added fix KI image code with cool progress bar Modified Paths: -------------- pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/kiimage.py pymoul/trunk/src/moul/file/plasmalog.py pymoul/trunk/src/moul/file/wdysini.py pymoul/trunk/src/moul/metadata.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/simpleprogressbar.py pymoul/trunk/src/moul/qt/threadlet.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-02-02 17:13:40 UTC (rev 120) @@ -93,6 +93,7 @@ self._path = srcdir self._dest = destdir self._logs = [] + LOG.debug("ChatlogMover: %s -> %s" % (srcdir, destdir)) if not os.path.isdir(srcdir): LOG.warning("%s is not a directory" % srcdir) if not os.path.isdir(destdir): Modified: pymoul/trunk/src/moul/file/kiimage.py =================================================================== --- pymoul/trunk/src/moul/file/kiimage.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/file/kiimage.py 2007-02-02 17:13:40 UTC (rev 120) @@ -222,16 +222,20 @@ self._found = [] # all found files self._tocheck = [] # found files to check self._fixed = [] # fixed files + LOG.debug("KIImageFixer: %s -> %s" % (srcdir, destdir)) if not os.path.isdir(srcdir): LOG.warning("%s is not a directory" % srcdir) if not os.path.isdir(destdir): - LOG.info("Creating chatlog directory %s" % destdir) + LOG.info("Creating fixed images directory %s" % destdir) os.mkdir(destdir) def findFiles(self): - """Find filess + """Find files """ + if not os.path.isdir(self._srcdir): + return False + for root, dirs, files in os.walk(self._srcdir): for name in files: matches = [pat for pat in self._pat @@ -248,23 +252,41 @@ LOG.debug("File %s exists and is fixed." % name) else: self._tocheck.append((ki, fixed)) - def checkAndCopyFiles(self): - """Check files if they are KI images + return self._tocheck + def checkAndCopyFile(self, kiname, fixedname): + """Check and copy file + If the file is a KI image than copy the file to the new location """ + ki = KIImage(kiname) + if ki.isMoulImage(): + tmp = ki.removeMoulHeader() + fixed = open(fixedname, 'wb') + while True: + buf = tmp.read(4096) + if not buf: + break + fixed.write(buf) + LOG.info("Created fixed image %s" % fixedname) + self._fixed.append((kiname, fixedname)) + fixed.close() + tmp.close() + ki.close() + + def __len__(self): + """len() support - returns number of images to check + """ + return len(self._tocheck) + + def __iter__(self): + """Iterate over the files to check + + Calls checkAndCopyFiles() for each element. This method is used to + update a progress bar in the UI. + + Yields a NULL seperated string containing "kiname\x00fixedname" + """ for kiname, fixedname in self._tocheck: - ki = KIImage(kiname) - if ki.isMoulImage(): - tmp = ki.removeMoulHeader() - fixed = open(fixedname, 'wb') - while True: - buf = tmp.read(4096) - if not buf: - break - fixed.write(buf) - LOG.info("Created fixed image %s" % fixedname) - self._fixed.append((kiname, fixedname)) - fixed.close() - tmp.close() - ki.close() + yield fixedname # "%s"x00%s" % (kiname, fixedname) + self.checkAndCopyFile(kiname, fixedname) Modified: pymoul/trunk/src/moul/file/plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/plasmalog.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/file/plasmalog.py 2007-02-02 17:13:40 UTC (rev 120) @@ -43,6 +43,7 @@ def __init__(self, srcdir, destdir): self._srcdir = srcdir self._destdir = destdir + LOG.debug("PlasmalogZipper: %s -> %s" % (srcdir, destdir)) self._zipped_dirs = {} # dirname -> zipfile self._not_removed = [] # files with full path Modified: pymoul/trunk/src/moul/file/wdysini.py =================================================================== --- pymoul/trunk/src/moul/file/wdysini.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/file/wdysini.py 2007-02-02 17:13:40 UTC (rev 120) @@ -314,6 +314,7 @@ if not os.path.isdir(path): LOG.warning("Directory not found %s" % path) self._fpath = os.path.join(path, self._filename) + LOG.debug("ConfFile: %s - %s" % (path, self._filename)) self._filedata = {} self._newdata = {} self._order = [] Modified: pymoul/trunk/src/moul/metadata.py =================================================================== --- pymoul/trunk/src/moul/metadata.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/metadata.py 2007-02-02 17:13:40 UTC (rev 120) @@ -15,8 +15,27 @@ ''' name = '''pyMoul''' -README = '''''' +README = '''========================================= +Python library for Myst Online : Uru Live +========================================= +About +===== + +pyMoul is a set of Python libraries around MOUL (Myst Online : Uru Live). At +the moment the main focus is on the Qt4 based graphical tool. + +Donate +====== + +If you like the tool and find it usful please donate some money. You can +use the link below to send me money over PayPal. You don't need a PayPal +account. A credit card or bank account is sufficient. + +https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=christian%40cheimes%2ede&item_name=Donate%20for%20Tiran%27s%20open%20source%20activities&page_style=PayPal&no_shipping=2&cn=Your%20note%20for%20me&tax=0¤cy_code=EUR&lc=DE&bn=PP%2dDonationsBF&charset=UTF%2d8 + +''' + LICENSE = ''' GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 17:13:40 UTC (rev 120) @@ -36,16 +36,22 @@ from moul.qt.localization import LocalizationMixin from moul.osdependent import isMoulRunning from moul.config import lookupDir -from moul.file.wdysini import AudioIni -from moul.file.wdysini import GraphicsIni +from moul.file.directory import UruGameDataDirectory +from moul.file.directory import UruPersonalDataDirectory from moul.file.wdysini import videoModes from moul.log import getLogger from moul.log import signalLogDecorator from moul.server.ping import ServerList from moul.server.ping import isSocketError from moul.time.cavern import CavernTime +from moul.qt.threadlet import YieldingThreadlet +from moul.qt.simpleprogressbar import SimpleProgressbar from moul import metadata +# TBR +from moul.file.wdysini import AudioIni +from moul.file.wdysini import GraphicsIni + LOG = getLogger('moul.qt') class MainWindow(QtGui.QMainWindow, Ui_MainWindow, LocalizationMixin): @@ -63,6 +69,12 @@ # dirty flag: unsaved changes self._dirty = False self.setDirty(False) + + # set directory handlers + self.urugamedir = UruGameDataDirectory(lookupDir('install')) + self.urudatadir = UruPersonalDataDirectory(lookupDir('userdata')) + # TODO: checks + self.urudatadir.initializeFactories() # init handlers self._timezone_init() @@ -110,11 +122,11 @@ QtGui.QMessageBox.information(self, self.trUtf8("Not Implemented"), self.trUtf8("""Sorry, this feature is not implemented yet!""")) - + def closeEvent(self, event): """ Close event handler - + @qtslot closeEvent(event QCloseEvent): notify on close @param event: close event @type event: QCloseEvent instance @@ -125,7 +137,7 @@ self._systray_close() event.accept() - + def keyPressEvent(self, event): """ Key event handler @@ -136,11 +148,12 @@ Has to ignore unknown events """ - #if event.key() == Qt.Key_Escape: - # self.emit(SIGNAL("close()")) - # event.accept() + if event.key() == Qt.Key_Escape: + # FIXME: signal doesn't do anything + self.emit(SIGNAL("close()")) + event.accept() event.ignore() - + def setDirty(self, boolean): """ Sets the save state @@ -150,7 +163,7 @@ #self.main_buttonbox_save.setEnabled(boolean) self.main_buttonbox_save.setEnabled(True) self.main_buttonbox_reset.setEnabled(True) - + # ************************************************************************ # system tray def _systray_init(self): @@ -163,6 +176,49 @@ self.systemtray.setVisible(False) # ************************************************************************ + # tasks + + @pyqtSignature("") + @signalLogDecorator(LOG) + def on_pb_kiimage_repair_clicked(self): + """ + Clicked repair button + """ + kimover = self.urudatadir.kiimages + if not kimover.findFiles(): + # TODO: msg + return + + self.pb_kiimage_repair.setEnabled(False) + self._kiimage_progressbar = SimpleProgressbar(self) + self._kiimage_progressbar.setWindowTitle( + self.trUtf8("Repairing KI images")) + self._kiimage_threadlet = YieldingThreadlet(self) + + self._kiimage_progressbar.setProgressbar(0, len(kimover), 0) + self.connect(self._kiimage_threadlet, SIGNAL("yield(const QString&)"), + self._kiimage_progressbar.increase) + self.connect(self._kiimage_threadlet, SIGNAL("finished()"), + self.on_pb_kiimage_repair_done) + self._kiimage_progressbar.show() + self._kiimage_threadlet.detach(kimover) + + @signalLogDecorator(LOG) + def on_pb_kiimage_repair_done(self): + """ + Repair threadlet done + """ + self._kiimage_progressbar.close() + self.disconnect(self._kiimage_threadlet, SIGNAL("yield(result)"), + self._kiimage_progressbar.increase) + self.disconnect(self._kiimage_threadlet, SIGNAL("finished()"), + self.on_pb_kiimage_repair_done) + del self._kiimage_threadlet + del self._kiimage_progressbar + self.pb_kiimage_repair.setEnabled(True) + # TODO: msg + + # ************************************************************************ # graphics settings def _about_init(self): self.te_license.setPlainText(metadata.LICENSE) Modified: pymoul/trunk/src/moul/qt/simpleprogressbar.py =================================================================== --- pymoul/trunk/src/moul/qt/simpleprogressbar.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/qt/simpleprogressbar.py 2007-02-02 17:13:40 UTC (rev 120) @@ -58,6 +58,26 @@ self.progressbar.setMaximum(maxval) self.progressbar.setValue(value) + def increase(self, *args): + """Increase value by one + + Additional arguments are ignored. You can use the method as a + destination for a signal w/o worrying about the signature. + + @qtslot increase(): increase value by one + """ + self.progressbar.setValue(self.progressbar.value()+1) + + def decrease(self, *args): + """Decrease value by one + + Additional arguments are ignored. You can use the method as a + destination for a signal w/o worrying about the signature. + + @qtslot decrease(): decrease value by one + """ + self.progressbar.setValue(self.progressbar.value()-1) + @pyqtSignature("int") def setValue(self, value): """Set value of progress bar Modified: pymoul/trunk/src/moul/qt/threadlet.py =================================================================== --- pymoul/trunk/src/moul/qt/threadlet.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/qt/threadlet.py 2007-02-02 17:13:40 UTC (rev 120) @@ -55,7 +55,6 @@ @qtsignal started(): Signal is emitted when the thread starts executing. @qtsignal finished(): Signal is emitted when the thread has finished. @qtsignal terminated(): Signal is emitted when the thread is terminated. - @qtsignal done(result): Signal is emitted when the function has returned. @warning: The function and all applied arguments must be thread safe! """ @@ -79,16 +78,16 @@ self._args = None self._kwargs = None - def detach(self, func, *args, **kwargs): + def detach(self, obj, *args, **kwargs): """ Detach a function call - @param func: a callable + @param obj: a callable (or iterable for YieldingThreadlet) @param *args: additional arguments for the function @param **kwargs: additional keyword arguments for the function """ self.mutex.lock() - self._func = func + self._obj = obj self._args = args self._kwargs = kwargs self.mutex.unlock() @@ -97,14 +96,30 @@ def run(self): """ - Payload - runs the script and emits done(result) + Payload - runs the callable and emits done(result) The function and its args/kwargs are cleared after the function has run to avoid cyclic references. + + @qtsignal done(result): Signal is emitted when the function has returned. """ self.mutex.lock() - result = self._func(*self._args, **self._kwargs) + result = self._obj(*self._args, **self._kwargs) self.emit(SIGNAL("done(result)"), result) self.clear() self.mutex.unlock() +class YieldingThreadlet(Threadlet): + """ + Similar to Threadlet by iters over the object and yields each value + """ + def run(self): + """ + Paylad - iters over the object and yields each value + + @qtsignal yield(const QString&): yield + """ + self.mutex.lock() + for result in iter(self._obj): + self.emit(SIGNAL("yield(const QString&)"), result) + self.mutex.unlock() Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-02-02 17:13:40 UTC (rev 120) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'src/moul/qt/ui/mainwindow.ui' # -# Created: Tue Jan 30 21:05:11 2007 +# Created: Fri Feb 2 17:26:46 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -13,6 +13,7 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") + MainWindow.resize(QtCore.QSize(QtCore.QRect(0,0,472,595).size()).expandedTo(MainWindow.minimumSizeHint())) MainWindow.setMinimumSize(QtCore.QSize(472,595)) MainWindow.setMaximumSize(QtCore.QSize(472,595)) MainWindow.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) @@ -75,7 +76,33 @@ self.tab_tasks = QtGui.QWidget() self.tab_tasks.setObjectName("tab_tasks") + self.groupBox_2 = QtGui.QGroupBox(self.tab_tasks) + self.groupBox_2.setGeometry(QtCore.QRect(10,120,451,61)) + self.groupBox_2.setObjectName("groupBox_2") + + self.layoutWidget = QtGui.QWidget(self.groupBox_2) + self.layoutWidget.setGeometry(QtCore.QRect(10,20,431,30)) + self.layoutWidget.setObjectName("layoutWidget") + + self.hboxlayout2 = QtGui.QHBoxLayout(self.layoutWidget) + self.hboxlayout2.setMargin(0) + self.hboxlayout2.setSpacing(6) + self.hboxlayout2.setObjectName("hboxlayout2") + + self.pb_kiimage_repair = QtGui.QPushButton(self.layoutWidget) + self.pb_kiimage_repair.setMinimumSize(QtCore.QSize(60,0)) + self.pb_kiimage_repair.setObjectName("pb_kiimage_repair") + self.hboxlayout2.addWidget(self.pb_kiimage_repair) + + self.pb_kiimage_repair1 = QtGui.QLabel(self.layoutWidget) + self.pb_kiimage_repair1.setObjectName("pb_kiimage_repair1") + self.hboxlayout2.addWidget(self.pb_kiimage_repair1) + + spacerItem2 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) + self.hboxlayout2.addItem(spacerItem2) + self.groupBox = QtGui.QGroupBox(self.tab_tasks) + self.groupBox.setEnabled(False) self.groupBox.setGeometry(QtCore.QRect(10,0,451,121)) self.groupBox.setObjectName("groupBox") @@ -85,16 +112,16 @@ self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.NoButton) self.buttonBox.setObjectName("buttonBox") - self.widget = QtGui.QWidget(self.groupBox) - self.widget.setGeometry(QtCore.QRect(11,21,431,86)) - self.widget.setObjectName("widget") + self.layoutWidget1 = QtGui.QWidget(self.groupBox) + self.layoutWidget1.setGeometry(QtCore.QRect(11,21,431,89)) + self.layoutWidget1.setObjectName("layoutWidget1") - self.gridlayout = QtGui.QGridLayout(self.widget) + self.gridlayout = QtGui.QGridLayout(self.layoutWidget1) self.gridlayout.setMargin(0) self.gridlayout.setSpacing(6) self.gridlayout.setObjectName("gridlayout") - self.lb_log_archive = QtGui.QLabel(self.widget) + self.lb_log_archive = QtGui.QLabel(self.layoutWidget1) self.lb_log_archive.setTextFormat(QtCore.Qt.PlainText) self.lb_log_archive.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) self.lb_log_archive.setWordWrap(True) @@ -102,62 +129,41 @@ self.lb_log_archive.setObjectName("lb_log_archive") self.gridlayout.addWidget(self.lb_log_archive,0,1,1,1) - self.lb_log_remove = QtGui.QLabel(self.widget) + self.lb_log_remove = QtGui.QLabel(self.layoutWidget1) self.lb_log_remove.setObjectName("lb_log_remove") self.gridlayout.addWidget(self.lb_log_remove,1,1,1,1) - self.pb_log_remove = QtGui.QPushButton(self.widget) + self.pb_log_remove = QtGui.QPushButton(self.layoutWidget1) + self.pb_log_remove.setEnabled(False) self.pb_log_remove.setMinimumSize(QtCore.QSize(60,0)) self.pb_log_remove.setObjectName("pb_log_remove") self.gridlayout.addWidget(self.pb_log_remove,1,0,1,1) - self.pb_log_archive = QtGui.QPushButton(self.widget) + self.pb_log_archive = QtGui.QPushButton(self.layoutWidget1) + self.pb_log_archive.setEnabled(False) self.pb_log_archive.setMinimumSize(QtCore.QSize(60,0)) self.pb_log_archive.setObjectName("pb_log_archive") self.gridlayout.addWidget(self.pb_log_archive,0,0,1,1) - spacerItem2 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) - self.gridlayout.addItem(spacerItem2,0,2,1,1) + spacerItem3 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) + self.gridlayout.addItem(spacerItem3,0,2,1,1) self.vboxlayout = QtGui.QVBoxLayout() self.vboxlayout.setMargin(0) self.vboxlayout.setSpacing(6) self.vboxlayout.setObjectName("vboxlayout") - self.radio_ziplogs = QtGui.QRadioButton(self.widget) + self.radio_ziplogs = QtGui.QRadioButton(self.layoutWidget1) + self.radio_ziplogs.setEnabled(False) self.radio_ziplogs.setChecked(True) self.radio_ziplogs.setObjectName("radio_ziplogs") self.vboxlayout.addWidget(self.radio_ziplogs) - self.radio_deletelogs = QtGui.QRadioButton(self.widget) + self.radio_deletelogs = QtGui.QRadioButton(self.layoutWidget1) + self.radio_deletelogs.setEnabled(False) self.radio_deletelogs.setObjectName("radio_deletelogs") self.vboxlayout.addWidget(self.radio_deletelogs) self.gridlayout.addLayout(self.vboxlayout,0,3,1,1) - - self.groupBox_2 = QtGui.QGroupBox(self.tab_tasks) - self.groupBox_2.setGeometry(QtCore.QRect(10,120,451,61)) - self.groupBox_2.setObjectName("groupBox_2") - - self.widget1 = QtGui.QWidget(self.groupBox_2) - self.widget1.setGeometry(QtCore.QRect(10,20,431,30)) - self.widget1.setObjectName("widget1") - - self.hboxlayout2 = QtGui.QHBoxLayout(self.widget1) - self.hboxlayout2.setMargin(0) - self.hboxlayout2.setSpacing(6) - self.hboxlayout2.setObjectName("hboxlayout2") - - self.pb_kiimage_repair = QtGui.QPushButton(self.widget1) - self.pb_kiimage_repair.setMinimumSize(QtCore.QSize(60,0)) - self.pb_kiimage_repair.setObjectName("pb_kiimage_repair") - self.hboxlayout2.addWidget(self.pb_kiimage_repair) - - self.pb_kiimage_repair1 = QtGui.QLabel(self.widget1) - self.pb_kiimage_repair1.setObjectName("pb_kiimage_repair1") - self.hboxlayout2.addWidget(self.pb_kiimage_repair1) - - spacerItem3 = QtGui.QSpacerItem(40,20,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Minimum) - self.hboxlayout2.addItem(spacerItem3) self.tabwidget.addTab(self.tab_tasks,"") self.tab_settings = QtGui.QWidget() @@ -484,16 +490,16 @@ self.groupBox_aud_level.setGeometry(QtCore.QRect(10,0,451,171)) self.groupBox_aud_level.setObjectName("groupBox_aud_level") - self.layoutWidget = QtGui.QWidget(self.groupBox_aud_level) - self.layoutWidget.setGeometry(QtCore.QRect(20,20,191,112)) - self.layoutWidget.setObjectName("layoutWidget") + self.layoutWidget2 = QtGui.QWidget(self.groupBox_aud_level) + self.layoutWidget2.setGeometry(QtCore.QRect(20,20,191,112)) + self.layoutWidget2.setObjectName("layoutWidget2") - self.vboxlayout10 = QtGui.QVBoxLayout(self.layoutWidget) + self.vboxlayout10 = QtGui.QVBoxLayout(self.layoutWidget2) self.vboxlayout10.setMargin(0) self.vboxlayout10.setSpacing(6) self.vboxlayout10.setObjectName("vboxlayout10") - self.verticalLayout_57 = QtGui.QWidget(self.layoutWidget) + self.verticalLayout_57 = QtGui.QWidget(self.layoutWidget2) self.verticalLayout_57.setObjectName("verticalLayout_57") self.vboxlayout11 = QtGui.QVBoxLayout(self.verticalLayout_57) @@ -520,7 +526,7 @@ self.vboxlayout11.addWidget(self.sl_aud_fx) self.vboxlayout10.addWidget(self.verticalLayout_57) - self.verticalLayout_59 = QtGui.QWidget(self.layoutWidget) + self.verticalLayout_59 = QtGui.QWidget(self.layoutWidget2) self.verticalLayout_59.setObjectName("verticalLayout_59") self.vboxlayout12 = QtGui.QVBoxLayout(self.verticalLayout_59) @@ -547,16 +553,16 @@ self.vboxlayout12.addWidget(self.sl_aud_music) self.vboxlayout10.addWidget(self.verticalLayout_59) - self.layoutWidget1 = QtGui.QWidget(self.groupBox_aud_level) - self.layoutWidget1.setGeometry(QtCore.QRect(240,20,191,139)) - self.layoutWidget1.setObjectName("layoutWidget1") + self.layoutWidget3 = QtGui.QWidget(self.groupBox_aud_level) + self.layoutWidget3.setGeometry(QtCore.QRect(240,20,191,139)) + self.layoutWidget3.setObjectName("layoutWidget3") - self.vboxlayout13 = QtGui.QVBoxLayout(self.layoutWidget1) + self.vboxlayout13 = QtGui.QVBoxLayout(self.layoutWidget3) self.vboxlayout13.setMargin(0) self.vboxlayout13.setSpacing(6) self.vboxlayout13.setObjectName("vboxlayout13") - self.verticalLayout_58 = QtGui.QWidget(self.layoutWidget1) + self.verticalLayout_58 = QtGui.QWidget(self.layoutWidget3) self.verticalLayout_58.setObjectName("verticalLayout_58") self.vboxlayout14 = QtGui.QVBoxLayout(self.verticalLayout_58) @@ -583,7 +589,7 @@ self.vboxlayout14.addWidget(self.sl_aud_ambience) self.vboxlayout13.addWidget(self.verticalLayout_58) - self.verticalLayout_56 = QtGui.QWidget(self.layoutWidget1) + self.verticalLayout_56 = QtGui.QWidget(self.layoutWidget3) self.verticalLayout_56.setObjectName("verticalLayout_56") self.vboxlayout15 = QtGui.QVBoxLayout(self.verticalLayout_56) @@ -610,7 +616,7 @@ self.vboxlayout15.addWidget(self.sl_aud_npc) self.vboxlayout13.addWidget(self.verticalLayout_56) - self.cb_aud_mute = QtGui.QCheckBox(self.layoutWidget1) + self.cb_aud_mute = QtGui.QCheckBox(self.layoutWidget3) self.cb_aud_mute.setObjectName("cb_aud_mute") self.vboxlayout13.addWidget(self.cb_aud_mute) @@ -722,6 +728,7 @@ self.tab_pymoul.setObjectName("tab_pymoul") self.groupBox_4 = QtGui.QGroupBox(self.tab_pymoul) + self.groupBox_4.setEnabled(False) self.groupBox_4.setGeometry(QtCore.QRect(10,0,451,371)) self.groupBox_4.setObjectName("groupBox_4") self.tab_sub_settings.addTab(self.tab_pymoul,"") @@ -824,6 +831,7 @@ self.tab_sub_chatlogs.setObjectName("tab_sub_chatlogs") self.groupBox_5 = QtGui.QGroupBox(self.tab_sub_chatlogs) + self.groupBox_5.setEnabled(False) self.groupBox_5.setGeometry(QtCore.QRect(10,0,451,371)) self.groupBox_5.setObjectName("groupBox_5") @@ -914,6 +922,12 @@ self.tab_sub_about = QtGui.QWidget() self.tab_sub_about.setObjectName("tab_sub_about") + + self.label_6 = QtGui.QLabel(self.tab_sub_about) + self.label_6.setGeometry(QtCore.QRect(20,10,431,351)) + self.label_6.setTextFormat(QtCore.Qt.PlainText) + self.label_6.setAlignment(QtCore.Qt.AlignCenter) + self.label_6.setObjectName("label_6") self.tabwidget_about.addTab(self.tab_sub_about,"") self.tab_sub_license = QtGui.QWidget() @@ -947,6 +961,9 @@ def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) + self.groupBox_2.setTitle(QtGui.QApplication.translate("MainWindow", "KI Image repair", None, QtGui.QApplication.UnicodeUTF8)) + self.pb_kiimage_repair.setText(QtGui.QApplication.translate("MainWindow", "Repair", None, QtGui.QApplication.UnicodeUTF8)) + self.pb_kiimage_repair1.setText(QtGui.QApplication.translate("MainWindow", "Fix KI and avatar images", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox.setTitle(QtGui.QApplication.translate("MainWindow", "Chat and debug logs", None, QtGui.QApplication.UnicodeUTF8)) self.lb_log_archive.setText(QtGui.QApplication.translate("MainWindow", "Archive chatlogs and zip log files", None, QtGui.QApplication.UnicodeUTF8)) self.lb_log_remove.setText(QtGui.QApplication.translate("MainWindow", "Remove zipped logs", None, QtGui.QApplication.UnicodeUTF8)) @@ -954,9 +971,6 @@ self.pb_log_archive.setText(QtGui.QApplication.translate("MainWindow", "Archive", None, QtGui.QApplication.UnicodeUTF8)) self.radio_ziplogs.setText(QtGui.QApplication.translate("MainWindow", "Zip debug logs", None, QtGui.QApplication.UnicodeUTF8)) self.radio_deletelogs.setText(QtGui.QApplication.translate("MainWindow", "Delete debug logs", None, QtGui.QApplication.UnicodeUTF8)) - self.groupBox_2.setTitle(QtGui.QApplication.translate("MainWindow", "KI Image repair", None, QtGui.QApplication.UnicodeUTF8)) - self.pb_kiimage_repair.setText(QtGui.QApplication.translate("MainWindow", "Repair", None, QtGui.QApplication.UnicodeUTF8)) - self.pb_kiimage_repair1.setText(QtGui.QApplication.translate("MainWindow", "Fix KI and avatar images", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_tasks), QtGui.QApplication.translate("MainWindow", "Tasks", None, QtGui.QApplication.UnicodeUTF8)) self.groupBox_screenres.setTitle(QtGui.QApplication.translate("MainWindow", "Screen Resolution", None, QtGui.QApplication.UnicodeUTF8)) self.lb_screenres.setText(QtGui.QApplication.translate("MainWindow", "800x600 (4:3)", None, QtGui.QApplication.UnicodeUTF8)) @@ -1024,6 +1038,11 @@ self.label_3.setText(QtGui.QApplication.translate("MainWindow", "Set", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_sub_journals), QtGui.QApplication.translate("MainWindow", "Journals", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_browse), QtGui.QApplication.translate("MainWindow", "Browse", None, QtGui.QApplication.UnicodeUTF8)) + self.label_6.setText(QtGui.QApplication.translate("MainWindow", "Tool for Myst Online : Uru Live\n" + "\n" + "(c) 2007 by Christian Heimes\n" + "\n" + "http://pymoul.sourceforge.net/", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget_about.setTabText(self.tabwidget_about.indexOf(self.tab_sub_about), QtGui.QApplication.translate("MainWindow", "About pyMoul", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget_about.setTabText(self.tabwidget_about.indexOf(self.tab_sub_license), QtGui.QApplication.translate("MainWindow", "License", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_about), QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8)) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-02-02 14:38:56 UTC (rev 119) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-02-02 17:13:40 UTC (rev 120) @@ -1,6 +1,14 @@ <ui version="4.0" > <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>472</width> + <height>595</height> + </rect> + </property> <property name="minimumSize" > <size> <width>472</width> @@ -154,7 +162,74 @@ <attribute name="title" > <string>Tasks</string> </attribute> + <widget class="QGroupBox" name="groupBox_2" > + <property name="geometry" > + <rect> + <x>10</x> + <y>120</y> + <width>451</width> + <height>61</height> + </rect> + </property> + <property name="title" > + <string>KI Image repair</string> + </property> + <widget class="QWidget" name="layoutWidget" > + <property name="geometry" > + <rect> + <x>10</x> + <y>20</y> + <width>431</width> + <height>30</height> + </rect> + </property> + <layout class="QHBoxLayout" > + <property name="margin" > + <number>0</number> + </property> + <property name="spacing" > + <number>6</number> + </property> + <item> + <widget class="QPushButton" name="pb_kiimage_repair" > + <property name="minimumSize" > + <size> + <width>60</width> + <height>0</height> + </size> + </property> + <property name="text" > + <string>Repair</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="pb_kiimage_repair" > + <property name="text" > + <string>Fix KI and avatar images</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> <widget class="QGroupBox" name="groupBox" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="geometry" > <rect> <x>10</x> @@ -182,13 +257,13 @@ <set>QDialogButtonBox::NoButton</set> </property> </widget> - <widget class="QWidget" name="" > + <widget class="QWidget" name="layoutWidget" > <property name="geometry" > <rect> <x>11</x> <y>21</y> <width>431</width> - <height>86</height> + <height>89</height> </rect> </property> <layout class="QGridLayout" > @@ -226,6 +301,9 @@ </item> <item row="1" column="0" > <widget class="QPushButton" name="pb_log_remove" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="minimumSize" > <size> <width>60</width> @@ -239,6 +317,9 @@ </item> <item row="0" column="0" > <widget class="QPushButton" name="pb_log_archive" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="minimumSize" > <size> <width>60</width> @@ -273,6 +354,9 @@ </property> <item> <widget class="QRadioButton" name="radio_ziplogs" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="text" > <string>Zip debug logs</string> </property> @@ -283,6 +367,9 @@ </item> <item> <widget class="QRadioButton" name="radio_deletelogs" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="text" > <string>Delete debug logs</string> </property> @@ -293,70 +380,6 @@ </layout> </widget> </widget> - <widget class="QGroupBox" name="groupBox_2" > - <property name="geometry" > - <rect> - <x>10</x> - <y>120</y> - <width>451</width> - <height>61</height> - </rect> - </property> - <property name="title" > - <string>KI Image repair</string> - </property> - <widget class="QWidget" name="" > - <property name="geometry" > - <rect> - <x>10</x> - <y>20</y> - <width>431</width> - <height>30</height> - </rect> - </property> - <layout class="QHBoxLayout" > - <property name="margin" > - <number>0</number> - </property> - <property name="spacing" > - <number>6</number> - </property> - <item> - <widget class="QPushButton" name="pb_kiimage_repair" > - <property name="minimumSize" > - <size> - <width>60</width> - <height>0</height> - </size> - </property> - <property name="text" > - <string>Repair</string> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="pb_kiimage_repair" > - <property name="text" > - <string>Fix KI and avatar images</string> - </property> - </widget> - </item> - <item> - <spacer> - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" > - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> </widget> <widget class="QWidget" name="tab_settings" > <attribute name="title" > @@ -1509,6 +1532,9 @@ <string>pyMoul</string> </attribute> <widget class="QGroupBox" name="groupBox_4" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="geometry" > <rect> <x>10</x> @@ -1732,6 +1758,9 @@ <string>Chat logs</string> </attribute> <widget class="QGroupBox" name="groupBox_5" > + <property name="enabled" > + <bool>false</bool> + </property> <property name="geometry" > <rect> <x>10</x> @@ -1902,6 +1931,29 @@ <attribute name="title" > <string>About pyMoul</string> </attribute> + <widget class="QLabel" name="label_6" > + <property name="geometry" > + <rect> + <x>20</x> + <y>10</y> + <width>431</width> + <height>351</height> + </rect> + </property> + <property name="text" > + <string>Tool for Myst Online : Uru Live + +(c) 2007 by Christian Heimes + +http://pymoul.sourceforge.net/</string> + </property> + <property name="textFormat" > + <enum>Qt::PlainText</enum> + </property> + <property name="alignment" > + <set>Qt::AlignCenter</set> + </property> + </widget> </widget> <widget class="QWidget" name="tab_sub_license" > <attribute name="title" > This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-02 17:59:03
|
Revision: 125 http://pymoul.svn.sourceforge.net/pymoul/?rev=125&view=rev Author: tiran Date: 2007-02-02 09:59:04 -0800 (Fri, 02 Feb 2007) Log Message: ----------- Fixes for windows issues Modified Paths: -------------- pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/processinfo.py pymoul/trunk/src/moul/qt/mainwindow.py Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-02-02 17:45:42 UTC (rev 124) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-02-02 17:59:04 UTC (rev 125) @@ -33,11 +33,11 @@ __version__ = "$Id$" __revision__ = "$Revision$" +from logging import getLogger import os import sys from types import ModuleType -from moul.log import getLogger from moul.osdependent.processinfo import getPidNames from moul.osdependent.processinfo import getPids Modified: pymoul/trunk/src/moul/osdependent/processinfo.py =================================================================== --- pymoul/trunk/src/moul/osdependent/processinfo.py 2007-02-02 17:45:42 UTC (rev 124) +++ pymoul/trunk/src/moul/osdependent/processinfo.py 2007-02-02 17:59:04 UTC (rev 125) @@ -51,7 +51,11 @@ import os import sys +from logging import getLogger + +LOG = getLogger("processinfo") + _plat = sys.platform.startswith if _plat('linux'): PLAT = 'linux' @@ -195,7 +199,10 @@ sizeof(hModule), byref(count)) PSAPI.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname)) - name = u"".join([c for c in modname if c != NULL]) + try: + name = u"".join([c for c in modname if c != NULL]) + except UnicodeError, msg: + LOG.exception("Can't decode name of pid %i" % pid) modname[:] = sizeof(modname) * NULL KERNEL.CloseHandle(hProcess) mapping[pid] = name Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 17:45:42 UTC (rev 124) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 17:59:04 UTC (rev 125) @@ -626,7 +626,7 @@ ping = server.portping() if isSocketError(ping): self.emit(SIGNAL("pingerror(const QString&, int, const QString&)"), - name, ping[0], ping[1]) + name, ping[0], (len(ping) == 2) and ping[1] or "unknown") continue self.emit(SIGNAL("ping(const QString&, float)"), name, ping) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-02 21:05:51
|
Revision: 127 http://pymoul.svn.sourceforge.net/pymoul/?rev=127&view=rev Author: tiran Date: 2007-02-02 13:05:40 -0800 (Fri, 02 Feb 2007) Log Message: ----------- Progress bar for LOC loader Modified Paths: -------------- pymoul/trunk/src/moul/file/directory.py pymoul/trunk/src/moul/file/localization.py pymoul/trunk/src/moul/file/tests/test_localization.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/mainwindow.py Modified: pymoul/trunk/src/moul/file/directory.py =================================================================== --- pymoul/trunk/src/moul/file/directory.py 2007-02-02 18:11:58 UTC (rev 126) +++ pymoul/trunk/src/moul/file/directory.py 2007-02-02 21:05:40 UTC (rev 127) @@ -26,7 +26,7 @@ from moul.file.chatlog import ChatlogDirectoryView from moul.file.chatlog import ChatlogMover from moul.file.kiimage import KIImageFixer -from moul.file.localization import parseLocDirectory +from moul.file.localization import LocDirParser from moul.file.plasmalog import PlasmalogZipper from moul.file.wdysini import AudioIni from moul.file.wdysini import GraphicsIni @@ -147,7 +147,7 @@ 'video' : 'avi', } _factories = { - 'loc' : (parseLocDirectory, ('loc',)), + 'loc' : (LocDirParser, ('loc',)), } class UruPersonalDataDirectory(AbstractUruDirectory): Modified: pymoul/trunk/src/moul/file/localization.py =================================================================== --- pymoul/trunk/src/moul/file/localization.py 2007-02-02 18:11:58 UTC (rev 126) +++ pymoul/trunk/src/moul/file/localization.py 2007-02-02 21:05:40 UTC (rev 127) @@ -121,7 +121,6 @@ dset = dage.setdefault(setname, {}) dset[element] = key - class Translation(unicode): """Translation object @@ -168,6 +167,7 @@ def __init__(self, fname=''): self._fname = fname + self.translations = [] def startDocument(self): self._age = None @@ -202,70 +202,101 @@ elif name == u"element": self._element = None elif name == u"translation": - content = self._content - content = u''.join(content) - tl = Translation(age = self._age, - set = self._set, - element = self._element, - language = self._language, - content = content, - fname = self._fname) - registerTranslation(tl) + self.translationFound() self._language = None self._content = [] + def translationFound(self): + """</translation> handler + """ + content = u''.join(self._content) + tl = Translation(age = self._age, + set = self._set, + element = self._element, + language = self._language, + content = content, + fname = self._fname) + self.translations.append(tl) -def parseLoc(fd, fname=''): - """Parse a loc file +class LocDirParser(object): + """Parse translation LOC files """ - parser = make_parser() - parser.setFeature(feature_namespaces, False) - dh = MoulLocHandler(fname=fname) - parser.setContentHandler(dh) - parser.parse(fd) + contentHandler = MoulLocHandler + + def __init__(self, srcdir, registry=translationRegistry, clear=False): + """Constructor + + @param srcdir: directory containing loc files to parse + @type srcdir: string + @param registry: a translation registry instance + @type registry: TranslationRegistry + @param clear: clear the registry before parsing files? + @type clear: bool + """ + self._srcdir = srcdir + self._tr = registry + self._locs = None + if clear: + self._tr.clear() -def parseLocDirectory(path, clear=False): - """Parse all loc files in a directory - """ - files = [] - errors = [] + def exists(self): + """Test if directory exists + """ + return os.path.isdir(self._srcdir) - if clear: - translationRegistry.clear() + def parseLoc(self, fd, fname=''): + """Parse a loc file + + @param fd: file to handler + @type fd: file descriptor + @param fname: file name + @type fname: str + @return: a list of translations + @rtype: list + """ + parser = make_parser() + parser.setFeature(feature_namespaces, False) + ch = self.contentHandler(fname=fname) + parser.setContentHandler(ch) + parser.parse(fd) + return ch.translations - if not os.path.isdir(path): - raise IOError("invalid path %s" % path) + def findLocs(self): + """Find loc files in the directory + """ + if self._locs is not None: + LOG.info("findLocs() called twice") + return - globpat = os.path.join(path, '*.loc') - locs = glob.glob(globpat) + if not os.path.isdir(self._srcdir): + LOG.warning("%s is not a directory" % self._srcdir) + return False - if not locs: - raise ValueError("no localizations found in %s" % path) + globpat = os.path.join(self._srcdir, '*.loc') + locs = glob.glob(globpat) + self._locs = locs + return locs + + def parseLocDir(self): + """Parse all loc files at once + """ + if self._loc is None: + self.findLocs() + for loc in iter(self): + pass - for loc in locs: - fname = os.path.basename(loc) - if not os.access(loc, os.R_OK): - errors.append(fname) - LOG.debug("parseLogDirectory: unable to read file %s" % loc) - continue - with open(loc, 'r') as fd: - parseLoc(fd, fname=fname) - files.append(fname) - - return {'files' : files, 'errors' : errors } - -def _test(path="D:/games/MystOnline/dat", out=False): - from pprint import pprint - files, errors = parseLocDirectory(path, clear=True) - if out: - print errors - tr = translationRegistry - print tr.languages() - print tr.ages() - print tr.sets() - print tr.elements() - pprint(tr.tree()) - -if __name__ == '__main__': - _test(out=True) + def __len__(self): + """len() support + """ + return len(self._locs) + + def __iter__(self): + """Iterator support for GUI progress bar + """ + for loc in self._locs: + with open(loc, 'r') as fd: + yield loc + translations = self.parseLoc(fd, loc) + for tl in translations: + self._tr.register(tl) Modified: pymoul/trunk/src/moul/file/tests/test_localization.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_localization.py 2007-02-02 18:11:58 UTC (rev 126) +++ pymoul/trunk/src/moul/file/tests/test_localization.py 2007-02-02 21:05:40 UTC (rev 127) @@ -25,8 +25,7 @@ import unittest from doctest import DocTestSuite -from moul.file.localization import parseLoc -from moul.file.localization import parseLocDirectory +from moul.file.localization import LocDirParser from moul.file.localization import translationRegistry @@ -41,17 +40,12 @@ pass def test_parseLocDir(self): - parseLocDirectory(base) + ldp = LocDirParser(base) + ldp.parseLocDir() key = (u'english', u'testage', u'testset', u'testelement') self.failUnless(key in translationRegistry, translationRegistry.keys()) self.failUnlessEqual(len(translationRegistry), 1) - def test_parseLoc(self): - parseLoc(os.path.join(base, 'test.loc')) - key = (u'english', u'testage', u'testset', u'testelement') - self.failUnless(key in translationRegistry, translationRegistry.keys()) - self.failUnlessEqual(len(translationRegistry), 1) - def test_suite(): return unittest.TestSuite(( unittest.makeSuite(LocalizationTest), Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-02-02 18:11:58 UTC (rev 126) +++ pymoul/trunk/src/moul/log.py 2007-02-02 21:05:40 UTC (rev 127) @@ -17,6 +17,8 @@ # """pyMoul logger """ +from __future__ import absolute_import + __author__ = "Christian Heimes" __version__ = "$Id$" __revision__ = "$Revision$" @@ -27,6 +29,7 @@ import os import platform import sys +import time # absolute import! from logging import Formatter from logging import handlers @@ -39,7 +42,7 @@ format = Formatter('%(asctime)s %(name)-8s %(levelname)-7s %(message)s', #'%a, %d %b %Y %H:%M:%S' - '%m-%d %H:%M:%S') + '%H:%M:%S') root = getLogger() root.setLevel(logging.DEBUG) LOG = getLogger('pyMoul') @@ -94,6 +97,7 @@ def _systemInfo(): from moul.osdependent import __INFO__ + LOG.info("time: " + time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())) LOG.info("pyMoul version: %s" % moul_version) LOG.info("Python: %s" % repr(sys.version_info)) LOG.info("Python: %s" % sys.version.replace('\n', ' ')) @@ -113,7 +117,7 @@ shdlr = logging.StreamHandler(sys.stderr) shdlr.setFormatter(format) root.addHandler(shdlr) - #_systemInfo() + _systemInfo() else: _installMemoryHdlr() _systemInfo() Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-02-02 18:11:58 UTC (rev 126) +++ pymoul/trunk/src/moul/qt/localization.py 2007-02-02 21:05:40 UTC (rev 127) @@ -30,14 +30,12 @@ from PyQt4.QtCore import SIGNAL from PyQt4.QtCore import pyqtSignature -from moul.config import lookupDir -from moul.file.directory import UruGameDataDirectory from moul.file.localization import translationRegistry as tr from moul.log import getLogger from moul.log import signalLogDecorator from moul.qt.simpleprogressbar import SimpleProgressbar -from moul.qt.threadlet import Threadlet +from moul.qt.threadlet import YieldingThreadlet LOG = getLogger('moul.loc') @@ -76,22 +74,28 @@ if self._journals_loaded: return - # TODO: other message box + ldh = self.urugamedir.factory('loc') + if not ldh.exists(): + self.tab_sub_journals.setEnabled(False) + # TODO: message + return + + ldh.findLocs() + if not len(ldh): + # TODO: message + return + self._journal_progressbar = SimpleProgressbar(self) self._journal_progressbar.setWindowTitle(self.trUtf8("Loading journals")) - self._journal_progressbar.setProgressbar(0, 1, 0) + self._journal_progressbar.setProgressbar(0, len(ldh), 0) self._journal_progressbar.show() - installDir = lookupDir('install') - self._gamedir = UruGameDataDirectory(installDir) - if not self._gamedir.exists('loc'): - self.tab_sub_journals.setEnabled(False) - return - - self._journal_threadlet = Threadlet() + self._journal_threadlet = YieldingThreadlet(self) self.connect(self._journal_threadlet, SIGNAL('finished()'), self.on_localization_loaded) - self._journal_threadlet.detach(self._gamedir.factory, 'loc') + self.connect(self._journal_threadlet, SIGNAL("yield(const QString&)"), + self._journal_progressbar.increase) + self._journal_threadlet.detach(ldh) @signalLogDecorator(LOG) def on_localization_loaded(self): @@ -100,11 +104,12 @@ """ # remove thread self.disconnect(self._journal_threadlet, SIGNAL('finished()'), - self.on_localization_loaded) + self.on_localization_loaded) + self.disconnect(self._journal_threadlet, SIGNAL("yield(const QString&)"), + self._journal_progressbar.increase) del self._journal_threadlet # close and remove info message box - self._journal_progressbar.setValue(1) self._journal_progressbar.close() del self._journal_progressbar self._journals_loaded = True Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 18:11:58 UTC (rev 126) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 21:05:40 UTC (rev 127) @@ -20,6 +20,10 @@ """ from __future__ import with_statement +__author__ = "Christian Heimes" +__version__ = "$Id$" +__revision__ = "$Revision$" + import sys from PyQt4 import QtCore from PyQt4 import QtGui @@ -31,8 +35,6 @@ from moul.config import lookupDir from moul.file.directory import UruGameDataDirectory from moul.file.directory import UruPersonalDataDirectory -from moul.file.wdysini import AudioIni -from moul.file.wdysini import GraphicsIni from moul.file.wdysini import videoModes from moul.log import getLogger from moul.log import signalLogDecorator @@ -46,16 +48,7 @@ from moul.qt.threadlet import YieldingThreadlet from moul.qt.ui.mainwindow import Ui_MainWindow -__author__ = "Christian Heimes" -__version__ = "$Id$" -__revision__ = "$Revision$" - - - -# TBR - - LOG = getLogger('moul.qt') class MainWindow(QtGui.QMainWindow, Ui_MainWindow, LocalizationMixin): @@ -76,9 +69,9 @@ # set directory handlers self.urugamedir = UruGameDataDirectory(lookupDir('install')) - self.urudatadir = UruPersonalDataDirectory(lookupDir('userdata')) + self.urupersonaldir = UruPersonalDataDirectory(lookupDir('userdata')) # TODO: checks - self.urudatadir.initializeFactories() + self.urupersonaldir.initializeFactories() # init handlers self._timezone_init() @@ -188,7 +181,7 @@ """ Clicked repair button """ - kimover = self.urudatadir.kiimages + kimover = self.urupersonaldir.kiimages if not kimover.findFiles(): # TODO: msg return @@ -217,7 +210,7 @@ self._kiimage_progressbar.increase) self.disconnect(self._kiimage_threadlet, SIGNAL("finished()"), self.on_pb_kiimage_repair_done) - del self._kiimage_threadlet + del self._kiimage_threadlet# TODO: other message box del self._kiimage_progressbar self.pb_kiimage_repair.setEnabled(True) # TODO: msg @@ -245,8 +238,7 @@ """ @qtslot graphicsini_loaded(): notify when a graphics.ini is loaded """ - inipath = lookupDir('ini') - self._graphics_ini = gini = GraphicsIni(inipath) + gini = self.urupersonaldir.graphicsini try: gini.read() except Exception, msg: @@ -262,7 +254,7 @@ """ SIGNAL graphicsini_reset() """ - self._graphics_ini.reset() + self.urupersonaldir.graphicsini.reset() self._graphicsini_setstate() @signalLogDecorator(LOG) @@ -271,14 +263,14 @@ SIGNAL graphicsini_save() """ #self._notimplemented() - self._graphics_ini.write() + self.urupersonaldir.graphicsini.write() self.setDirty(False) def _graphicsini_setstate(self): """ Set sliders according to graphics ini settings """ - gini = self._graphics_ini + gini = self.urupersonaldir.graphicsini length = len(videoModes) - 1 self.sl_gra_screenres.setMaximum(length) @@ -301,7 +293,7 @@ # XXX: fixme txt = videoModes.getVidModeHuman(idx) self.lb_screenres.setText(QtCore.QString(txt)) - self._graphics_ini.screenres = idx + self.urupersonaldir.graphicsini.screenres = idx @signalLogDecorator(LOG) @pyqtSignature("int") @@ -318,7 +310,7 @@ """ SIGNAL: valueChanged (int) """ - self._graphics_ini.quality = idx + self.urupersonaldir.graphicsini.quality = idx @signalLogDecorator(LOG) @pyqtSignature("int") @@ -326,7 +318,7 @@ """ SIGNAL: valueChanged (int) """ - self._graphics_ini.texture = idx + self.urupersonaldir.graphicsini.texture = idx @signalLogDecorator(LOG) @pyqtSignature("int") @@ -334,7 +326,7 @@ """ SIGNAL: valueChanged (int) """ - self._graphics_ini.antialias = idx + self.urupersonaldir.graphicsini.antialias = idx @signalLogDecorator(LOG) @pyqtSignature("int") @@ -342,7 +334,7 @@ """ SIGNAL: valueChanged (int) """ - self._graphics_ini.anisotropic = idx + self.urupersonaldir.graphicsini.anisotropic = idx @signalLogDecorator(LOG) @pyqtSignature("int") @@ -350,7 +342,7 @@ """ SIGNAL: valueChanged (int) """ - self._graphics_ini.shadow = idx + self.urupersonaldir.graphicsini.shadow = idx @signalLogDecorator(LOG) @pyqtSignature("int") @@ -358,7 +350,7 @@ """ SIGNAL: stateChanged(int) """ - self._graphics_ini.windowed = state + self.urupersonaldir.graphicsini.windowed = state @signalLogDecorator(LOG) @pyqtSignature("int") @@ -366,7 +358,7 @@ """ SIGNAL: stateChanged(int) """ - self._graphics_ini.vsync = state + self.urupersonaldir.graphicsini.vsync = state @signalLogDecorator(LOG) @pyqtSignature("int") @@ -374,7 +366,7 @@ """ SIGNAL: stateChanged(int) """ - self._graphics_ini.shadow_enabled = state + self.urupersonaldir.graphicsini.shadow_enabled = state # ************************************************************************ # audio settings @@ -395,8 +387,7 @@ """ SIGNAL: audioini_loaded() """ - inipath = lookupDir('ini') - self._audio_ini = aini = AudioIni(inipath) + aini = self.urupersonaldir.audioini try: aini.read() except Exception, msg: @@ -412,7 +403,7 @@ """ SIGNAL audioini_reset() """ - self._audio_ini.reset() + self.urupersonaldir.audioini.reset() self._audioini_setstate() @signalLogDecorator(LOG) @@ -421,14 +412,14 @@ SIGNAL audioini_save() """ #self._notimplemented() - self._audio_ini.write() + self.urupersonaldir.audioini.write() self.setDirty(False) # urks def _audioini_setstate(self): """ Set sliders according to audio ini settings """ - aini = self._audio_ini + aini = self.urupersonaldir.audioini self.sl_aud_device.setMaximum(aini.numberOfDevices()-1) self.sl_aud_npc.setValue(aini.npc) @@ -444,55 +435,55 @@ @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_device_valueChanged(self, idx): - self._audio_ini.device = idx - txt = self._audio_ini.getDeviceName(idx) + self.urupersonaldir.audioini.device = idx + txt = self.urupersonaldir.audioini.getDeviceName(idx) self.lb_aud_device.setText(QtCore.QString(txt[1:-1])) @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_device_sliderMoved(self, idx): - txt = self._audio_ini.getDeviceName(idx) + txt = self.urupersonaldir.audioini.getDeviceName(idx) self.lb_aud_device.setText(QtCore.QString(txt[1:-1])) @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_npc_valueChanged(self, idx): - self._audio_ini.npc = idx + self.urupersonaldir.audioini.npc = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_music_valueChanged(self, idx): - self._audio_ini.music = idx + self.urupersonaldir.audioini.music = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_fx_valueChanged(self, idx): - self._audio_ini.fx = idx + self.urupersonaldir.audioini.fx = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_ambience_valueChanged(self, idx): - self._audio_ini.ambience = idx + self.urupersonaldir.audioini.ambience = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_priority_valueChanged(self, idx): - self._audio_ini.priority = idx + self.urupersonaldir.audioini.priority = idx @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_eax_stateChanged (self, state): - self._audio_ini.eax = state + self.urupersonaldir.audioini.eax = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_mute_stateChanged (self, state): - self._audio_ini.mute = state + self.urupersonaldir.audioini.mute = state @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_voicechat_stateChanged (self, state): - self._audio_ini.voicechat = state + self.urupersonaldir.audioini.voicechat = state # ************************************************************************ # time zones This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-03 02:12:43
|
Revision: 128 http://pymoul.svn.sourceforge.net/pymoul/?rev=128&view=rev Author: tiran Date: 2007-02-02 18:12:36 -0800 (Fri, 02 Feb 2007) Log Message: ----------- More fixes for the journal sub tab. A button was added to manually load the journals. Added progressbar's close event and window modal handling Modified Paths: -------------- pymoul/trunk/src/moul/file/localization.py pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/simpleprogressbar.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui pymoul/trunk/src/moul/qt/ui/simpleprogressbar.py pymoul/trunk/src/moul/qt/ui/simpleprogressbar.ui Modified: pymoul/trunk/src/moul/file/localization.py =================================================================== --- pymoul/trunk/src/moul/file/localization.py 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/file/localization.py 2007-02-03 02:12:36 UTC (rev 128) @@ -40,10 +40,10 @@ IGNORE_ELEMENTS = [] class TranslationRegistry(dict): - """Registry for Translation objects""" - + """Registry for Translation objects + """ __slot__ = ('_bylanguage', '_byage', '_byset', '_byelement', '_tree') - + def __new__(cls, *args, **kwargs): self = dict.__new__(cls, *args, **kwargs) self._bylanguage = {} @@ -54,6 +54,14 @@ return self def register(self, translation): + """Register a translation instance + + Translations are stored by their key. During the registration the + translations are also inserted in multiple lookup tables and a tree. + + @param translation: a translation object + @type translation: Translation instance + """ key = translation.key() if key in self: msg = ("File %s, %s already registered" % @@ -75,6 +83,8 @@ self[key] = translation def __setitem__(self, key, translation): + """obj[] hook + """ assert key == translation.key() dict.__setitem__(self, key, translation) @@ -83,25 +93,50 @@ id(self), len(self)) def clear(self): + """Clear the translation registry. + + Removes every translation from the registry and its lookup tables. + """ dict.clear(self) self._bylanguage.clear() self._byage.clear() self._byset.clear() self._byelement.clear() + + def languages(self): + """Get sorted list of all registered languages - def languages(self): + @rtype: list + """ return sorted(self._bylanguage.keys()) def ages(self): + """Get sorted list of all registered ages + + @rtype: list + """ return sorted(self._byage.keys()) def sets(self): + """Get sorted list of all registered sets + + @rtype: list + """ return sorted(self._byset.keys()) def elements(self): + """Get sorted list of all registered elements + + @rtype: list + """ return sorted(self._byelement.keys()) def tree(self): + """Get a tree + + @return: tree with languages -> age -> set -> element -> key + @rtype: dict + """ return self._tree translationRegistry = TranslationRegistry() Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/qt/localization.py 2007-02-03 02:12:36 UTC (rev 128) @@ -53,11 +53,15 @@ @qtsignal loadLocalization(): load loc data """ self._journals_loaded = False + self._documents_clear('language') self.connect(self, SIGNAL('loadLocalization()'), self.on_localization_doload) - self.cb_doc_language.addItems(insertDummyQ([])) - self.cb_doc_language_eventFilter = LocalizationLoadEventFilter(self) - self.cb_doc_language.installEventFilter(self.cb_doc_language_eventFilter) + self.connect(self.cb_doc_language, SIGNAL("currentIndexChanged(int)"), + self.on_cb_doc_language_currentIndexChanged) + self.connect(self.cb_doc_age, SIGNAL("currentIndexChanged(int)"), + self.on_cb_doc_age_currentIndexChanged) + self.connect(self.cb_doc_set, SIGNAL("currentIndexChanged(int)"), + self.on_cb_doc_set_currentIndexChanged) @signalLogDecorator(LOG) def on_localization_doload(self): @@ -65,29 +69,25 @@ @qtslot loadLocalization(): Load localization @qtsignal finished(): self._journal_threadlet """ - if self.cb_doc_language_eventFilter: - self.cb_doc_language.removeEventFilter( - self.cb_doc_language_eventFilter - ) - self.cb_doc_language_eventFilter = None - if self._journals_loaded: return - ldh = self.urugamedir.factory('loc') - if not ldh.exists(): + loc = self.urugamedir.loc + if not loc.exists(): self.tab_sub_journals.setEnabled(False) - # TODO: message + self.lb_doc_status.setText( + self.trUtf8("Unable to load journals.")) return - ldh.findLocs() - if not len(ldh): - # TODO: message + loc.findLocs() + if not len(loc): + self.lb_doc_status.setText( + self.trUtf8("No journals found.")) return self._journal_progressbar = SimpleProgressbar(self) self._journal_progressbar.setWindowTitle(self.trUtf8("Loading journals")) - self._journal_progressbar.setProgressbar(0, len(ldh), 0) + self._journal_progressbar.setProgressbar(0, len(loc), 0) self._journal_progressbar.show() self._journal_threadlet = YieldingThreadlet(self) @@ -95,7 +95,7 @@ self.on_localization_loaded) self.connect(self._journal_threadlet, SIGNAL("yield(const QString&)"), self._journal_progressbar.increase) - self._journal_threadlet.detach(ldh) + self._journal_threadlet.detach(loc) @signalLogDecorator(LOG) def on_localization_loaded(self): @@ -112,24 +112,27 @@ # close and remove info message box self._journal_progressbar.close() del self._journal_progressbar + self._journals_loaded = True + self.lb_doc_status.setText( + self.trUtf8("Journals loaded.")) self._documents_state = {} - - self.connect(self.cb_doc_language, SIGNAL("currentIndexChanged(int)"), - self.on_cb_doc_language_currentIndexChanged) - self.connect(self.cb_doc_age, SIGNAL("currentIndexChanged(int)"), - self.on_cb_doc_age_currentIndexChanged) - self.connect(self.cb_doc_set, SIGNAL("currentIndexChanged(int)"), - self.on_cb_doc_set_currentIndexChanged) - #self.connect(self.cb_doc_element, SIGNAL("currentIndexChanged(int)"), - # self.on_cb_doc_element_currentIndexChanged) languages = sorted(tr.languages()) self._documents_state['languages'] = languages self.cb_doc_language.clear() self.cb_doc_language.addItems(insertDummyQ(languages)) self.cb_doc_language.setCurrentIndex(0) + self.cb_doc_language.setEnabled(True) + @pyqtSignature("") + @signalLogDecorator(LOG) + def on_pb_doc_loadjournals_clicked(self): + """ + """ + self.pb_doc_loadjournals.setEnabled(False) + self.emit(SIGNAL("loadLocalization()")) + def _documents_clear(self, name): names = ['language', 'age', 'set', 'element', 'doc'] for name in names[names.index(name):]: @@ -194,15 +197,15 @@ self.te_doc_view.setPlainText(qstr) self.te_doc_view.setEnabled(True) -class LocalizationLoadEventFilter(QtCore.QObject): - """Event filter to load localization - """ - def eventFilter(self, target, event): - """ - Event filter - """ - if event.type() in (QtCore.QEvent.MouseButtonPress, - QtCore.QEvent.FocusIn): - self.parent().emit(SIGNAL('loadLocalization()')) +#class LocalizationLoadEventFilter(QtCore.QObject): + #"""Event filter to load localization + #""" + #def eventFilter(self, target, event): + #""" + #Event filter + #""" + #if event.type() in (QtCore.QEvent.MouseButtonPress, + #QtCore.QEvent.FocusIn): + #self.parent().emit(SIGNAL('loadLocalization()')) - return QtCore.QObject.eventFilter(self, target, event) + #return QtCore.QObject.eventFilter(self, target, event) Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-03 02:12:36 UTC (rev 128) @@ -69,8 +69,8 @@ # set directory handlers self.urugamedir = UruGameDataDirectory(lookupDir('install')) + self.urugamedir.initializeFactories() self.urupersonaldir = UruPersonalDataDirectory(lookupDir('userdata')) - # TODO: checks self.urupersonaldir.initializeFactories() # init handlers Modified: pymoul/trunk/src/moul/qt/simpleprogressbar.py =================================================================== --- pymoul/trunk/src/moul/qt/simpleprogressbar.py 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/qt/simpleprogressbar.py 2007-02-03 02:12:36 UTC (rev 128) @@ -31,8 +31,11 @@ class SimpleProgressbar(QtGui.QDialog, Ui_SimpleProgressbar): - """A simple progress bar dialog + """A simple progress bar dialog. + A SimpleProgressbar is QT::ApplicationModal and can't be closed unless + canClose is set to True or close() is called manually. + >>> bar = SimpleProgressbar() >>> bar.setWindowTitle(bar.trUtf8('a bar')) >>> bar.setProgressbar(0, 100, 20) @@ -42,7 +45,26 @@ def __init__(self, parent=None): QtGui.QDialog.__init__(self, parent) self.setupUi(self) + self.canClose = False + + def closeEvent(self, event): + """ + Event handler for QCloseEvent + + @type event: QCloseEvent + """ + if self.canClose: + event.accept() + else: + event.ignore() + def close(self): + """ + Overwrite close() to set canClose to True + """ + self.canClose = True + return QtGui.QDialog.close(self) + def setProgressbar(self, minval, maxval, value=None): """Set progress bar min, max and initial value Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-02-03 02:12:36 UTC (rev 128) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file './src/moul/qt/ui/mainwindow.ui' # -# Created: Fri Feb 2 18:43:30 2007 +# Created: Sat Feb 3 00:25:54 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -858,13 +858,8 @@ self.gb_documents.setGeometry(QtCore.QRect(10,0,451,371)) self.gb_documents.setObjectName("gb_documents") - self.te_doc_view = QtGui.QTextEdit(self.gb_documents) - self.te_doc_view.setGeometry(QtCore.QRect(10,130,431,231)) - self.te_doc_view.setReadOnly(True) - self.te_doc_view.setObjectName("te_doc_view") - self.gridLayout_2 = QtGui.QWidget(self.gb_documents) - self.gridLayout_2.setGeometry(QtCore.QRect(10,20,291,108)) + self.gridLayout_2.setGeometry(QtCore.QRect(10,20,431,113)) self.gridLayout_2.setObjectName("gridLayout_2") self.gridlayout2 = QtGui.QGridLayout(self.gridLayout_2) @@ -872,23 +867,10 @@ self.gridlayout2.setSpacing(6) self.gridlayout2.setObjectName("gridlayout2") - self.label_2 = QtGui.QLabel(self.gridLayout_2) - self.label_2.setObjectName("label_2") - self.gridlayout2.addWidget(self.label_2,1,0,1,1) + self.cb_doc_element = QtGui.QComboBox(self.gridLayout_2) + self.cb_doc_element.setObjectName("cb_doc_element") + self.gridlayout2.addWidget(self.cb_doc_element,3,1,1,1) - self.label_7 = QtGui.QLabel(self.gridLayout_2) - self.label_7.setObjectName("label_7") - self.gridlayout2.addWidget(self.label_7,3,0,1,1) - - self.label = QtGui.QLabel(self.gridLayout_2) - self.label.setMinimumSize(QtCore.QSize(80,0)) - self.label.setObjectName("label") - self.gridlayout2.addWidget(self.label,0,0,1,1) - - self.label_3 = QtGui.QLabel(self.gridLayout_2) - self.label_3.setObjectName("label_3") - self.gridlayout2.addWidget(self.label_3,2,0,1,1) - self.cb_doc_language = QtGui.QComboBox(self.gridLayout_2) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Policy(7),QtGui.QSizePolicy.Policy(0)) @@ -899,17 +881,46 @@ self.cb_doc_language.setObjectName("cb_doc_language") self.gridlayout2.addWidget(self.cb_doc_language,0,1,1,1) - self.cb_doc_age = QtGui.QComboBox(self.gridLayout_2) - self.cb_doc_age.setObjectName("cb_doc_age") - self.gridlayout2.addWidget(self.cb_doc_age,1,1,1,1) + self.label = QtGui.QLabel(self.gridLayout_2) + self.label.setMinimumSize(QtCore.QSize(80,0)) + self.label.setObjectName("label") + self.gridlayout2.addWidget(self.label,0,0,1,1) self.cb_doc_set = QtGui.QComboBox(self.gridLayout_2) self.cb_doc_set.setObjectName("cb_doc_set") self.gridlayout2.addWidget(self.cb_doc_set,2,1,1,1) - self.cb_doc_element = QtGui.QComboBox(self.gridLayout_2) - self.cb_doc_element.setObjectName("cb_doc_element") - self.gridlayout2.addWidget(self.cb_doc_element,3,1,1,1) + self.label_7 = QtGui.QLabel(self.gridLayout_2) + self.label_7.setObjectName("label_7") + self.gridlayout2.addWidget(self.label_7,3,0,1,1) + + self.label_2 = QtGui.QLabel(self.gridLayout_2) + self.label_2.setObjectName("label_2") + self.gridlayout2.addWidget(self.label_2,1,0,1,1) + + self.label_3 = QtGui.QLabel(self.gridLayout_2) + self.label_3.setObjectName("label_3") + self.gridlayout2.addWidget(self.label_3,2,0,1,1) + + self.cb_doc_age = QtGui.QComboBox(self.gridLayout_2) + self.cb_doc_age.setObjectName("cb_doc_age") + self.gridlayout2.addWidget(self.cb_doc_age,1,1,1,1) + + self.pb_doc_loadjournals = QtGui.QPushButton(self.gridLayout_2) + self.pb_doc_loadjournals.setMinimumSize(QtCore.QSize(0,22)) + self.pb_doc_loadjournals.setMaximumSize(QtCore.QSize(16777215,22)) + self.pb_doc_loadjournals.setObjectName("pb_doc_loadjournals") + self.gridlayout2.addWidget(self.pb_doc_loadjournals,0,2,1,1) + + self.lb_doc_status = QtGui.QLabel(self.gridLayout_2) + self.lb_doc_status.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignTop) + self.lb_doc_status.setObjectName("lb_doc_status") + self.gridlayout2.addWidget(self.lb_doc_status,1,2,2,1) + + self.te_doc_view = QtGui.QTextEdit(self.gb_documents) + self.te_doc_view.setGeometry(QtCore.QRect(10,140,431,221)) + self.te_doc_view.setReadOnly(True) + self.te_doc_view.setObjectName("te_doc_view") self.tabWidget.addTab(self.tab_sub_journals,"") self.tabwidget.addTab(self.tab_browse,"") @@ -952,9 +963,9 @@ MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) - self.tabwidget.setCurrentIndex(0) + self.tabwidget.setCurrentIndex(4) self.tab_sub_settings.setCurrentIndex(0) - self.tabWidget.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(1) self.tabwidget_about.setCurrentIndex(0) QtCore.QObject.connect(self.main_buttonbox,QtCore.SIGNAL("rejected()"),MainWindow.close) QtCore.QMetaObject.connectSlotsByName(MainWindow) @@ -1032,10 +1043,12 @@ self.groupBox_5.setTitle(QtGui.QApplication.translate("MainWindow", "Read chatlogs", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_sub_chatlogs), QtGui.QApplication.translate("MainWindow", "Chat logs", None, QtGui.QApplication.UnicodeUTF8)) self.gb_documents.setTitle(QtGui.QApplication.translate("MainWindow", "Browse journals and notes", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("MainWindow", "Language", None, QtGui.QApplication.UnicodeUTF8)) + self.label_7.setText(QtGui.QApplication.translate("MainWindow", "Element", None, QtGui.QApplication.UnicodeUTF8)) self.label_2.setText(QtGui.QApplication.translate("MainWindow", "Age", None, QtGui.QApplication.UnicodeUTF8)) - self.label_7.setText(QtGui.QApplication.translate("MainWindow", "Element", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("MainWindow", "Language", None, QtGui.QApplication.UnicodeUTF8)) self.label_3.setText(QtGui.QApplication.translate("MainWindow", "Set", None, QtGui.QApplication.UnicodeUTF8)) + self.pb_doc_loadjournals.setText(QtGui.QApplication.translate("MainWindow", "Load journals", None, QtGui.QApplication.UnicodeUTF8)) + self.lb_doc_status.setText(QtGui.QApplication.translate("MainWindow", "TextLabel", None, QtGui.QApplication.UnicodeUTF8)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_sub_journals), QtGui.QApplication.translate("MainWindow", "Journals", None, QtGui.QApplication.UnicodeUTF8)) self.tabwidget.setTabText(self.tabwidget.indexOf(self.tab_browse), QtGui.QApplication.translate("MainWindow", "Browse", None, QtGui.QApplication.UnicodeUTF8)) self.label_6.setText(QtGui.QApplication.translate("MainWindow", "Tool for Myst Online : Uru Live\n" Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-02-03 02:12:36 UTC (rev 128) @@ -156,7 +156,7 @@ <enum>QTabWidget::North</enum> </property> <property name="currentIndex" > - <number>0</number> + <number>4</number> </property> <widget class="QWidget" name="tab_tasks" > <attribute name="title" > @@ -1751,7 +1751,7 @@ </rect> </property> <property name="currentIndex" > - <number>0</number> + <number>1</number> </property> <widget class="QWidget" name="tab_sub_chatlogs" > <attribute name="title" > @@ -1821,26 +1821,13 @@ <property name="title" > <string>Browse journals and notes</string> </property> - <widget class="QTextEdit" name="te_doc_view" > - <property name="geometry" > - <rect> - <x>10</x> - <y>130</y> - <width>431</width> - <height>231</height> - </rect> - </property> - <property name="readOnly" > - <bool>true</bool> - </property> - </widget> <widget class="QWidget" name="gridLayout_2" > <property name="geometry" > <rect> <x>10</x> <y>20</y> - <width>291</width> - <height>108</height> + <width>431</width> + <height>113</height> </rect> </property> <layout class="QGridLayout" > @@ -1850,17 +1837,18 @@ <property name="spacing" > <number>6</number> </property> - <item row="1" column="0" > - <widget class="QLabel" name="label_2" > - <property name="text" > - <string>Age</string> - </property> - </widget> + <item row="3" column="1" > + <widget class="QComboBox" name="cb_doc_element" /> </item> - <item row="3" column="0" > - <widget class="QLabel" name="label_7" > - <property name="text" > - <string>Element</string> + <item row="0" column="1" > + <widget class="QComboBox" name="cb_doc_language" > + <property name="sizePolicy" > + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> </widget> </item> @@ -1877,6 +1865,23 @@ </property> </widget> </item> + <item row="2" column="1" > + <widget class="QComboBox" name="cb_doc_set" /> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="label_7" > + <property name="text" > + <string>Element</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Age</string> + </property> + </widget> + </item> <item row="2" column="0" > <widget class="QLabel" name="label_3" > <property name="text" > @@ -1884,29 +1889,53 @@ </property> </widget> </item> - <item row="0" column="1" > - <widget class="QComboBox" name="cb_doc_language" > - <property name="sizePolicy" > - <sizepolicy> - <hsizetype>7</hsizetype> - <vsizetype>0</vsizetype> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> <item row="1" column="1" > <widget class="QComboBox" name="cb_doc_age" /> </item> - <item row="2" column="1" > - <widget class="QComboBox" name="cb_doc_set" /> + <item row="0" column="2" > + <widget class="QPushButton" name="pb_doc_loadjournals" > + <property name="minimumSize" > + <size> + <width>0</width> + <height>22</height> + </size> + </property> + <property name="maximumSize" > + <size> + <width>16777215</width> + <height>22</height> + </size> + </property> + <property name="text" > + <string>Load journals</string> + </property> + </widget> </item> - <item row="3" column="1" > - <widget class="QComboBox" name="cb_doc_element" /> + <item rowspan="2" row="1" column="2" > + <widget class="QLabel" name="lb_doc_status" > + <property name="text" > + <string>TextLabel</string> + </property> + <property name="alignment" > + <set>Qt::AlignHCenter|Qt::AlignTop</set> + </property> + </widget> </item> </layout> </widget> + <widget class="QTextEdit" name="te_doc_view" > + <property name="geometry" > + <rect> + <x>10</x> + <y>140</y> + <width>431</width> + <height>221</height> + </rect> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> </widget> </widget> </widget> Modified: pymoul/trunk/src/moul/qt/ui/simpleprogressbar.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/simpleprogressbar.py 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/qt/ui/simpleprogressbar.py 2007-02-03 02:12:36 UTC (rev 128) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file './src/moul/qt/ui/simpleprogressbar.ui' # -# Created: Fri Feb 2 18:43:31 2007 +# Created: Sat Feb 3 03:07:49 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -13,6 +13,7 @@ class Ui_SimpleProgressbar(object): def setupUi(self, SimpleProgressbar): SimpleProgressbar.setObjectName("SimpleProgressbar") + SimpleProgressbar.setWindowModality(QtCore.Qt.ApplicationModal) SimpleProgressbar.resize(QtCore.QSize(QtCore.QRect(0,0,203,38).size()).expandedTo(SimpleProgressbar.minimumSizeHint())) SimpleProgressbar.setMinimumSize(QtCore.QSize(203,38)) SimpleProgressbar.setMaximumSize(QtCore.QSize(203,38)) Modified: pymoul/trunk/src/moul/qt/ui/simpleprogressbar.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/simpleprogressbar.ui 2007-02-02 21:05:40 UTC (rev 127) +++ pymoul/trunk/src/moul/qt/ui/simpleprogressbar.ui 2007-02-03 02:12:36 UTC (rev 128) @@ -1,6 +1,9 @@ <ui version="4.0" > <class>SimpleProgressbar</class> <widget class="QDialog" name="SimpleProgressbar" > + <property name="windowModality" > + <enum>Qt::ApplicationModal</enum> + </property> <property name="geometry" > <rect> <x>0</x> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-03 18:42:22
|
Revision: 129 http://pymoul.svn.sourceforge.net/pymoul/?rev=129&view=rev Author: tiran Date: 2007-02-03 10:41:23 -0800 (Sat, 03 Feb 2007) Log Message: ----------- Added QNamespaceContainer() Fixed unit tests Modified Paths: -------------- pymoul/trunk/src/moul/file/kiimage.py pymoul/trunk/src/moul/file/localization.py pymoul/trunk/src/moul/file/tests/test_directory.py pymoul/trunk/src/moul/file/tests/test_plasmalog.py pymoul/trunk/src/moul/qt/errorhandler.py pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/mainwindow.py Added Paths: ----------- pymoul/trunk/src/moul/qt/utils.py Modified: pymoul/trunk/src/moul/file/kiimage.py =================================================================== --- pymoul/trunk/src/moul/file/kiimage.py 2007-02-03 02:12:36 UTC (rev 128) +++ pymoul/trunk/src/moul/file/kiimage.py 2007-02-03 18:41:23 UTC (rev 129) @@ -274,7 +274,7 @@ fixed.close() tmp.close() ki.close() - + def __len__(self): """len() support - returns number of images to check """ Modified: pymoul/trunk/src/moul/file/localization.py =================================================================== --- pymoul/trunk/src/moul/file/localization.py 2007-02-03 02:12:36 UTC (rev 128) +++ pymoul/trunk/src/moul/file/localization.py 2007-02-03 18:41:23 UTC (rev 129) @@ -316,7 +316,7 @@ def parseLocDir(self): """Parse all loc files at once """ - if self._loc is None: + if self._locs is None: self.findLocs() for loc in iter(self): pass @@ -324,7 +324,10 @@ def __len__(self): """len() support """ - return len(self._locs) + if self._locs is None: + return 0 + else: + return len(self._locs) def __iter__(self): """Iterator support for GUI progress bar Modified: pymoul/trunk/src/moul/file/tests/test_directory.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_directory.py 2007-02-03 02:12:36 UTC (rev 128) +++ pymoul/trunk/src/moul/file/tests/test_directory.py 2007-02-03 18:41:23 UTC (rev 129) @@ -53,7 +53,7 @@ def test_dumbfactorycreate(self): for name in self.urudir._factories: f = self.urudir.factory(name) - self.failUnless(f, str((type(f), repr(f), name))) + self.failUnless(f is not None, str((type(f), repr(f), name))) class UruPersonalDirTest(AbstractTest): klass = UruPersonalDataDirectory Modified: pymoul/trunk/src/moul/file/tests/test_plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-02-03 02:12:36 UTC (rev 128) +++ pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-02-03 18:41:23 UTC (rev 129) @@ -104,7 +104,9 @@ self.failUnless(os.path.isdir(self._kidest), self._kidest) kif.findFiles() - kif.checkAndCopyFiles() + # check and copy files + for f in iter(kif): + pass content = os.listdir(self._kidest) self.failUnlessEqual(len(content), 1, content) self.failUnlessEqual(content, ["KIimage001.jpg"]) Modified: pymoul/trunk/src/moul/qt/errorhandler.py =================================================================== --- pymoul/trunk/src/moul/qt/errorhandler.py 2007-02-03 02:12:36 UTC (rev 128) +++ pymoul/trunk/src/moul/qt/errorhandler.py 2007-02-03 18:41:23 UTC (rev 129) @@ -20,7 +20,7 @@ """Error handling for moul qt The module installs a custom exception hook that shows unhandled traceback in -the ui. It also contains several functions to create message boxes. +the ui. """ __author__ = "Christian Heimes" __version__ = "$Id" @@ -28,14 +28,14 @@ import os import sys -from PyQt4 import QtCore -from PyQt4 import QtGui -from PyQt4.QtCore import Qt +from PyQt4.QtGui import QApplication from traceback import format_exception from moul.log import getLogger +from moul.qt.utils import criticalMB + LOG = getLogger('moul.qt.error') @@ -48,9 +48,9 @@ if not getattr(sys, 'frozen', False): return try: - title= QtGui.QApplication.translate("excepthook", + title= QApplication.translate("excepthook", "An unhandled error has occured", - None, QtGui.QApplication.UnicodeUTF8) + None, QQApplication.UnicodeUTF8) msg = ("Please report the error:\n\n" + '\n'.join([line.strip() for line in format_exception(typ, value, traceback)]) @@ -74,46 +74,3 @@ """ LOG.info("Qt exception hook removed") sys.excepthook = sys.__excepthook__ - -def _mkMessageBox(context, icon='Information'): - """ - Create a message box - """ - assert icon in ('Question', 'Information', 'Warning', 'Critical') - if context: - mb = QtGui.QMessageBox(context) - else: - mb = QtGui.QMessageBox() - mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) - mb.setIcon(getattr(QtGui.QMessageBox, icon)) - mb.setStandardButtons(QtGui.QMessageBox.Close) - return mb - - -def criticalMB(context, title, text): - """ - Critical message box - """ - mb = _mkMessageBox(context, icon='Critical') - mb.setWindowTitle(title) - mb.setText(text) - return mb - -def warningMB(context, title, text): - """ - warning message box - """ - mb = _mkMessageBox(context, icon='Warning') - mb.setWindowTitle(title) - mb.setText(text) - return mb - -def infoMB(context, title, text): - """ - Info message box - """ - mb = _mkMessageBox(context, icon='Information') - mb.setStandardButtons(QtGui.QMessageBox.Ok) - mb.setWindowTitle(title) - mb.setText(text) - return mb Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-02-03 02:12:36 UTC (rev 128) +++ pymoul/trunk/src/moul/qt/localization.py 2007-02-03 18:41:23 UTC (rev 129) @@ -36,6 +36,7 @@ from moul.qt.simpleprogressbar import SimpleProgressbar from moul.qt.threadlet import YieldingThreadlet +from moul.qt.utils import QNamespaceContainer LOG = getLogger('moul.loc') @@ -44,17 +45,17 @@ dummy = type(lst)(["<choose>"]) return QtCore.QStringList(dummy+lst) -class LocalizationMixin(object): +class LocalizationContainer(QNamespaceContainer): """ Mixin for documentation tab """ - def _documents_init(self): + def initialize(self): """ @qtsignal loadLocalization(): load loc data """ - self._journals_loaded = False + self.loaded = False self._documents_clear('language') - self.connect(self, SIGNAL('loadLocalization()'), + self.connect(self.context, SIGNAL('loadLocalization()'), self.on_localization_doload) self.connect(self.cb_doc_language, SIGNAL("currentIndexChanged(int)"), self.on_cb_doc_language_currentIndexChanged) @@ -69,7 +70,7 @@ @qtslot loadLocalization(): Load localization @qtsignal finished(): self._journal_threadlet """ - if self._journals_loaded: + if self.loaded: return loc = self.urugamedir.loc @@ -85,17 +86,17 @@ self.trUtf8("No journals found.")) return - self._journal_progressbar = SimpleProgressbar(self) - self._journal_progressbar.setWindowTitle(self.trUtf8("Loading journals")) - self._journal_progressbar.setProgressbar(0, len(loc), 0) - self._journal_progressbar.show() + self.progressbar = SimpleProgressbar(self.context) + self.progressbar.setWindowTitle(self.trUtf8("Loading journals")) + self.progressbar.setProgressbar(0, len(loc), 0) + self.progressbar.show() - self._journal_threadlet = YieldingThreadlet(self) - self.connect(self._journal_threadlet, SIGNAL('finished()'), + self.threadlet = YieldingThreadlet(self.context) + self.connect(self.threadlet, SIGNAL('finished()'), self.on_localization_loaded) - self.connect(self._journal_threadlet, SIGNAL("yield(const QString&)"), - self._journal_progressbar.increase) - self._journal_threadlet.detach(loc) + self.connect(self.threadlet, SIGNAL("yield(const QString&)"), + self.progressbar.increase) + self.threadlet.detach(loc) @signalLogDecorator(LOG) def on_localization_loaded(self): @@ -103,17 +104,17 @@ @qtslot finished(): self._journal_threadlet """ # remove thread - self.disconnect(self._journal_threadlet, SIGNAL('finished()'), + self.disconnect(self.threadlet, SIGNAL('finished()'), self.on_localization_loaded) - self.disconnect(self._journal_threadlet, SIGNAL("yield(const QString&)"), - self._journal_progressbar.increase) - del self._journal_threadlet + self.disconnect(self.threadlet, SIGNAL("yield(const QString&)"), + self.progressbar.increase) + del self.threadlet # close and remove info message box - self._journal_progressbar.close() - del self._journal_progressbar + self.progressbar.close() + del self.progressbar - self._journals_loaded = True + self.loaded = True self.lb_doc_status.setText( self.trUtf8("Journals loaded.")) @@ -129,6 +130,9 @@ @signalLogDecorator(LOG) def on_pb_doc_loadjournals_clicked(self): """ + L{LocalizationContainer} + + @slot clicked(): clicked pb_doc_loadjournals """ self.pb_doc_loadjournals.setEnabled(False) self.emit(SIGNAL("loadLocalization()")) @@ -139,7 +143,7 @@ if name == 'doc': qobj = self.te_doc_view else: - qobj = getattr(self, 'cb_doc_%s' % name) + qobj = getattr(self.context, 'cb_doc_%s' % name) qobj.clear() qobj.setEnabled(False) @@ -196,16 +200,3 @@ qstr = QtCore.QString(translation) self.te_doc_view.setPlainText(qstr) self.te_doc_view.setEnabled(True) - -#class LocalizationLoadEventFilter(QtCore.QObject): - #"""Event filter to load localization - #""" - #def eventFilter(self, target, event): - #""" - #Event filter - #""" - #if event.type() in (QtCore.QEvent.MouseButtonPress, - #QtCore.QEvent.FocusIn): - #self.parent().emit(SIGNAL('loadLocalization()')) - - #return QtCore.QObject.eventFilter(self, target, event) Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-03 02:12:36 UTC (rev 128) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-03 18:41:23 UTC (rev 129) @@ -43,7 +43,7 @@ from moul.server.ping import isSocketError from moul.time.cavern import CavernTime -from moul.qt.localization import LocalizationMixin +from moul.qt.localization import LocalizationContainer from moul.qt.simpleprogressbar import SimpleProgressbar from moul.qt.threadlet import YieldingThreadlet from moul.qt.ui.mainwindow import Ui_MainWindow @@ -51,7 +51,7 @@ LOG = getLogger('moul.qt') -class MainWindow(QtGui.QMainWindow, Ui_MainWindow, LocalizationMixin): +class MainWindow(QtGui.QMainWindow, Ui_MainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) # Set up the user interface from Designer. @@ -80,8 +80,11 @@ self._ping_init() self._systray_init() self._about_init() - self._documents_init() + self.qcLocalization = LocalizationContainer(self) + # connect additional + QtCore.QMetaObject.connectSlotsByName(self) + # run checker self._moulrunning = None self._moulrunning_thread = MoulRunningThread() Copied: pymoul/trunk/src/moul/qt/utils.py (from rev 126, pymoul/trunk/src/moul/qt/errorhandler.py) =================================================================== --- pymoul/trunk/src/moul/qt/utils.py (rev 0) +++ pymoul/trunk/src/moul/qt/utils.py 2007-02-03 18:41:23 UTC (rev 129) @@ -0,0 +1,226 @@ +#!/usr/bin/env python2.5 +# pyMoul - Python interface to Myst Online URU Live +# Copyright (C) 2007 Christian Heimes <christian (at) cheimes (dot) de> + +# This program 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 program 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. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., 59 +# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +"""Misc utilities + +It also contains several functions to create message boxes. +""" +__author__ = "Christian Heimes" +__version__ = "$Id" +__revision__ = "$Revision$" + +import re +import warnings +from PyQt4.QtCore import QObject +from PyQt4.QtCore import SIGNAL +from PyQt4 import QtGui +from types import UnboundMethodType as UnboundMethod + +from moul.log import getLogger + + +LOG = getLogger('moul.qt.utils') +_marker=object() +SLOT_RE = re.compile('^on_(.+)_([^_]+)$') + +class QNamespaceContainer(QObject): + """ + Base class to assemble methods and logic in its own class. + + Slot methods (on_method_event()) are automatically connected to widgets of + the parent. If the methods takes an argument you *must* apply a + @pyqtSignature() decorator! + + connect(), disconnect(), emit() and attribute access are forwarded to the + parent class (like Zope2 implicit acquisition wrapper) but you *must* use + self.context instead self as argument. + + >>> class MyStuff(QNamespaceContainer): + ... def initialize(self): + ... self.connect(self.context, SIGNAL("foo()"), bar) + ... + ... @pyqtSignature("int") + ... def on_button_clicked(self, boolean): + + Now add the container to your class + >>> class MainWindow(QtCore.QObject): + ... def __init__(self, parent=None): + ... QtCore.QObject.__init__(self, parent=None) + ... self.qcMystuff = MyStuff(parent) + + @warning: If you are creating new QObject based instances you should + bind them to self.context and *not* to self. This is especially true + for QWidget based objects. + """ + + def __init__(self, parent): + """ + Constructor + + Calls initialize() and auto connects slot methods with parent's + widgets. + + @param parent: the Qt parent object + @type parent: a QObject based instance + """ + QObject.__init__(self, parent) + self.initialize() + connectSlotsByName(container=parent, callobj=self) + + @property + def context(self): + """ + Shortcut for self.parent() + """ + return self.parent() + + def connect(self, *args): + """ + Shortcut for self.parent().connect(*args) + """ + if args[0] is self: + warnings.warn("You used self as first argument but should use " + "self.context!", SyntaxWarning, stacklevel=2) + self.parent().connect(*args) + + def disconnect(self, *args): + """ + Shortcut for self.parent().disconnect(*args) + """ + if args[0] is self: + warnings.warn("You used self as first argument but should use " + "self.context!", SyntaxWarning, stacklevel=2) + self.parent().disconnect(*args) + + def emit(self, *args): + """ + Shortcut for self.parent().emit(*args) + """ + self.parent().emit(*args) + + def __getattr__(self, name, default=_marker): + """ + Get attributes form parent. + + Works similar to Zope 2's Implicit Acquisition wrapper. + """ + try: + return getattr(self.parent(), name) + except AttributeError: + if default is not _marker: + return default + else: + raise AttributeError(name) + + def initialize(self): + """ + Initialize method + + Must be implement in the subclass + """ + raise NotImplementedError + +def connectSlotsByName(container, callobj): + """ + A version of connectSlotsByName() that uses a potentially different object + to search for widget instances and to search for callbacks. This is more + flexible than the version that is provided with Qt because it allows you to + bind to callbacks on any object, not just on the widget container class + itself. You can also call this with a number of combinations of container + and callback objects. + + See QtCore.QMetaObject.connectSlotsByName() for some background info. + + Based on U{http://www.diotavelli.net/PyQtWiki/AutoConnectingSlots} + + @param container: an instance whose attributes will be inspected to find + Qt widgets. + @type container: instance of a QObject subclass + @param callobj: an object which will be inspect for appropriately named methods + to be used as callbacks for widgets on 'container'. + @type callobj: instance of a QObject subclass + + @note: You *must* use @pyqtSignature() if the method takes an argument! + """ + #logging.debug('connectSlotsByName container=%s callobj=%s' % + # (container, callobj)) + for name in dir(callobj): + method = getattr(callobj, name) + if not isinstance(method, UnboundMethod): + continue + + mo = SLOT_RE.match(name) + if mo is None: + continue + + nwidget, nsignal = mo.groups() + try: + widget = getattr(container, nwidget) + except AttributeError: + #logging.debug("Widget '%s' not found; method '%s' will not be " + # "bound." % (nwidget, name)) + continue + + # Support the QtCore.pyqtSignature decorator. + signature = '%s(%s)' % (nsignal, getattr(method, '_signature', '')) + #logging.debug('Connecting: %s to %s: %s' % (widget, signature, method)) + QObject.connect(widget, SIGNAL(signature), method) + +def _mkMessageBox(context, icon='Information'): + """ + Create a message box + """ + assert icon in ('Question', 'Information', 'Warning', 'Critical') + if context: + mb = QtGui.QMessageBox(context) + else: + mb = QtGui.QMessageBox() + mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) + mb.setIcon(getattr(QtGui.QMessageBox, icon)) + mb.setStandardButtons(QtGui.QMessageBox.Close) + return mb + + +def criticalMB(context, title, text): + """ + Critical message box + """ + mb = _mkMessageBox(context, icon='Critical') + mb.setWindowTitle(title) + mb.setText(text) + return mb + +def warningMB(context, title, text): + """ + warning message box + """ + mb = _mkMessageBox(context, icon='Warning') + mb.setWindowTitle(title) + mb.setText(text) + return mb + +def infoMB(context, title, text): + """ + Info message box + """ + mb = _mkMessageBox(context, icon='Information') + mb.setStandardButtons(QtGui.QMessageBox.Ok) + mb.setWindowTitle(title) + mb.setText(text) + return mb This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-05 00:33:59
|
Revision: 134 http://pymoul.svn.sourceforge.net/pymoul/?rev=134&view=rev Author: tiran Date: 2007-02-04 16:33:55 -0800 (Sun, 04 Feb 2007) Log Message: ----------- Added logging meta class Added save question message box Modified Paths: -------------- pymoul/trunk/src/moul/file/utils.py pymoul/trunk/src/moul/log.py pymoul/trunk/src/moul/qt/localization.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/utils.py pymoul/trunk/src/moul/qt/wdysini.py Property Changed: ---------------- pymoul/trunk/src/moul/file/utils.py Modified: pymoul/trunk/src/moul/file/utils.py =================================================================== --- pymoul/trunk/src/moul/file/utils.py 2007-02-04 15:41:40 UTC (rev 133) +++ pymoul/trunk/src/moul/file/utils.py 2007-02-05 00:33:55 UTC (rev 134) @@ -20,8 +20,8 @@ from __future__ import absolute_import __author__ = "Christian Heimes" -__version__ = "$Id: kiimage.py 129 2007-02-03 18:41:23Z tiran $" -__revision__ = "$Revision: 129 $" +__version__ = "$Id$" +__revision__ = "$Revision$" import os import time Property changes on: pymoul/trunk/src/moul/file/utils.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/log.py =================================================================== --- pymoul/trunk/src/moul/log.py 2007-02-04 15:41:40 UTC (rev 133) +++ pymoul/trunk/src/moul/log.py 2007-02-05 00:33:55 UTC (rev 134) @@ -130,26 +130,3 @@ # Redirect stdout and stderr to logger when running as frozen app #sys.stdout = LoggingStdout(getLogger('stdout').info) #sys.stderr = LoggingStdout(getLogger('stderr').error) - -__LOG_SIGNALS__ = not __FROZEN__ -def signalLogDecorator(__logger__): - """Decorator to log signals - - Logs signal methods to __logger__.debug() including func name, args - and kwargs. - - signalLogDecorator() is a NOOP when running as a sys.frozen program. - """ - def wrapper(func): - if __LOG_SIGNALS__: - def logwrapper(*args, **kwargs): - __logger__.debug("%s(*%s, **%s)" % (func.__name__, - repr(args[1:]), repr(kwargs))) - return func(*args, **kwargs) - logwrapper._signature = getattr(func, '_signature', None) - logwrapper.__name__ = func.__name__ - logwrapper.__doc__ = func.__doc__ - return logwrapper - else: - return func - return wrapper Modified: pymoul/trunk/src/moul/qt/localization.py =================================================================== --- pymoul/trunk/src/moul/qt/localization.py 2007-02-04 15:41:40 UTC (rev 133) +++ pymoul/trunk/src/moul/qt/localization.py 2007-02-05 00:33:55 UTC (rev 134) @@ -32,19 +32,21 @@ from moul.file.localization import translationRegistry as tr from moul.log import getLogger -from moul.log import signalLogDecorator from moul.qt.simpleprogressbar import SimpleProgressbar from moul.qt.threadlet import YieldingThreadlet from moul.qt.utils import QNamespaceContainer +from moul.qt.utils import QSignalLoggerMetaclass - LOG = getLogger('moul.loc') class LocalizationContainer(QNamespaceContainer): """ Mixin for documentation tab """ + __metaclass__ = QSignalLoggerMetaclass + __logger__ = LOG.debug + def initialize(self): """ @qtsignal loadLocalization(): load loc data @@ -53,12 +55,6 @@ self._documents_clear('language') self.connect(self.context, SIGNAL('loadLocalization()'), self.on_localization_doload) - self.connect(self.cb_doc_language, SIGNAL("currentIndexChanged(int)"), - self.on_cb_doc_language_currentIndexChanged) - self.connect(self.cb_doc_age, SIGNAL("currentIndexChanged(int)"), - self.on_cb_doc_age_currentIndexChanged) - self.connect(self.cb_doc_set, SIGNAL("currentIndexChanged(int)"), - self.on_cb_doc_set_currentIndexChanged) @staticmethod def insertDummyQ(lst): @@ -66,7 +62,6 @@ return QtCore.QStringList(dummy+lst) @pyqtSignature("") - @signalLogDecorator(LOG) def on_localization_doload(self): """ @qtslot loadLocalization(): Load localization @@ -101,7 +96,6 @@ self.threadlet.detach(loc) @pyqtSignature("") - @signalLogDecorator(LOG) def on_localization_loaded(self): """ @qtslot finished(): self._journal_threadlet @@ -130,7 +124,6 @@ self.cb_doc_language.setEnabled(True) @pyqtSignature("") - @signalLogDecorator(LOG) def on_pb_doc_loadjournals_clicked(self): """ L{LocalizationContainer} @@ -151,7 +144,6 @@ qobj.setEnabled(False) @pyqtSignature("int") - @signalLogDecorator(LOG) def on_cb_doc_language_currentIndexChanged(self, idx): self._documents_clear('age') if idx <= 0: @@ -164,7 +156,6 @@ self.cb_doc_age.setEnabled(True) @pyqtSignature("int") - @signalLogDecorator(LOG) def on_cb_doc_age_currentIndexChanged(self, idx): self._documents_clear('set') if idx <= 0: @@ -178,7 +169,6 @@ self.cb_doc_set.setEnabled(True) @pyqtSignature("int") - @signalLogDecorator(LOG) def on_cb_doc_set_currentIndexChanged(self, idx): self._documents_clear('element') if idx <= 0: @@ -192,7 +182,6 @@ self.cb_doc_element.setEnabled(True) @pyqtSignature("int") - @signalLogDecorator(LOG) def on_cb_doc_element_currentIndexChanged(self, idx): self._documents_clear('doc') if idx <= 0: Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-04 15:41:40 UTC (rev 133) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-05 00:33:55 UTC (rev 134) @@ -36,7 +36,6 @@ from moul.file.directory import UruGameDataDirectory from moul.file.directory import UruPersonalDataDirectory from moul.log import getLogger -from moul.log import signalLogDecorator from moul.osdependent import isMoulRunning from moul.server.ping import ServerList from moul.server.ping import isSocketError @@ -47,10 +46,14 @@ from moul.qt.simpleprogressbar import SimpleProgressbar from moul.qt.threadlet import YieldingThreadlet from moul.qt.ui.mainwindow import Ui_MainWindow +from moul.qt import utils as qtutils LOG = getLogger('moul.qt') class MainWindow(QtGui.QMainWindow, Ui_MainWindow): + __metaclass__ = qtutils.QSignalLoggerMetaclass + __logger__ = LOG.debug + def __init__(self): QtGui.QMainWindow.__init__(self) # Set up the user interface from Designer. @@ -88,7 +91,6 @@ self.on_moulIsRunning) self._moulrunning_thread.startChecker(5.0) # check now and every 5 seconds - @signalLogDecorator(LOG) def on_moulIsRunning(self, boolean): """ @qtslot moulIsRunning(bool): notify if moul is running @@ -127,12 +129,13 @@ @param event: close event @type event: QCloseEvent instance """ - #if self._dirty: - # event.reject() - # return False - - self._systray_close() - event.accept() + accept = self.handleDirtyOnClose() + if accept: + self._systray_close() + self._moulrunning_thread.terminate() + event.accept() + else: + event.ignore() def keyPressEvent(self, event): """ @@ -179,10 +182,37 @@ self.main_buttonbox_save.setEnabled(False) self.main_buttonbox_reset.setEnabled(False) + def handleDirtyOnClose(self): + """ + Handle dirty status on close + + @return: Accept event? + @rtype: bool + """ + if not self.isDirty(): + return True + + mb = qtutils.saveMB( + self, + self.trUtf8("Quit"), + self.trUtf8("Do you want to save your changes or discard " + "them ?") + ) + button = mb.exec_() + if button == QtGui.QMessageBox.Save: + self.main_buttonbox_save.click() + return True + elif button == QtGui.QMessageBox.Cancel: + return False + elif button == QtGui.QMessageBox.Discard: + return True + else: + LOG.critical("Unknow button %s" % button) + return False + # ************************************************************************ # tasks @pyqtSignature("") - @signalLogDecorator(LOG) def on_pb_kiimage_repair_clicked(self): """ Clicked repair button @@ -206,7 +236,6 @@ self._kiimage_progressbar.show() self._kiimage_threadlet.detach(kimover) - @signalLogDecorator(LOG) def on_pb_kiimage_repair_done(self): """ Repair threadlet done @@ -271,6 +300,7 @@ self.lb_pacific_utc.setText(QtCore.QString(txt)) @pyqtSignature("") + @qtutils.skipLogging def on_timezone_timer_timeout(self): """ SIGNAL: QTimer timeout @@ -302,12 +332,10 @@ self.connect(thread, SIGNAL("ping(const QString&, float)"), self.on_pingthread_ping) - @signalLogDecorator(LOG) def on_pingthread_started(self): self.button_ping.setEnabled(False) self.text_ping.clear() - @signalLogDecorator(LOG) def on_pingthread_done(self): self.button_ping.setEnabled(True) @@ -330,7 +358,6 @@ self.text_ping.insertPlainText("PING error: %s\n" % errmsg) @pyqtSignature("bool") - @signalLogDecorator(LOG) def on_button_ping_clicked(self, ignore=False): thread = self._ping_thread if not thread.isRunning(): Modified: pymoul/trunk/src/moul/qt/utils.py =================================================================== --- pymoul/trunk/src/moul/qt/utils.py 2007-02-04 15:41:40 UTC (rev 133) +++ pymoul/trunk/src/moul/qt/utils.py 2007-02-05 00:33:55 UTC (rev 134) @@ -14,7 +14,7 @@ # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., 59 -# Temple Place, Suite 330, Boston, MA 02111-1307 USA +# Temple Place, Suitel 330, Boston, MA 02111-1307 USA # """Misc utilities @@ -27,15 +27,81 @@ import logging import re +import sip import warnings from PyQt4.QtCore import QObject from PyQt4.QtCore import SIGNAL from PyQt4 import QtGui -from types import UnboundMethodType as UnboundMethod +from types import UnboundMethodType +from types import FunctionType _marker=object() SLOT_RE = re.compile('^on_(.+)_([^_]+)$') +def skipLogging(func): + """Decorator to skip logging + + @param func: a function object + @type func: FunctionType + """ + func.__qsignallogger__ = False + return func + +def logDecorator(func, logger=None): + """ + Log decorator for QSignalLoggerMetaclass + + @param logger: a callable or None + @param func: a function object + @type func: FunctionType + """ + if logger is None: + logger = logging.debug + def logwrapper(*args, **kwargs): + name = func.__name__ + logger("Call: %s(%s %s)" % (name, + repr(args[1:]) if len(args) > 1 else '', + repr(kwargs) if kwargs else '')) + return func(*args, **kwargs) + + logwrapper.__name__ = func.__name__ + logwrapper.__doc__ = func.__doc__ + signature = getattr(func, '_signature', None) + if signature is not None: + logwrapper._signature = signature + return logwrapper + +class QSignalLoggerMetaclass(sip.wrappertype): + """ + QSignal logger meta class + + Example: + >>> class MyClass: + ... __metaclass__ = QSignalLogger + ... __logger__ = aCallableLoggerFunction + ... + ... @pyqtSignature("bool") + ... def on_mybutton_clicked(self, boolean): + ... pass + ... + ... @pyqtSignature("") + ... @skipLogging + ... def on_notinteresting_clicked(self, boolean): + ... pass + + """ + def __new__(cls, name, bases, dict): + logger = dict.get('__logger__', None) + for key, value in dict.items(): + # on_*_* + if not isinstance(value, FunctionType): + continue + if getattr(value, '__qsignallogger__', None) is not None: + continue + if (key.startswith('on_') and key.find('_', 4) > 0): + dict[key] = logDecorator(value, logger) + return sip.wrappertype.__new__(cls, name, bases, dict) + class QNamespaceContainer(QObject): """ Base class to assemble methods and logic in its own class. @@ -159,7 +225,7 @@ # (container, callobj)) for name in dir(callobj): method = getattr(callobj, name) - if not isinstance(method, UnboundMethod): + if not isinstance(method, UnboundMethodType): continue mo = SLOT_RE.match(name) @@ -185,7 +251,7 @@ #logging.debug('Connecting: %s to %s: %s' % (widget, signature, method)) QObject.connect(widget, SIGNAL(signature), method) -def _mkMessageBox(context, icon='Information'): +def _mkMessageBox(context, title, text, icon='Information'): """ Create a message box """ @@ -197,33 +263,35 @@ mb.setWindowIcon(QtGui.QIcon(":/resources/uru_icon_32x32.png")) mb.setIcon(getattr(QtGui.QMessageBox, icon)) mb.setStandardButtons(QtGui.QMessageBox.Close) + mb.setWindowTitle(title) + mb.setText(text) return mb - def criticalMB(context, title, text): """ Critical message box """ - mb = _mkMessageBox(context, icon='Critical') - mb.setWindowTitle(title) - mb.setText(text) - return mb + return _mkMessageBox(context, title, text, icon='Critical') def warningMB(context, title, text): """ warning message box """ - mb = _mkMessageBox(context, icon='Warning') - mb.setWindowTitle(title) - mb.setText(text) - return mb + return _mkMessageBox(context, title, text, icon='Warning') def infoMB(context, title, text): """ Info message box """ - mb = _mkMessageBox(context, icon='Information') + mb = _mkMessageBox(context, title, text, icon='Information') mb.setStandardButtons(QtGui.QMessageBox.Ok) - mb.setWindowTitle(title) - mb.setText(text) return mb + +def saveMB(context, title, text): + """ + A question box with save discard cancel + """ + mb = _mkMessageBox(context, title, text, icon='Question') + mb.setStandardButtons(QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard + | QtGui.QMessageBox.Cancel) + return mb Modified: pymoul/trunk/src/moul/qt/wdysini.py =================================================================== --- pymoul/trunk/src/moul/qt/wdysini.py 2007-02-04 15:41:40 UTC (rev 133) +++ pymoul/trunk/src/moul/qt/wdysini.py 2007-02-05 00:33:55 UTC (rev 134) @@ -37,32 +37,36 @@ from moul.file.directory import UruPersonalDataDirectory from moul.file.wdysini import videoModes from moul.log import getLogger -from moul.log import signalLogDecorator from moul.qt.utils import QNamespaceContainer +from moul.qt.utils import QSignalLoggerMetaclass LOG = getLogger('moul.qt') class IniFileContainer(QNamespaceContainer): + __metaclass__ = QSignalLoggerMetaclass + __logger__ = LOG.debug + def initialize(self): # graphics.ini + gini = self.urupersonaldir.graphicsini self.connect(self.context, SIGNAL("graphicsChanged(bool)"), self.on_graphicsChanged) - self.connect(self.context, SIGNAL("graphicsini_loaded()"), self.on_graphicsini_loaded) + self.connect(self.context, SIGNAL("graphicsini_load()"), self.on_graphicsini_load) self.connect(self.context, SIGNAL("graphicsini_reset()"), self.on_graphicsini_reset) self.connect(self.context, SIGNAL("graphicsini_save()"), self.on_graphicsini_save) self.connect(self.main_buttonbox_reset, SIGNAL("clicked()"), self.on_graphicsini_reset) self.connect(self.main_buttonbox_save, SIGNAL("clicked()"), self.on_graphicsini_save) # audio.ini + aini = self.urupersonaldir.audioini self.connect(self.context, SIGNAL("audioChanged(bool)"), self.on_audioChanged) - self.connect(self.context, SIGNAL("audioini_loaded()"), self.on_audioini_loaded) + self.connect(self.context, SIGNAL("audioini_load()"), self.on_audioini_load) self.connect(self.context, SIGNAL("audiini_reset()"), self.on_audioini_reset) self.connect(self.context, SIGNAL("audiini_save()"), self.on_audioini_save) self.connect(self.main_buttonbox_reset, SIGNAL("clicked()"), self.on_audioini_reset) self.connect(self.main_buttonbox_save, SIGNAL("clicked()"), self.on_audioini_save) + # emit load + self.context.emit(SIGNAL("audioini_load()")) # XXX: hard coded emit + self.context.emit(SIGNAL("graphicsini_load()")) # XXX: hard coded emit - self.context.emit(SIGNAL("audioini_loaded()")) # XXX: hard coded emit - self.context.emit(SIGNAL("graphicsini_loaded()")) # XXX: hard coded emit - - @signalLogDecorator(LOG) @pyqtSignature("bool") def on_graphicsChanged(self, boolean): """ @@ -70,7 +74,6 @@ """ self.context.notifyDirty('graphicsini', boolean) - @signalLogDecorator(LOG) @pyqtSignature("bool") def on_audioChanged(self, boolean): """ @@ -78,11 +81,10 @@ """ self.context.notifyDirty('audioini', boolean) - @signalLogDecorator(LOG) @pyqtSignature("") - def on_graphicsini_loaded(self): + def on_graphicsini_load(self): """ - @qtslot graphicsini_loaded(): notify when a graphics.ini is loaded + @qtslot graphicsini_load(): load ini """ gini = self.urupersonaldir.graphicsini try: @@ -96,7 +98,6 @@ self._graphicsini_setstate() self.emit(SIGNAL("graphicsChanged(bool)"), False) - @signalLogDecorator(LOG) @pyqtSignature("") def on_graphicsini_reset(self): """ @@ -106,7 +107,6 @@ self.urupersonaldir.graphicsini.reset() self._graphicsini_setstate() - @signalLogDecorator(LOG) @pyqtSignature("") def on_graphicsini_save(self): """ @@ -136,7 +136,6 @@ self.cb_gra_vsync.setChecked(gini.vsync) self.cb_gra_shadow.setChecked(gini.shadow_enabled) - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_screenres_valueChanged(self, idx): """ @@ -145,7 +144,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.screenres = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_screenres_sliderMoved(self, idx): """ @@ -155,7 +153,6 @@ txt = videoModes.getVidModeHuman(idx) self.lb_screenres.setText(QtCore.QString(txt)) - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_quality_valueChanged(self, idx): """ @@ -164,7 +161,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.quality = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_texture_valueChanged(self, idx): """ @@ -173,7 +169,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.texture = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_antialias_valueChanged(self, idx): """ @@ -182,7 +177,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.antialias = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_anisotropic_valueChanged(self, idx): """ @@ -191,7 +185,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.anisotropic = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_gra_shadow_valueChanged(self, idx): """ @@ -200,7 +193,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.shadow = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_windowed_stateChanged(self, state): """ @@ -209,7 +201,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.windowed = state - @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_vsync_stateChanged (self, state): """ @@ -218,7 +209,6 @@ self.emit(SIGNAL("graphicsChanged(bool)"), True) self.urupersonaldir.graphicsini.vsync = state - @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_gra_shadow_stateChanged (self, state): """ @@ -230,10 +220,9 @@ # ************************************************************************ # audio settings - @signalLogDecorator(LOG) - def on_audioini_loaded(self): + def on_audioini_load(self): """ - SIGNAL: audioini_loaded() + SIGNAL: audioini_load() """ aini = self.urupersonaldir.audioini try: @@ -247,7 +236,6 @@ self._audioini_setstate() self.emit(SIGNAL("audioChanged(bool)"), False) - @signalLogDecorator(LOG) def on_audioini_reset(self): """ SIGNAL audioini_reset() @@ -256,7 +244,6 @@ self.urupersonaldir.audioini.reset() self._audioini_setstate() - @signalLogDecorator(LOG) def on_audioini_save(self): """ SIGNAL audioini_save() @@ -284,61 +271,51 @@ self.cb_aud_mute.setChecked(aini.mute) self.cb_aud_voicechat.setChecked(aini.enablevoice) - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_device_valueChanged(self, idx): self.urupersonaldir.audioini.device = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_device_sliderMoved(self, idx): self.emit(SIGNAL("audioChanged(bool)"), True) txt = self.urupersonaldir.audioini.getDeviceName(idx) self.lb_aud_device.setText(QtCore.QString(txt[1:-1])) - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_npc_valueChanged(self, idx): self.emit(SIGNAL("audioChanged(bool)"), True) self.urupersonaldir.audioini.npc = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_music_valueChanged(self, idx): self.emit(SIGNAL("audioChanged(bool)"), True) self.urupersonaldir.audioini.music = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_fx_valueChanged(self, idx): self.emit(SIGNAL("audioChanged(bool)"), True) self.urupersonaldir.audioini.fx = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_ambience_valueChanged(self, idx): self.emit(SIGNAL("audioChanged(bool)"), True) self.urupersonaldir.audioini.ambience = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_sl_aud_priority_valueChanged(self, idx): self.emit(SIGNAL("audioChanged(bool)"), True) self.urupersonaldir.audioini.priority = idx - @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_eax_stateChanged (self, state): self.emit(SIGNAL("audioChanged(bool)"), True) self.urupersonaldir.audioini.eax = state - @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_mute_stateChanged (self, state): self.emit(SIGNAL("audioChanged(bool)"), True) self.urupersonaldir.audioini.mute = state - @signalLogDecorator(LOG) @pyqtSignature("int") def on_cb_aud_voicechat_stateChanged (self, state): self.emit(SIGNAL("audioChanged(bool)"), True) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-05 04:09:42
|
Revision: 137 http://pymoul.svn.sourceforge.net/pymoul/?rev=137&view=rev Author: tiran Date: 2007-02-04 20:09:41 -0800 (Sun, 04 Feb 2007) Log Message: ----------- Removed second implemenation of procesinfo stuff Added getMoulInstallDir() function and a list of locations for Win32 and Linux Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/osdependent/__init__.py pymoul/trunk/src/moul/osdependent/linux/__init__.py pymoul/trunk/src/moul/osdependent/win32/__init__.py pymoul/trunk/src/moul/osdependent/win32/winpath.py Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-02-05 03:19:59 UTC (rev 136) +++ pymoul/trunk/src/moul/config/__init__.py 2007-02-05 04:09:41 UTC (rev 137) @@ -45,8 +45,8 @@ from moul.osdependent import getMoulUserDataDir from moul.osdependent import getPyMoulDataDir +from moul.osdependent import getMoulInstallDir - _marker=object() # configuration @@ -111,9 +111,7 @@ addSection = _configuration.addSection listConfig = _configuration.listConfig -# hard coded for my system -#setOption('moul', 'installdir', 'D:\\games\\MystOnline') -setOption('moul', 'installdir', '/home/heimes/dev/pymoul/MystOnline') +#setOption('moul', 'installdir', '') ## directories class Directories(object): @@ -124,7 +122,7 @@ self._config = config def getMoulInstallDir(self): - return self._config.getOption('moul.installdir') + return getMoulInstallDir() def getMoulUserDataDir(self): return getMoulUserDataDir() Modified: pymoul/trunk/src/moul/osdependent/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/__init__.py 2007-02-05 03:19:59 UTC (rev 136) +++ pymoul/trunk/src/moul/osdependent/__init__.py 2007-02-05 04:09:41 UTC (rev 137) @@ -59,10 +59,13 @@ __POSIX__, __NT__) # names to import: from moul.osdependent.ID import NAME (as NAME) -NAMES = ('getMoulUserDataDir', - ('getPyMoulDataDir', '_getPyMoulDataDir'), # as - 'startMoul', 'isMoulRunning', - ) +NAMES = ( + 'getMoulUserDataDir', + 'getMoulInstallDir', + ('getPyMoulDataDir', '_getPyMoulDataDir'), # as + 'startMoul', + 'isMoulRunning', + ) _marker = object() Modified: pymoul/trunk/src/moul/osdependent/linux/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-02-05 03:19:59 UTC (rev 136) +++ pymoul/trunk/src/moul/osdependent/linux/__init__.py 2007-02-05 04:09:41 UTC (rev 137) @@ -23,6 +23,7 @@ import os from subprocess import Popen +from moul.osdependent.processinfo import getPidNames from moul.log import getLogger @@ -35,6 +36,11 @@ EXEC_NAME = "UruLauncher" HOME = os.environ['HOME'] PROCESSES = ('urulauncher', 'uruexplorer') +LOCATIONS = [ + "%s/dev/pymoul/MystOnline" % HOME, + "/media/d/games/MystOnline", + "/usr/local/games/MystOnline" + ] def getMoulUserDataDir(): """Get path of MOUL data directory @@ -50,6 +56,17 @@ inidir= os.path.join(HOME, '.pymoul') return inidir +def getMoulInstallDir(): + """Get path to MOUL install dir + """ + for path in LOCATIONS: + if os.path.isfile(os.path.join(path, EXEC_NAME)): + LOG.info("Uru directory found: %s" % path) + return path + LOG.warning("Uru directory NOT found! Search path was: \n %s" % + repr(LOCATIONS)) + return 'INVALID' + def startMoul(installdir, *args, **kwargs): """Start MOUL - returns a Popen instance @@ -63,55 +80,7 @@ def isMoulRunning(): """Test if MOUL or the launcher is running """ - for pid, name in getCurrentPidNames().items(): + for pid, name in getPidNames().items(): if name.lower() in PROCESSES: - return name.lower() + return pid return False - -# process info -# based on http://gelb.bcom.at/trac/misc/browser/processinfo -def getCurrentPids(): - """Returns current process ids - """ - pids = [] - for fname in os.listdir("/proc"): - if os.path.isdir(os.path.join("/proc", fname)): - try: - pids.append(int(fname)) - except ValueError: - continue - return pids - -def getCurrentPidDetails(): - """Returns mapping pid -> detailed informations - """ - mapping = {} - for pid in getCurrentPids(): - try: - try: - # read entiry file to avoid race condition bugs - fd = open('/proc/%i/status' % pid, 'rb') - status = fd.read().split('\n') - finally: - if fd: - fd.close() - except IOError: - continue - details = {} - for line in status: - try: - key, value = line.split(':\t') - except ValueError: - continue - details[key.lower()] = value.strip() - mapping[pid] = details - - return mapping - -def getCurrentPidNames(): - """Returns mapping pid -> name - """ - mapping = {} - for pid, details in getCurrentPidDetails().items(): - mapping[pid] = details.get('name', None) - return mapping Modified: pymoul/trunk/src/moul/osdependent/win32/__init__.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-02-05 03:19:59 UTC (rev 136) +++ pymoul/trunk/src/moul/osdependent/win32/__init__.py 2007-02-05 04:09:41 UTC (rev 137) @@ -26,8 +26,7 @@ from moul.log import getLogger from moul.osdependent.processinfo import getPidNames -from moul.osdependent.win32.winpath import get_appdata as getAppdata -from moul.osdependent.win32.winpath import get_homedir as getMyDocuments +from moul.osdependent.win32 import winpath LOG = getLogger('moul.win') @@ -37,9 +36,21 @@ # lower case PROCESSES = ("urulauncher.exe", "uruexplorer.exe") -MYDOCS = getMyDocuments() -MYAPPDATA = getAppdata() +MYDOCS = winpath.getMyDocuments() +MYAPPDATA = winpath.getAppdata() +PROGRAMFILES = winpath.getProgramFiles() +HOME = winpath.getHome() +DESKTOP = winpath.getHome() +LOCATIONS = [ + # my location + r"D:\games\MystOnline", + r"%s\moul\MystOnline" % DESKTOP, + # generic locations + r"%s\Myst Online" % PROGRAMFILES, + r"%s\GameTap\volumes\games\140000150\data" % PROGRAMFILES, + ] + def getMoulUserDataDir(): """Get path of MOUL data directory @@ -55,6 +66,17 @@ inidir = os.path.join(MYAPPDATA , 'pyMoul') return inidir +def getMoulInstallDir(): + """Get path to MOUL install dir + """ + for path in LOCATIONS: + if os.path.isfile(os.path.join(path, EXEC_NAME)): + LOG.info("Uru directory found: %s" % path) + return path + LOG.warning("Uru directory NOT found! Search path was: \n %s" % + repr(LOCATIONS)) + return 'INVALID' + def startMoul(installdir, *args, **kwargs): """Start MOUL - returns a Popen instance @@ -70,6 +92,5 @@ """ for pid, name in getPidNames().items(): if name.lower() in PROCESSES: - return pid, name.lower() + return pid return False - Modified: pymoul/trunk/src/moul/osdependent/win32/winpath.py =================================================================== --- pymoul/trunk/src/moul/osdependent/win32/winpath.py 2007-02-05 03:19:59 UTC (rev 136) +++ pymoul/trunk/src/moul/osdependent/win32/winpath.py 2007-02-05 04:09:41 UTC (rev 137) @@ -27,9 +27,10 @@ __copyright__ = "Python license" # standard library modules -import _winreg, os +import _winreg +import os +import re - SHELL_FOLDERS = \ r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' USER_SHELL_FOLDERS = \ @@ -41,20 +42,14 @@ def _substenv(m): return os.environ.get(m.group(1), m.group(0)) -_env_rx = None +_env_rx = re.compile(r'%([^|<>=^%]+)%') def expandvars(s): """Expand environment variables of form %var%. Unknown variables are left unchanged. """ - - global _env_rx - if '%' not in s: return s - if _env_rx is None: - import re - _env_rx = re.compile(r'%([^|<>=^%]+)%') return _env_rx.sub(_substenv, s) def _get_reg_value(key, subkey, name): @@ -63,7 +58,6 @@ Environment variables in values of type REG_EXPAND_SZ are expanded if possible. """ - key = _winreg.OpenKey(key, subkey) try: ret = _winreg.QueryValueEx(key, name) @@ -78,46 +72,47 @@ def _get_reg_user_value(key, name): """Return a windows registry value from the CURRENT_USER branch.""" - return _get_reg_value(HKCU, key, name) def _get_reg_machine_value(key, name): """Return a windows registry value from the LOCAL_MACHINE branch.""" - return _get_reg_value(HKLM, key, name) # public functions -def get_appdata(): - """Return path of directory where apps should store user specific data.""" - +def getAppdata(): + """Return path of directory where apps should store user specific data. + """ return _get_reg_user_value(SHELL_FOLDERS, 'AppData') -def get_common_shellfolders(): - """Return mapping of shell folder names (all users) to paths.""" +def getCommonShellfolders(): + """Return mapping of shell folder names (all users) to paths. + """ + return getShellfolders(branch=HKLM) - return get_shellfolders(branch=HKLM) +def getMyDocuments(): + """Return path to user home directory, i.e. 'My Files'. + """ + return _get_reg_user_value(SHELL_FOLDERS, 'Personal') -def get_homedir(): - """Return path to user home directory, i.e. 'My Files'.""" +def getDesktop(): + """Return path to desktop. + """ + return _get_reg_user_value(SHELL_FOLDERS, 'Desktop') - return _get_reg_user_value(SHELL_FOLDERS, 'Personal') - -def get_sharedconf(prog, *args): +def getSharedconf(prog, *args): """Return path to shared configuration data for 'prog' from 'vendor'. Additional arguments are appended via os.path.join(). See also: get_user_conf() """ - return os.path.join( _get_reg_machine_value(SHELL_FOLDERS, 'Common AppData'), vendor, prog, *args ) -def get_shellfolders(branch=HKCU, key=SHELL_FOLDERS): +def getShellfolders(branch=HKCU, key=SHELL_FOLDERS): """Return mapping of shell folder names (current user) to paths.""" - key = _winreg.OpenKey(branch, key) folders = {} i = 0 @@ -134,7 +129,7 @@ key.Close() return folders -def get_userconf(vendor, prog, *args): +def getUserconf(vendor, prog, *args): """Return path to user configuration data for 'prog' from 'vendor'. Additional arguments are appended via os.path.join(), e.g. @@ -142,10 +137,19 @@ optionsfn = get_userconf("ACME Soft", "Exploder", "Options.xml") """ + return os.path.join(getAppdata(), vendor, prog, *args) - return os.path.join(get_appdata(), vendor, prog, *args) +def getWindir(): + """Convenience function to get path to windows installation directory. + """ + return unicode(os.environ["WINDIR"]) -def get_windir(): - """Convenience function to get path to windows installation directory.""" +def getProgramFiles(): + """Convenience function to get path to program files directory. + """ + return unicode(os.environ["PROGRAMFILES"]) - return unicode(os.environ["WINDIR"]) +def getHome(): + """Convenience function to get path to home directory. + """ + return unicode(os.path.expanduser("~")) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-05 14:51:31
|
Revision: 140 http://pymoul.svn.sourceforge.net/pymoul/?rev=140&view=rev Author: tiran Date: 2007-02-05 06:51:30 -0800 (Mon, 05 Feb 2007) Log Message: ----------- Fixed some unit tests Manually set tab order Modified Paths: -------------- pymoul/trunk/src/moul/config/__init__.py pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/file/tests/test_plasmalog.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.py pymoul/trunk/src/moul/qt/ui/mainwindow.ui Modified: pymoul/trunk/src/moul/config/__init__.py =================================================================== --- pymoul/trunk/src/moul/config/__init__.py 2007-02-05 14:03:09 UTC (rev 139) +++ pymoul/trunk/src/moul/config/__init__.py 2007-02-05 14:51:30 UTC (rev 140) @@ -93,7 +93,7 @@ """List >>> cfg = listConfig() - >>> len(cfg) > 0 + >>> len(cfg) == 0 True >>> type(cfg) <type 'dict'> Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-02-05 14:03:09 UTC (rev 139) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-02-05 14:51:30 UTC (rev 140) @@ -121,7 +121,7 @@ 'modtime' : mtime, 'created' : created, 'newname' : newname, - 'v' : os.path.join(self._dest, newname), + 'newpath' : os.path.join(self._dest, newname), } self._logs.append(details) Modified: pymoul/trunk/src/moul/file/tests/test_plasmalog.py =================================================================== --- pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-02-05 14:03:09 UTC (rev 139) +++ pymoul/trunk/src/moul/file/tests/test_plasmalog.py 2007-02-05 14:51:30 UTC (rev 140) @@ -109,10 +109,11 @@ pass content = os.listdir(self._kidest) self.failUnlessEqual(len(content), 1, content) - self.failUnlessEqual(content, ["KIimage001.jpg"]) + self.failUnless(content[0].startswith("KIimage_200")) + self.failUnless(content[0].endswith("_0001.jpg")) cleandata = open(os.path.join(base, 'avatar_clean.jpg'), 'rb').read() - newdata = open(os.path.join(self._kidest, "KIimage001.jpg"), 'rb').read() + newdata = open(os.path.join(self._kidest, content[0]), 'rb').read() self.failUnlessEqual(len(cleandata), len(newdata)) self.failUnlessEqual(cleandata, newdata) Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-05 14:03:09 UTC (rev 139) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-05 14:51:30 UTC (rev 140) @@ -58,7 +58,12 @@ QtGui.QMainWindow.__init__(self) # Set up the user interface from Designer. self.setupUi(self) - + + #self.lb_top_image.setPixmap(QtGui.QPixmap(":/resources/moul_logo.png")) + self.tabWidget.setCurrentIndex(0) + self.tab_sub_settings.setCurrentIndex(0) + self.tabwidget_about.setCurrentIndex(0) + # hook up main buttonbox but = self.main_buttonbox.button self.main_buttonbox_reset = but(QtGui.QDialogButtonBox.Reset) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-02-05 14:03:09 UTC (rev 139) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.py 2007-02-05 14:51:30 UTC (rev 140) @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file './src/moul/qt/ui/mainwindow.ui' # -# Created: Mon Feb 5 03:59:23 2007 +# Created: Mon Feb 5 15:25:54 2007 # by: PyQt4 UI code generator 4.1.1 # # WARNING! All changes made in this file will be lost! @@ -38,7 +38,6 @@ self.lb_top_image.setMaximumSize(QtCore.QSize(434,61)) self.lb_top_image.setFrameShape(QtGui.QFrame.StyledPanel) self.lb_top_image.setFrameShadow(QtGui.QFrame.Sunken) - self.lb_top_image.setPixmap(QtGui.QPixmap(":/resources/moul_logo.png")) self.lb_top_image.setObjectName("lb_top_image") self.hboxlayout.addWidget(self.lb_top_image) Modified: pymoul/trunk/src/moul/qt/ui/mainwindow.ui =================================================================== --- pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-02-05 14:03:09 UTC (rev 139) +++ pymoul/trunk/src/moul/qt/ui/mainwindow.ui 2007-02-05 14:51:30 UTC (rev 140) @@ -80,9 +80,6 @@ <property name="text" > <string/> </property> - <property name="pixmap" > - <pixmap resource="moulqt.qrc" >:/resources/moul_logo.png</pixmap> - </property> </widget> </item> <item> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ti...@us...> - 2007-02-06 16:48:49
|
Revision: 147 http://pymoul.svn.sourceforge.net/pymoul/?rev=147&view=rev Author: tiran Date: 2007-02-06 08:48:27 -0800 (Tue, 06 Feb 2007) Log Message: ----------- Fixed import errors Fixed already running msg Modified Paths: -------------- pymoul/trunk/src/moul/file/chatlog.py pymoul/trunk/src/moul/qt/i18n/__init__.py pymoul/trunk/src/moul/qt/mainwindow.py pymoul/trunk/src/moul/qt/moulqt.py Property Changed: ---------------- pymoul/trunk/src/moul/qt/i18n/__init__.py Modified: pymoul/trunk/src/moul/file/chatlog.py =================================================================== --- pymoul/trunk/src/moul/file/chatlog.py 2007-02-06 15:58:25 UTC (rev 146) +++ pymoul/trunk/src/moul/file/chatlog.py 2007-02-06 16:48:27 UTC (rev 147) @@ -73,9 +73,6 @@ r"(?P<ch>\d{2})(?P<cm>\d{2})_(?P<sh>\d{2})(?P<sm>\d{2})\.txt", # hhmm_hhmm.txt RE_FLAGS ) -#CHATLOG_FNAME_RE = re.compile( -# r"[cC]hat.*\.log", # chat*.log -# RE_FLAGS) LOG = getLogger('moul.chat') @@ -203,9 +200,16 @@ def __init__(self, logdir): self._logdir = logdir self._logfiles = [] # list of ChatlogViews + self.refresh() - if not os.path.isdir(logdir): + def refresh(self): + """Refresh list + """ + # TODO: inefficient, compare list with directory content + if not os.path.isdir(self._logdir): LOG.warning("%s is not a directory" % logdir) + return + self._logfiles[:] = [] self._findChatlogs() def _findChatlogs(self): @@ -218,10 +222,12 @@ chatlog = ChatlogView(fname) if chatlog.date is not None: self._logfiles.append(chatlog) + self._logfiles.sort(key=lambda element:(element.date, element.name)) - @property - def names(self): - return [clv.name for clv in self] + def __len__(self): + """len() support + """ + return len(self._logfiles) def __iter__(self): return iter(self._logfiles) @@ -281,8 +287,8 @@ def view(self): """View the file - Returns an iterator which iterates over the lines of the file + @return: file content + @rtype: str """ self.open() - # TODO: add parser, currently simply iterates over the file - return iter(self._fd) + self._fd.read() Modified: pymoul/trunk/src/moul/qt/i18n/__init__.py =================================================================== --- pymoul/trunk/src/moul/qt/i18n/__init__.py 2007-02-06 15:58:25 UTC (rev 146) +++ pymoul/trunk/src/moul/qt/i18n/__init__.py 2007-02-06 16:48:27 UTC (rev 147) @@ -20,8 +20,8 @@ moul.qt.i18n """ __author__ = "Christian Heimes" -__version__ = "$Id: __init__.py 108 2007-01-31 14:46:54Z tiran $" -__revision__ = "$Revision: 108 $" +__version__ = "$Id$" +__revision__ = "$Revision$" import sys Property changes on: pymoul/trunk/src/moul/qt/i18n/__init__.py ___________________________________________________________________ Name: svn:keywords + Id Revision Name: svn:eol-style + native Modified: pymoul/trunk/src/moul/qt/mainwindow.py =================================================================== --- pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-06 15:58:25 UTC (rev 146) +++ pymoul/trunk/src/moul/qt/mainwindow.py 2007-02-06 16:48:27 UTC (rev 147) @@ -24,12 +24,13 @@ __version__ = "$Id$" __revision__ = "$Revision$" -import sys +import os from PyQt4 import QtCore from PyQt4 import QtGui from PyQt4.QtCore import Qt from PyQt4.QtCore import SIGNAL from PyQt4.QtCore import pyqtSignature +import sys from moul import metadata from moul.config import lookupDir @@ -96,32 +97,6 @@ self.on_moulIsRunning) self._moulrunning_thread.startChecker(5.0) # check now and every 5 seconds - about = self.trUtf8(""" -<center> -<h3>Tool for Myst Online : Uru Live</h3> - -<p>(c) 2007 Christian Heimes</p> - -<p><a href="http://pymoul.sourceforge.net">http://pymoul.sourceforge.net</a></p> -</center> - -<h4>Bug reporting</h4> -<p align="justify">If you encountered a bug please <a href="http://sourceforge.net/tracker/?group_id=186624&atid=918033l"> -create a bug report</a> with description of your actions along with the log file. You can find the log file at:</p> - -<tt align="center">%1/pymoul.log</tt> - -<h4>Donation</h4> -<p align="justify">If you like the tool please consider to <a href="%2">donate</a> some money to sponsor my work. The tool is created in my free time as an open source project. You can sent money to my <a href="%2">PayPal account</a> using your PayPal account, credit card or bank account. You can also use the SourceForget.net <a href="%3">donate page</a>. Your money will be used to found my MOUL account and new hardware for my 4 years old computer.</p> - -<p>sincerely yours<br> -Tiran [KI: #00025784]</p> - """) - paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=chr...@ch...&item_name=Donate for Tiran's open source activities&page_style=PayPal&no_shipping=0&cn=Your note for me&tax=0¤cy_code=EUR&lc=DE&bn=PP-DonationsBF&charset=UTF-8" - sfdonate_url = "https://sourceforge.net/donate/index.php?user_id=560817" - self.tb_abouttext.setHtml(about.arg(lookupDir('pymouldir'), paypal_url, - sfdonate_url)) - def on_moulIsRunning(self, boolean): """ @qtslot moulIsRunning(bool): notify if moul is running @@ -329,7 +304,34 @@ def _about_init(self): self.tb_license.setHtml('<pre style="font-size:7pt;">' + metadata.LICENSE + '</pre>') + about = self.trUtf8(""" +<center> +<h3>Tool for Myst Online : Uru Live</h3> +<p>(c) 2007 Christian Heimes</p> + +<p><a href="http://pymoul.sourceforge.net">http://pymoul.sourceforge.net</a></p> +</center> + +<h4>Bug reporting</h4> +<p align="justify">If you encountered a bug please <a href="http://sourceforge.net/tracker/?group_id=186624&atid=918033l"> +create a bug report</a> with description of your actions along with the log file. You can find the log file at:</p> + +<tt align="center">%1</tt> + +<h4>Donation</h4> +<p align="justify">If you like the tool please consider to <a href="%2">donate</a> some money to sponsor my work. The tool is created in my free time as an open source project. You can sent money to my <a href="%2">PayPal account</a> using your PayPal account, credit card or bank account. You can also use the SourceForget.net <a href="%3">donate page</a>. Your money will be used to found my MOUL account and new hardware for my 4 years old computer.</p> + +<p>sincerely yours<br> +Tiran [KI: #00025784]</p> + """) + paypal_url = "https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=chr...@ch...&item_name=Donate for Tiran's open source activities&page_style=PayPal&no_shipping=0&cn=Your note for me&tax=0¤cy_code=EUR&lc=DE&bn=PP-DonationsBF&charset=UTF-8" + sfdonate_url = "https://sourceforge.net/donate/index.php?user_id=560817" + self.tb_abouttext.setHtml(about.arg( + os.path.join(lookupDir('pymouldir'),'pymoul.log'), + paypal_url, + sfdonate_url)) + # ************************************************************************ # time zones def _timezone_init(self): @@ -340,6 +342,7 @@ self._timezone_update() # create a timer to update the display every second + # TODO: change timer from every second to every minute self._timezone_timer = timer = QtCore.QTimer(self) timer.setInterval(1000) # 1 sec # TODO: needs optimization? run only when timer tab is active Modified: pymoul/trunk/src/moul/qt/moulqt.py =================================================================== --- pymoul/trunk/src/moul/qt/moulqt.py 2007-02-06 15:58:25 UTC (rev 146) +++ pymoul/trunk/src/moul/qt/moulqt.py 2007-02-06 16:48:27 UTC (rev 147) @@ -58,15 +58,15 @@ singleapp = SimpleSingleApp('pymoulqt', path=getPyMoulDataDir(check=True)) try: singleapp.acquire() + createLogfile() except OSError: - mb = criticalMB(app, + mb = criticalMB(None, app.trUtf8("pyMoul QT already running"), app.trUtf8("""An instance of pyMoul QT is already running!""") ) mb.exec_() sys.exit(1) - createLogfile() setupQtExceptHook() installTranslator(app) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |