1#!/usr/bin/env python3 2# -*- Coding: UTF-8 -*- 3 4# --------------------------------------------------------------------------- 5# Open Asset Import Library (ASSIMP) 6# --------------------------------------------------------------------------- 7# 8# Copyright (c) 2006-2020, ASSIMP Development Team 9# 10# All rights reserved. 11# 12# Redistribution and use of this software in source and binary forms, 13# with or without modification, are permitted provided that the following 14# conditions are met: 15# 16# * Redistributions of source code must retain the above 17# copyright notice, this list of conditions and the 18# following disclaimer. 19# 20# * Redistributions in binary form must reproduce the above 21# copyright notice, this list of conditions and the 22# following disclaimer in the documentation and/or other 23# materials provided with the distribution. 24# 25# * Neither the name of the ASSIMP team, nor the names of its 26# contributors may be used to endorse or promote products 27# derived from this software without specific prior 28# written permission of the ASSIMP Development Team. 29# 30# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41# --------------------------------------------------------------------------- 42from tkinter import * 43import sys 44import os 45import platform 46import run 47import subprocess 48import result_checker as rc 49 50INFO = 0 51WARN = 1 52ERROR = 2 53 54# ------------------------------------------------------------------------------- 55def log( sev, msg ): 56 """ 57 This function is used to log info, warnings and errors. 58 """ 59 logEntry = "" 60 if sev == 0: 61 logEntry = logEntry + "[INFO]: " 62 elif sev == 1: 63 logEntry = logEntry + "[WARN]: " 64 elif sev == 2: 65 logEntry = logEntry + "[ERR] : " 66 logEntry = logEntry + str( msg ) 67 print( logEntry ) 68 69# ------------------------------------------------------------------------------- 70class BaseDialog( Toplevel ): 71 """ 72 Helper base class for dialogs used in the UI. 73 """ 74 75 def __init__(self, parent, title = None, buttons=""): 76 """ 77 Constructor 78 """ 79 Toplevel.__init__( self, parent ) 80 self.transient(parent) 81 82 if title: 83 self.title(title) 84 85 self.parent = parent 86 self.result = None 87 body = Frame(self) 88 self.initial_focus = self.body(body) 89 body.pack(padx=5, pady=5) 90 self.buttonbox(buttons) 91 self.grab_set() 92 if not self.initial_focus: 93 self.initial_focus = self 94 self.protocol("WM_DELETE_WINDOW", self.cancel) 95 self.geometry("+%d+%d" % (parent.winfo_rootx() + 50, 96 parent.winfo_rooty() + 50)) 97 self.initial_focus.focus_set() 98 self.wait_window(self) 99 100 def body(self, master): 101 # create dialog body. return widget that should have 102 # initial focus. this method should be overridden 103 pass 104 105 def buttonbox(self, buttons): 106 # add standard button box. override if you don't want the 107 # standard buttons 108 box = Frame(self) 109 w = Button(box, text="OK", width=40, command=self.ok, default=ACTIVE) 110 w.pack(side=LEFT, padx=5, pady=5) 111 self.bind("<Return>", self.ok) 112 box.pack() 113 114 def ok(self, event=None): 115 if not self.validate(): 116 self.initial_focus.focus_set() # put focus back 117 return 118 119 self.withdraw() 120 self.update_idletasks() 121 self.apply() 122 self.cancel() 123 124 def cancel(self, event=None): 125 # put focus back to the parent window 126 self.parent.focus_set() 127 self.destroy() 128 129 def validate(self): 130 return 1 # override 131 132 def apply(self): 133 pass # override 134 135# ------------------------------------------------------------------------------- 136class VersionDialog( BaseDialog ): 137 """ 138 This class is used to create the info dialog. 139 """ 140 def body(self, master): 141 # info will be read from assimp command line tool 142 version = "Asset importer lib version unknown" 143 exe = run.getEnvVar( "assimp_path" ) 144 if len( exe ) != 0: 145 command = [exe, "version" ] 146 log( INFO, "command = " + str(command)) 147 stdout = subprocess.check_output(command) 148 for line in stdout.splitlines(): 149 pos = str(line).find( "Version" ) 150 if -1 != pos: 151 version = line 152 Label(master, text=version).pack() 153 154 def apply(self): 155 pass 156 157# ------------------------------------------------------------------------------- 158class SetupDialog( BaseDialog ): 159 """ 160 This class is used to create the setup dialog. 161 """ 162 def body(self, master): 163 Label(master, justify=LEFT, text="Assimp: " ).grid(row=0, column=0) 164 Label(master, justify=LEFT, text=run.getEnvVar("assimp_path")).grid(row=0, column=1) 165 Label(master, text="New executable:").grid(row=1) 166 self.e1 = Entry(master) 167 self.e1.grid(row=1, column=1) 168 return self.e1 # initial focus 169 170 def apply(self): 171 exe = str( self.e1.get() ) 172 if len( exe ) == 0: 173 return 0 174 if os.path.isfile( exe ): 175 log( INFO, "Set executable at " + exe) 176 self.assimp_bin_path = exe 177 run.setEnvVar("assimp_path", self.assimp_bin_path) 178 else: 179 log( ERROR, "Executable not found at "+exe ) 180 return 0 181 182# ------------------------------------------------------------------------------- 183class RegDialog( object ): 184 """ 185 This class is used to create a simplified user interface for running the regression test suite. 186 """ 187 188 def __init__(self, bin_path ): 189 """ 190 Constructs the dialog, you can define which executable shal be used. 191 @param bin_path [in] Path to assimp binary. 192 """ 193 run.setEnvVar( "assimp_path", bin_path ) 194 self.b_run_ = None 195 self.b_update_ = None 196 self.b_res_checker_ = None 197 self.b_quit_ = None 198 if platform.system() == "Windows": 199 self.editor = "notepad" 200 elif platform.system() == "Linux": 201 self.editor = "vim" 202 self.root = None 203 self.width=40 204 205 def run_reg(self): 206 log(INFO, "Starting regression test suite.") 207 run.run_test() 208 rc.run() 209 self.b_update_.config( state=ACTIVE ) 210 return 0 211 212 def reg_update(self): 213 assimp_exe = run.getEnvVar( "assimp_path" ) 214 if len( assimp_exe ) == 0: 215 return 1 216 exe = "python" 217 command = [ exe, "gen_db.py", assimp_exe ] 218 log(INFO, "command = " + str(command)) 219 stdout = subprocess.call(command) 220 221 log(INFO, stdout) 222 return 0 223 224 def shop_diff( self ): 225 log(WARN, "ToDo!") 226 return 0 227 228 def open_log(self): 229 command = [ self.editor, "../results/run_regression_suite_output.txt", ] 230 log(INFO, "command = " + str( command ) ) 231 r = subprocess.call(command) 232 return 0 233 234 def show_version( self ): 235 d = VersionDialog( self.root ) 236 return 0 237 238 def setup(self): 239 d = SetupDialog( self.root ) 240 return 0 241 242 def quit(self): 243 log( INFO, "quit" ) 244 sys.exit( 0 ) 245 246 def initUi(self): 247 # create the frame with buttons 248 self.root = Tk() 249 self.root.title( "Assimp-Regression UI") 250 self.b_run_ = Button( self.root, text="Run regression ", command=self.run_reg, width = self.width ) 251 self.b_update_ = Button( self.root, text="Update database", command=self.reg_update, width = self.width ) 252 self.b_show_diff_ = Button( self.root, text="Show diff", command=self.shop_diff, width = self.width ) 253 self.b_log_ = Button( self.root, text="Open log", command=self.open_log, width = self.width ) 254 self.b_setup_ = Button( self.root, text="Setup", command=self.setup, width = self.width ) 255 self.b_version_ = Button( self.root, text="Show version", command=self.show_version, width = self.width ) 256 self.b_quit_ = Button( self.root, text="Quit", command=self.quit, width = self.width ) 257 258 # define the used grid 259 self.b_run_.grid( row=0, column=0, sticky=W+E ) 260 self.b_update_.grid( row=1, column=0, sticky=W+E ) 261 self.b_show_diff_.grid( row=2, column=0, sticky=W+E ) 262 self.b_log_.grid( row=3, column=0, sticky=W+E ) 263 self.b_setup_.grid( row=4, column=0, sticky=W+E ) 264 self.b_version_.grid( row=5, column=0, sticky=W+E ) 265 self.b_quit_.grid( row=6, column=0, sticky=W+E ) 266 267 #self.b_update_.config( state=DISABLED ) 268 self.b_show_diff_.config( state=DISABLED ) 269 270 # run mainloop 271 self.root.mainloop() 272 273# ------------------------------------------------------------------------------- 274def getDefaultExecutable(): 275 assimp_bin_path = "" 276 if platform.system() == "Windows": 277 assimp_bin_path = '..\\..\\bin\\debug\\assimpd.exe' 278 elif platform.system() == "Linux": 279 assimp_bin_path = '../../bin/assimp' 280 281 return assimp_bin_path 282 283# ------------------------------------------------------------------------------- 284if __name__ == "__main__": 285 if len(sys.argv) > 1: 286 assimp_bin_path = sys.argv[1] 287 else: 288 assimp_bin_path = getDefaultExecutable() 289 log( INFO, 'Using assimp binary: ' + assimp_bin_path ) 290 dlg = RegDialog(assimp_bin_path) 291 dlg.initUi() 292 293# vim: ai ts=4 sts=4 et sw=4 294