ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/cmview/branches/CMView-jung/cmview/Start.java
Revision: 249
Committed: Tue Dec 4 15:27:58 2007 UTC (11 years, 2 months ago) by lpetzo
File size: 22875 byte(s)
Log Message:
class Start:
- some changes in function preloadModel(...) due to the new loading scheme for models
- changed default settings for the contact type and the contact distance according to Michael's suggestions

class View:
- adapted new loading scheme for the models
- implemented chain code and model serial Getters for the retrieval of all present chain codes and model serials in the source
Line File contents
1 package cmview;
2 import java.io.*;
3 import java.sql.SQLException;
4 import java.util.Properties;
5 import java.util.TreeMap;
6 import java.util.concurrent.Executors;
7 import java.util.concurrent.ThreadPoolExecutor;
8
9 import javax.swing.JColorChooser;
10 import javax.swing.JFileChooser;
11 import javax.swing.JPanel;
12 import javax.swing.UIManager;
13 import javax.swing.UnsupportedLookAndFeelException;
14
15 import proteinstructure.PdbCodeNotFoundError;
16
17 import tools.MySQLConnection;
18
19 import cmview.datasources.Model;
20 import cmview.datasources.ModelConstructionError;
21 import cmview.datasources.PdbaseModel;
22
23 /**
24 * Main class to start contact map viewer application.
25 * Contains static main function, constants and some helper functions.
26 */
27 public class Start {
28
29 static final long serialVersionUID = 1l;
30
31 // internal constants (not user changeable)
32 public static final String APP_NAME = "CMView"; // name of this application
33 public static final String VERSION = "0.8.5"; // current version of this application (should match manifest)
34 public static final String NULL_CHAIN_CODE = "NULL"; // used by Pdb/Graph objects for the empty pdbChainCode
35 public static final int NO_SEQ_SEP_VAL = -1; // default seq sep value indicating that no seq sep has been specified
36 public static final String NO_SEQ_SEP_STR = "none"; // text output if some seqsep variable equals NO_SEQ_SEP_VAL
37 public static final String RESOURCE_DIR = "/resources/"; // path within the jar archive where resources are located
38 public static final String PYMOL_HOST = "localhost"; // currently, the XMLRPC server in Pymol only supports localhost
39 public static final String PYMOL_PORT = "9123"; // default port, if port is blocked, pymol will increase automatically
40 public static final String PYMOL_SERVER_URL = "http://"+PYMOL_HOST+":"+PYMOL_PORT; // TODO: set this later so that the two above may change
41
42 // The following config file name may be overwritten by a command line switch
43 public static String CONFIG_FILE_NAME = "cmview.cfg"; // default name of config file (can be overridden by cmd line param)
44
45 // The following 'constants' can be overwritten by the user's config file. In the code, they are being used as if they were (final) constants
46 // and the only time when they may change is during startup. Note that for each variable that ought to be user changeable, i.e. read from cfg file
47 // there has to be a line in the applyUserProperties method. The preassigned values are the default and being used unless overwritten by the user.
48 // Additioanlly, values that should appear in the example config file should be added to the getSelectedProperties method.
49
50 // environment
51 public static String TEMP_DIR = System.getProperty("java.io.tmpdir");
52
53 // user customizations
54 public static int INITIAL_SCREEN_SIZE = 800; // initial size of the contactMapPane in pixels
55 public static boolean USE_DATABASE = true; // if false, all functions involving a database will be hidden
56 public static boolean USE_PYMOL = true; // if false, all pymol specific functionality will be hidden
57 public static boolean INCLUDE_GROUP_INTERNALS = true; // this flag shall indicate strongly experimental stuff, use it to disable features in release versions
58 public static boolean PRELOAD_PYMOL = true; // if true, pymol is preloaded on startup
59 public static boolean SHUTDOWN_PYMOL_ON_EXIT = true; // if true, pymol is shutdown on exit
60
61 public static boolean SHOW_RULERS_ON_STARTUP = true; // if true, rulers will be shown by default
62 public static boolean FORCE_DSSP = false; // if true, secondary structure will be always taken from DSSP (if available)
63 public static String DSSP_EXECUTABLE = "/project/StruPPi/Software/dssp/dsspcmbi";
64 public static String DSSP_PARAMETERS = "--";
65 public static String PDB_FTP_URL = "ftp://ftp.wwpdb.org/pub/pdb/data/structures/all/mmCIF/";
66
67 // constants not in config file yet
68 public static String DIST_MAP_CONTACT_TYPE = "Ca"; // contact type to be used for distance map calculation (only single atom allowed)
69 public static boolean SHOW_ICON_BAR = true; // if true, icon bar is used
70 public static boolean ICON_BAR_FLOATABLE = false; // if true, icon bar can be dragged out of the window (buggy, don't use)
71
72 // pymol connection
73 public static String PYMOL_EXECUTABLE = "/project/StruPPi/bin/pymol-1.0"; // to start pymol automatically
74 public static String PYMOL_PARAMETERS = "-R -q"; // run xmlrpc server and skip splash screen
75 public static long PYMOL_CONN_TIMEOUT = 15000; // pymol connection time out in milliseconds
76
77 // database connection
78 public static String DB_HOST = "white"; // TODO: change to dummy name
79 public static String DB_USER = getUserName(); // guess user name
80 public static String DB_PWD = "nieve"; // TODO: change to tiger
81
82 // default values for loading contact maps
83 public static String DEFAULT_GRAPH_DB = "pdb_reps_graph"; // shown in load from graph db dialog
84 public static String DEFAULT_PDB_DB = "pdbase"; // for loading from command line
85 public static String DEFAULT_MSDSD_DB = "msdsd_00_07_a"; // used when loading structures for cm file graphs
86 public static String DEFAULT_CONTACT_TYPE = "Ca"; // loading from command line and shown in LoadDialog
87 public static double DEFAULT_DISTANCE_CUTOFF = 8.0; // dito
88 private static final int DEFAULT_MIN_SEQSEP = NO_SEQ_SEP_VAL; // dito, but not user changeable at the moment
89 private static final int DEFAULT_MAX_SEQSEP = NO_SEQ_SEP_VAL; // dito, but not user changeable at the moment
90
91 // internal status variables
92 protected static boolean database_found = true;
93 protected static boolean pymol_found = true;
94 protected static boolean dssp_found = true; // check later whether dssp can be used
95 protected static Properties userProperties; // properties read from the user's config file
96 protected static Properties selectedProperties; // selected default properties for the example config file
97
98 // global session variables (use getter methods)
99 private static MySQLConnection conn;
100 private static JFileChooser fileChooser;
101 private static JColorChooser colorChooser;
102 private static PyMolAdaptor pymolAdaptor;
103
104 // the thread pool
105 public static ThreadPoolExecutor threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool();
106
107 // mapping pdb-code to mmCIF files in the tmp-directory
108 private static TreeMap<String, String> pdbCode2file = new TreeMap<String, String>();
109
110 /**
111 * Gets the filename of the local copy of the structure file corresponding
112 * to the given pdb code.
113 * @param pdbCode pdb code
114 * @return path to the file of the given pdb code. Returns null if there
115 * is no such file.
116 */
117 public static String getFilename2PdbCode(String pdbCode) {
118 return pdbCode2file.get(pdbCode.toLowerCase());
119 }
120
121 /**
122 * Sets the name of the local copy of the structure file corresponding to
123 * the given pdb code.
124 * @param pdbCode pdb code
125 * @param filename name of the file corresponding to <code>pdbCode</code>
126 */
127 public static void setFilename2PdbCode(String pdbCode, String filename) {
128 pdbCode2file.put(pdbCode, filename);
129 }
130
131 /**
132 * Get user name from operating system (for use as database username).
133 * */
134 private static String getUserName() {
135 String user = null;
136 user = System.getProperty("user.name");
137 if(user == null) {
138 System.err.println("Could not get user name from operating system.");
139 }
140 return user;
141 }
142
143 /**
144 * Returns a property object with the default values for selected customizable variables.
145 * These are the variables that we expect users to commonly change. They are written
146 * when the users selects the 'write example config file' from the Help menu.
147 * Other possible customizable variables should be mentioned somewhere in the manual.
148 */
149 private static Properties getSelectedProperties() {
150
151 Properties d = new Properties();
152
153 // properties which the user will have to change
154 d.setProperty("PYMOL_EXECUTABLE",PYMOL_EXECUTABLE);
155 d.setProperty("DB_HOST",DB_HOST);
156 d.setProperty("DB_USER",DB_USER);
157 d.setProperty("DB_PWD",DB_PWD);
158
159 // properties which the user may want to change
160 d.setProperty("INITIAL_SCREEN_SIZE",new Integer(INITIAL_SCREEN_SIZE).toString());
161 d.setProperty("USE_DATABASE",new Boolean(USE_DATABASE).toString());
162 d.setProperty("USE_PYMOL",new Boolean(USE_PYMOL).toString());
163 d.setProperty("PRELOAD_PYMOL",new Boolean(PRELOAD_PYMOL).toString());
164 d.setProperty("SHUTDOWN_PYMOL_ON_EXIT",new Boolean(SHUTDOWN_PYMOL_ON_EXIT).toString());
165 d.setProperty("DEFAULT_CONTACT_TYPE",DEFAULT_CONTACT_TYPE);
166 d.setProperty("DEFAULT_DISTANCE_CUTOFF",new Double(DEFAULT_DISTANCE_CUTOFF).toString());
167 d.setProperty("DSSP_EXECUTABLE", DSSP_EXECUTABLE);
168 d.setProperty("FORCE_DSSP", new Boolean(FORCE_DSSP).toString());
169 d.setProperty("SHOW_RULERS_ON_STARTUP", new Boolean(SHOW_RULERS_ON_STARTUP).toString());
170
171 // properties which will become obsolete when loading from online pdb is implemented
172 d.setProperty("DEFAULT_PDB_DB",DEFAULT_PDB_DB);
173 d.setProperty("DEFAULT_GRAPH_DB", DEFAULT_GRAPH_DB);
174 d.setProperty("DEFAULT_MSDSD_DB",DEFAULT_MSDSD_DB);
175
176 // properties that should be changed only if problems arise
177 // these will be mentioned in the documentation somewhere but not in the example config file
178 //d.setProperty("TEMP_DIR",TEMP_DIR);
179 //d.setProperty("PYMOL_PARAMETERS",PYMOL_PARAMETERS);
180 //d.setProperty("PYMOL_CONN_TIMEOUT",new Long(PYMOL_CONN_TIMEOUT).toString());
181 //d.setProperty("DSSP_PARAMETERS", DSSP_PARAMETERS);
182
183 return d;
184 }
185
186 /**
187 * Loads user properties from the given configuration file.
188 * Returns null on failure;
189 * @throws IOException
190 * @throws FileNotFoundException
191 */
192 private static Properties loadUserProperties(String fileName) throws FileNotFoundException, IOException {
193 Properties p = new Properties();
194 p.load(new FileInputStream(fileName));
195 return p;
196 }
197
198 /**
199 * Overwrite the local constants with the values from the given properties object
200 */
201 private static void applyUserProperties(Properties p) {
202
203 // The logic here is: First, take the value from the user config file,
204 // if that is not found, keep the variable value unchanged.
205 // Note that any value in the user config file that is not being processed here is ignored.
206
207 TEMP_DIR = p.getProperty("TEMP_DIR",TEMP_DIR);
208 INITIAL_SCREEN_SIZE = Integer.valueOf(p.getProperty("INITIAL_SCREEN_SIZE", new Integer(INITIAL_SCREEN_SIZE).toString()));
209 USE_DATABASE = Boolean.valueOf(p.getProperty("USE_DATABASE", new Boolean(USE_DATABASE).toString()));
210 USE_PYMOL = Boolean.valueOf(p.getProperty("USE_PYMOL", new Boolean(USE_PYMOL).toString()));
211 PRELOAD_PYMOL = Boolean.valueOf(p.getProperty("PRELOAD_PYMOL", new Boolean(PRELOAD_PYMOL).toString()));
212 SHUTDOWN_PYMOL_ON_EXIT = Boolean.valueOf(p.getProperty("SHUTDOWN_PYMOL_ON_EXIT", new Boolean(SHUTDOWN_PYMOL_ON_EXIT).toString()));
213 SHOW_RULERS_ON_STARTUP = Boolean.valueOf(p.getProperty("SHOW_RULERS_ON_STARTUP", new Boolean(SHOW_RULERS_ON_STARTUP).toString()));
214
215 PYMOL_PARAMETERS = p.getProperty("PYMOL_PARAMETERS", PYMOL_PARAMETERS);
216 PYMOL_EXECUTABLE = p.getProperty("PYMOL_EXECUTABLE", PYMOL_EXECUTABLE);
217 PYMOL_CONN_TIMEOUT = Long.valueOf(p.getProperty("PYMOL_CONN_TIMEOUT",new Long(PYMOL_CONN_TIMEOUT).toString()));
218
219 DSSP_EXECUTABLE = p.getProperty("DSSP_EXECUTABLE",DSSP_EXECUTABLE);
220 DSSP_PARAMETERS = p.getProperty("DSSP_PARAMETERS",DSSP_PARAMETERS);
221 FORCE_DSSP = Boolean.valueOf(p.getProperty("FORCE_DSSP", new Boolean(FORCE_DSSP).toString()));
222
223 DB_HOST = p.getProperty("DB_HOST", DB_HOST);
224 DB_USER = p.getProperty("DB_USER", DB_USER);
225 DB_PWD = p.getProperty("DB_PWD", DB_PWD);
226
227 DEFAULT_PDB_DB = p.getProperty("DEFAULT_PDB_DB", DEFAULT_PDB_DB);
228 DEFAULT_CONTACT_TYPE = p.getProperty("DEFAULT_CONTACT_TYPE", DEFAULT_CONTACT_TYPE);
229 DEFAULT_DISTANCE_CUTOFF = Double.valueOf(p.getProperty("DEFAULT_DISTANCE_CUTOFF", new Double(DEFAULT_DISTANCE_CUTOFF).toString()));
230
231 DEFAULT_GRAPH_DB = p.getProperty("DEFAULT_GRAPH_DB", DEFAULT_GRAPH_DB);
232 DEFAULT_MSDSD_DB = p.getProperty("DEFAULT_MSDSD_DB", DEFAULT_MSDSD_DB);
233
234 }
235
236 /**
237 * Copy external resources (data files and executables) from the jar archive to a temp directory.
238 * The files are marked to be deleted on exit. Use getResourcePath() to access resources later.
239 * */
240 private static void unpackResources() {
241 unpackResource(PyMolAdaptor.PYMOLFUNCTIONS_SCRIPT);
242 }
243
244 /**
245 * Copy the resource file 'resource' from the resource dir in the jar file to the temp directory.
246 * The resource will be marked as to be deleted. Use getResourcePath() to access resource later.
247 */
248 private static void unpackResource(String resource) {
249
250 String source = RESOURCE_DIR + resource;
251 File target = new File(TEMP_DIR, resource);
252
253 try{
254 try {
255 target.createNewFile();
256 } catch (IOException e) {
257 System.err.println("Failed to create file " + target);
258 throw e;
259 }
260
261 InputStream inp = Runtime.getRuntime().getClass().getResourceAsStream(source);
262 BufferedInputStream in = new BufferedInputStream(inp);
263 FileOutputStream out = new FileOutputStream(target);
264
265 try {
266 int ch;
267 while((ch = in.read()) != -1)
268 out.write(ch);
269 in.close();
270 out.close();
271 } catch (IOException e) {
272 System.err.println("Failed to read from " + source);
273 throw e;
274 }
275 }
276 catch(IOException e) {
277 System.err.println("Severe error: Failed to create resource " + target);
278 }
279 finally {
280 target.deleteOnExit();
281 }
282
283 }
284
285 /**
286 * Return the absolute path to the unpacked resource with the given name.
287 * Will always return a file object but the resource may not exists unless
288 * it has been created with unpackResource() previously.
289 */
290 protected static String getResourcePath(String resource) {
291 return new File(TEMP_DIR, resource).getAbsolutePath();
292 }
293
294 /**
295 * Set native OSlook and feel (is possible).
296 */
297 private static void setLookAndFeel() {
298 try {
299 // Set System L&F
300 UIManager.setLookAndFeel(
301 //looks[2].getClassName());
302 UIManager.getSystemLookAndFeelClassName());
303 }
304 catch (UnsupportedLookAndFeelException e) {
305 System.out.println(e);
306 }
307 catch (ClassNotFoundException e) {
308 System.out.println(e); // handle exception
309 }
310 catch (InstantiationException e) {
311 System.out.println(e); // handle exception
312 }
313 catch (IllegalAccessException e) {
314 System.out.println(e); // handle exception
315 }
316 }
317
318 /**
319 * Runs external pymol executable if possible. Return true on success, false otherwise.
320 */
321 private static boolean runPymol() {
322 try {
323 System.out.println("Starting PyMol...");
324 File f = new File(PYMOL_EXECUTABLE);
325 if(!f.exists()) {
326 System.err.println(PYMOL_EXECUTABLE + " does not exist.");
327 // try to start pymol anyways because on Mac f.exists() returns false even though the file is there
328 }
329 Runtime.getRuntime().exec(f.getCanonicalPath() + " " + PYMOL_PARAMETERS);
330 } catch(IOException e) {
331 return false;
332 }
333 return true;
334 }
335
336 /**
337 * Try connecting to the database server. Returns true on success, false otherwise.
338 */
339 private static boolean tryConnectingToDb() {
340 try {
341 conn = new MySQLConnection(DB_HOST, DB_USER, DB_PWD);
342 }
343 catch(Exception e) {
344 return false;
345 }
346 return true;
347 }
348
349 /**
350 * Preload a model based on the command line parameters.
351 * Returns the model or null on failure.
352 * TODO: Do proper command line parsing with switches to preload files or structures from online pdb
353 */
354 private static Model preloadModel(String[] args) {
355 Model mod = null;
356 // parameters should be pdb code and chain code
357 if(USE_DATABASE && database_found) {
358 String pdbCode = args[0];
359 String chainCode;
360 if(args.length > 1) {
361 chainCode = args[1];
362 } else {
363 chainCode = NULL_CHAIN_CODE;
364 }
365 try {
366 mod = new PdbaseModel(pdbCode, DEFAULT_CONTACT_TYPE, DEFAULT_DISTANCE_CUTOFF, DEFAULT_MIN_SEQSEP, DEFAULT_MAX_SEQSEP, DEFAULT_PDB_DB);
367 mod.load(chainCode, 1);
368 } catch(ModelConstructionError e) {
369 System.err.println("Could not load structure for given command line parameters:");
370 System.err.println(e.getMessage());
371 } catch (PdbCodeNotFoundError e) {
372 System.err.println("Could not load structure for given command line parameters:");
373 System.err.println(e.getMessage());
374 } catch (SQLException e) {
375 System.err.println("Could not load structure for given command line parameters:");
376 System.err.println(e.getMessage());
377 }
378 } else {
379 System.err.println("No database. Ignoring command line parameters.");
380 }
381 return mod;
382 }
383
384 /**
385 * Returns true iff the given path is a directory which is writable.
386 */
387 private static boolean isWritableDir(String path) {
388 File f = new File(path);
389 if(!f.isDirectory()) return false;
390 if(!f.canWrite()) return false;
391 return true;
392 }
393
394 /*---------------------------- public methods ---------------------------*/
395
396 /**
397 * Writes an example configuration file with the default values for selected user
398 * customizable variables. The file will be written in the current directory.
399 * The values are taken from the variable selectedProperties which has to be
400 * initialized previously using getSelectedProperties().
401 * @throws IOException
402 * @throws FileNotFoundException
403 */
404 public static void writeExampleConfigFile(String fileName) throws FileNotFoundException, IOException {
405 Properties d = selectedProperties;
406 String comment = "Properties file for " + APP_NAME + " " + VERSION;
407 d.store(new FileOutputStream(fileName), comment);
408 }
409
410 /**
411 * Returns true if a database connection is expected to be available. This is to avoid
412 * trying to connect when it is clear that the trial will fail.
413 */
414 public static boolean isDatabaseConnectionAvailable() {
415 return Start.USE_DATABASE && Start.database_found;
416 }
417
418 /**
419 * Returns true if a connection to pymol is expected to be available. This is to avoid
420 * trying to connect when it is clear that the trial will fail.
421 */
422 public static boolean isPyMolConnectionAvailable() {
423 return Start.USE_PYMOL && Start.pymol_found;
424 }
425
426 /**
427 * Returns true if external dssp application is available.
428 */
429 public static boolean isDsspAvailable() {
430 return dssp_found;
431 }
432
433 /**
434 * Return the global db connection for this session.
435 * @return The MySQLConnection object
436 */
437 public static MySQLConnection getDbConnection() {
438 return conn;
439 }
440
441 /**
442 * Return the global fileChooser for this session.
443 * @return A JFileChooser to be used whenever possible.
444 */
445 public static JFileChooser getFileChooser() {
446 return fileChooser;
447 }
448
449 /**
450 * Return the global colorChooser for this session.
451 * @return A JColorChooser to be used whenever possible.
452 */
453 public static JColorChooser getColorChooser() {
454 return colorChooser;
455 }
456
457 /**
458 * Return the global pymolAdaptor of this session.
459 * @return The PyMolAdaptor object
460 */
461 public static PyMolAdaptor getPyMolAdaptor() {
462 return pymolAdaptor;
463 }
464
465
466 /**
467 * Main method to start CMView application
468 * @param args command line arguments
469 */
470 public static void main(String args[]){
471
472 System.out.println("Starting " + APP_NAME + " " + VERSION + " - Interactive contact map viewer");
473
474 // TODO: check whether config file is passed as command line parameter, otherwise use default one
475
476 // load configuration
477 selectedProperties = getSelectedProperties();
478 try {
479 Properties p = loadUserProperties(CONFIG_FILE_NAME);
480 System.out.println("Loading configuration file " + CONFIG_FILE_NAME);
481 userProperties = p;
482 applyUserProperties(userProperties);
483 } catch (FileNotFoundException e) {
484 System.out.println("No configuration file found. Using default settings.");
485 } catch (IOException e) {
486 System.err.println("Error while reading from file " + CONFIG_FILE_NAME + ". Using default settings.");
487 }
488
489 // TODO: apply command line arguments here
490
491 // add shutdown hook
492 Runtime.getRuntime().addShutdownHook(new Thread() {
493 public void run() {
494 System.out.println("Shutting down");
495 if(isPyMolConnectionAvailable() && SHUTDOWN_PYMOL_ON_EXIT) {
496 pymolAdaptor.shutdown(PYMOL_SERVER_URL);
497 }
498 }
499 });
500
501 // check temp directory
502 System.out.println("Using temporary directory " + TEMP_DIR);
503 if(isWritableDir(TEMP_DIR)) {
504 unpackResources();
505 } else {
506 System.err.println("Error: Can not write to temporary directory. Some features may not function correctly.");
507 }
508
509 // connect to pymol
510 if(USE_PYMOL) {
511 pymolAdaptor = new PyMolAdaptor(PYMOL_SERVER_URL);
512 if(pymolAdaptor.tryConnectingToPymol(100) == true) { // running pymol server found
513 System.out.println("PyMol server found. Connected.");
514 pymol_found = true;
515 } else {
516 if(PRELOAD_PYMOL) {
517 if(runPymol() == false) {
518 //System.err.println("Warning: Failed to start PyMol automatically. Please manually start Pymol with the -R parameter.");
519 System.err.println("Failed. (You can try to restart this application after manually starting pymol with the -R parameter)");
520 pymol_found = false;
521 } else {
522 System.out.println("Connecting to PyMol server...");
523 if(pymolAdaptor.tryConnectingToPymol(PYMOL_CONN_TIMEOUT) == false) {
524 System.err.println("Failed. (You can try to restart this application after manually starting pymol with the -R parameter)");
525 pymol_found = false;
526 } else {
527 System.out.println("Connected.");
528 pymol_found = true;
529 }
530 }
531 }
532 }
533 if(!pymol_found) {
534 System.err.println("Could not connect to PyMol server. Some functionality will not be available.");
535 }
536 }
537
538 // connect to database
539 if(USE_DATABASE) {
540 System.out.println("Connecting to database...");
541 if(tryConnectingToDb() == false) {
542 System.err.println("No database found. Some functionality will not be available.");
543 database_found = false;
544 } else {
545 System.out.println("Connected.");
546 database_found = true;
547 }
548 }
549
550 setLookAndFeel();
551
552 // initialize session variables
553 fileChooser = new JFileChooser();
554 colorChooser = new JColorChooser();
555 colorChooser.setPreviewPanel(new JPanel()); // removing the preview panel
556
557 // start gui without a model or preload contact map based on command line parameters
558 String wintitle = "Contact Map Viewer";
559 Model mod = null;
560 View view = new View(mod, wintitle);
561 if (args.length>=1){
562 mod = preloadModel(args);
563 if(mod != null) {
564 view.spawnNewViewWindow(mod);
565 }
566 }
567 }
568 }