-
Notifications
You must be signed in to change notification settings - Fork 27
/
MesquiteModule.java
2755 lines (2611 loc) · 127 KB
/
MesquiteModule.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Mesquite source code. Copyright 1997 and onward, W. Maddison and D. Maddison.
Disclaimer: The Mesquite source code is lengthy and we are few. There are no doubt inefficiencies and goofs in this code.
The commenting leaves much to be desired. Please approach this source code with the spirit of helping out.
Perhaps with your help we can be more than a few, and make Mesquite better.
Mesquite is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
Mesquite's web site is http://mesquiteproject.org
This source code and its compiled class files are free and modifiable under the terms of
GNU Lesser General Public License. (http://www.gnu.org/copyleft/lesser.html)
*/
package mesquite.lib;
import java.awt.*;
import java.util.*;
import java.util.List;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.lang.StringEscapeUtils;
import mesquite.lib.duties.*;
import mesquite.tol.lib.BaseHttpRequestMaker;
import edu.stanford.ejalbert.*; //for Browserlauncher
/* ============================Class MesquiteModule============================================ */
/** The Mesquite system operates around a tree of modules (subclasses of MesquiteModule), with the class containing the "main" method being
the <strong>trunk</strong> module, and the other modules like branches that are attached to the trunk.<p>
When Mesquite starts up, the trunk starts up and surveys the mesquite folder to acquire information about all of the available modules
(i.e., all of the available subclasses of MesquiteModule). To be found, a module must be in a folder (directory) of the same name as itself; that is,
a module whose class file is "MyModule.class" must be in a directory named "MyModule". Mesquite remembers the modules in a vector of MesquiteModuleInfo objects.
Later, when modules need to be "hired" to perform certain tasks, this vector of information can be used to help choose which module to hire. To be hired, a module is instantiated
and linked to its employer module. Thus, a new branch sprouts in the Mesquite bureaucratic hierarchy.
<p>
Modules are chosen for hire by other modules according to their talents. What talents a module has is implicit in its superclass. For instance, a module
that subclasses the NumberForTree class (itself a subclass of MesquiteModule) calculates a number for a tree. Any module that
wants numbers calculated for trees can therefore hire a module that is an instance of the NumberForTree class.
The basic talent-defining classes are part of the Mesquite Class LIbrary, in the subpackage duties. There is in addition a system to determine whether a
module is compatible with a particular condition (e.g. operating on continuous-valued data.)<p>
The only types of module that the trunk knows of directly are the FileCoordinator and FileInterpreter classes. Each instance
of the File Coordinator is associated with one file, and it is responsible for using employee modules to
read and write the file, and to hire tree windows and data windows. The trunk is a specific subclass of MesquiteModule,
a MesquiteTrunk<p>
Because menus are composed hierarchically along the employee tree, menu composition is most easily done where there is easy access to
employee-employer relations. For this reason, it is most convenient to have the menu composition embedded within the module code. In order not to
burden the MesquiteModule class with numerous methods to handle employee-employer relations, the MesquiteModule class was split into three: its superclass,
EmployeeEmployer (which handles employee-employer relations), MenuOwner (which handles all menu issues) and MesquiteModule itself, which handles its basic functions.
EmployeeEmployer and MenuOwner are intended to be used ONLY as superclasses to MesquiteModule<p>
The MesquiteModule class is more or less equivalent to the MacClade proto4 ModuleRecord, while its instantiated objects
are more or less equivalent to the MacClade proto4 Tasks. Hence, "task" is sometimes used in names for
MesquiteModule objects.<p>
*/
public abstract class MesquiteModule extends EmployerEmployee implements Commandable, Showable, Logger, FunctionExplainable, Identifiable, FileDirtier, MesquiteListener, XMLPreferencesProcessor {
/*.................................................................................................................*/
/** returns build date of the Mesquite system (e.g., "22 September 2003") */
public final static String getBuildDate() {
return "21 September 2017";
}
/*.................................................................................................................*/
/** returns version of the Mesquite system */
public final static String getMesquiteVersion() {
return "3.31";
}
/*.................................................................................................................*/
/** returns letter in the build number of the Mesquite system (e.g., "e" of "e58") */
public final static String getBuildLetter() {
//see comment under getBuildNumber
return "";
}
/*.................................................................................................................*/
/** returns number in the build number of the Mesquite system (e.g., 58 of "e58") */
public final static int getBuildNumber() {
//as of 26 Dec 08, build naming changed from letter + number to just number. Accordingly j105 became 473, based on
// highest build numbers of d51+e81+g97+h66+i69+j105 + 3 for a, b, c
return 859;
}
//0.95.80 14 Mar 01 - first beta release
//0.96 2 April 01 beta - second beta release
//0.97 30 May 01 - not a release version
//0.98 24 July 01 0.98
//0.99 released 21 Aug 02 hits at posting: 12860 home page; 3251 download; 466 source
//0.991 = d21 released 14 Sep 02 hits at posting: 13599 home page; 3460 download; 502 source
//0.992 = d24 released 27 Sep 02 approximate hits at posting: 14171 home page; 3590 download; 525 source
//0.993 = d42 released 10 Jan 03 approximate hits at posting: 16122 home page; 4458 download; 671 source
//0.994 = d51 released 7 Feb 03 approximate hits at posting: 16790 home page; 4831 download; 720 source
//0.995 = e23 released 21 May 03 approximate hits at posting: 19389 home page; 6088 download; 898 source
//0.996 = e30 released 21 June 03 approximate hits at posting: 20028 home page; 6349 download; 958 source
//1.0 = e58 released 22 September 03 approximate hits at posting: 21315 home page; 6880 download; 1087 source
//1.01 = e80 released 14 January 04 approximate hits at posting: 25636 home page; 8753 download; 1359 source
// = e81 released 17 January 04 minor change to MesquiteTable to prevent problem with autoSizeColumns under Windows
//1.02 = g6 released 6 May 04 approximate hits at posting: 28719 home page; 10170 download; 1574 source
// = g7 released 12 May 04 minor change to fix cosmetic bug
//1.03 = g19 released 1 July 04 approximate hits at posting: 30058 home page; 10803 download; 1685 source
//1.04 = g21 released 1 September 04 approximate hits at posting: 31636 home page; 11462 download; 1806 source
//1.05 = g24 released 29 September 04 approximate hits at posting: 32502 home page; 11827 download; 1864 source
//1.06 = g97 released 30 August 05 approximate hits at posting: 44106 home page; 16865 download; 2478 source
//1.1 = h60 released 18 May 06 approximate hits at posting: 56303 home page; 22012 download; 3168 source
//24may just before evoldir announcement 56781/22266/3209
//1.11 = h64 released 21 June 06 approximate hits 58671/ 23167/3319
//1.12 = h66 released 23 September 06
//2.0 = i68 released 21 September 07 80089 / 31816 / 4666; i69 released 24 Sept to fix java 1.4 ExtensibleDialog setCaretPosition crash
//2.01 = j27 released 7 December 07 85399/ 34315 / 4910; j28 released 7 December 07 to fix coalescence counting bug
//2.5 = j77 released 9 June 08 95129/ 38754 / 5526
//2.6 = 486 released 24 January 09 107577/ 45169 / 6123
//2.7 = 510 released 26 August 09 121070/ 52820 / 6830
//2.71 = 514 released 7 Sept 09 121886/ 53466 / 6867
//2.72 = 527 released 11 Dec 09 129448/ 58128 / 7207; 528 released 20 Dec 09 to fix non-substantive bugs
//2.73 = 544 released 25 July 10 144981 / 67206 / 7817
//2.74 = 550 released 3 October 10 150117 / 71997 / 7980
//2.75 = 564 released 30 September 2011 179839 / 91129 / 8939
// = 565 included 4 October 2011 in Chromaseq release; slight changes to UndoInstructions for Chromaseq
// = 566 update 10 October 2011, small fix in this module to re-enable error reporting of NullPointerExceptions and ArrayIndexOutOfBoundsExceptions
//3.00 = 644 released 29 Aug 2014; 645 released 4 Sept 2014
//3.01 = 658 released 19 Sep 2014
//3.02 = 681 released 6 January 2015
//3.03 = 702 released 31 March 2015
//3.04 = 725 released 16 August 2015
//3.10 = 765 released 27 June 2016
//3.11 = 766 released 3 December 2016, fix of miswriting of codon positions
//3.20 = 801 released 1 January 2017
//3.30 = 854 released 12 Sept 2017
//3.31 = 858 released 20 Sept 2017
/*.................................................................................................................*/
/** returns a string if this is a special version of Mesquite */
public final static String getSpecialVersion() {
return "";
}
/*.................................................................................................................*/
public final static String getBuildVersion() {
return " (build " + getBuildLetter() + getBuildNumber() + ")";
}
/*.................................................................................................................*/
/*.................................................................................................................*/
//As of 3.0 this becomes fixed, not changing with version)
public static String errorReportURL = "http://mesquiteproject.org/pyMesquiteFeedback";
public static String versionReportURL = "http://mesquiteproject.org/pyMesquiteStartup";
public static String beansReportURL = "http://mesquiteproject.org/pyMesquiteBeans";
//See Mesquite.java for notices.xml URLs
//See Installer for updates.xml URLs
/*.................................................................................................................*/
LeakFinder leakFinder = MesquiteTrunk.leakFinderObject;
/** Static storage so that everyone can find the trunk MesquiteModule object*/
public static MesquiteTrunk mesquiteTrunk;
/** The root of the mesquite classpath.*/
public static File mesquiteDirectory=null;
/** The root of the mesquite classpath.*/
public static String mesquiteDirectoryPath=null;
/** The directory that includes all the preference files.*/
public static File prefsDirectory=null;
/** The user's directory.*/
public static File userDirectory=null;
/** The Mesquite_Support_Files directory.*/
public static File supportFilesDirectory=null;
/** The window, created by mesquiteTrunk, that displays the log.*/
public static LogWindow logWindow;
/** true if name of MesquiteModule is to be shown in alerts*/
private static final boolean showModuleInAlert = true;
/** true if name of MesquiteModule is to be shown in log entries*/
private static final boolean showModuleInLog = false;
/** true if alerts should show a dialog, or merely write to log.*/
private static final boolean alertUseDialog = true;
/** the file path to the web browser for showing web pages*/
protected static String browserString = null;
/** true if does extra check for module compatibility at startup.*/
public static boolean checkMethodsAtStartup = false;
public static final int NEXTRELEASE = Integer.MAX_VALUE;
/** this is for modules to store their last MesquiteNumber result for later use; intended for NumberForItem subclasses */
protected Object lastResult;
/** this is for modules to store their last result string for later use; intended for NumberForItem subclasses */
protected String lastResultString;
/** The default author for this machine and user account */
public static Author author = new Author();
/** This module was hired as a default choice in scripting*/
public boolean hiredAsDefaultInScripting = false;
//
/** Has module requested enabling of macro auto-save?*/
private boolean autoSaveMacros = false;
private boolean lastEmployee = false;
public static int totalFinalized = 0;
/** the MesquiteModuleInfo that refers to the module*/
protected MesquiteModuleInfo moduleInfo = null;
/** The project that the module was hired under. Almost all modules are descendant from a file coordinating module that belongs to
a specific project*/
protected MesquiteProject proj=null;
/** for the paging system (may be defunct)*/
Vector pagingsEphemeral = new Vector();
/** for the paging system (may be defunct)*/
Vector pagingsPersistent = new Vector();
Vector subfunctions = new Vector();
public ListableVector attachments = new ListableVector();
public static boolean textEdgeRemembered = false;
public static int textEdgeCompensationHeight = 5; //6 on mac; 7 on pc
public static int textEdgeCompensationWidth = 10; //12 on mac; 28 on pc
private static int instantiations = 0;
private int idNumber;
private String permanentIDString = null;
private String assignedIDString = null;
private static Random randomNumberGenerator;
static {
randomNumberGenerator = new Random(System.currentTimeMillis());
}
/** The constructor in general is to be avoided, because modules are instantiated momentarily on startup to gather
information. The usual functions of a constructor are performed by startJob*/
public MesquiteModule () {
super();
setModule(this);
instantiations++;
idNumber = instantiations;
permanentIDString = Integer.toString(idNumber) + "." + System.currentTimeMillis() + "." + Math.abs(randomNumberGenerator.nextLong());
assignedIDString = null;//new String(permanentIDString);
}
/*.................................................................................................................*/
/** instantiations of modules are numbered sequentially so they can be referred to by number*/
public long getID(){
return idNumber;
}
/*.................................................................................................................*/
/** A string that uniquely refers to this module (unique even across runs of Mesquite)*/
public String getPermanentIDString(){
if (assignedIDString == null)
return permanentIDString;
else
return assignedIDString;
}
/*.................................................................................................................*/
/** A string that should uniquely refer to this module during this run time
public String getAssignedIDString(){
return assignedIDString;
}
/*.................................................................................................................*/
/** Broadcasts that an id has been assigned to a module. This is used for scripting, in which a module assigns itself
an id string in a snapshot (e.g., a TreeContext) that an interested module can clue in to (e.g., TreeOfContext). This
allows the interested module to hook up to the assigning module even if the former was script-created before the latter
(see interaction between BasicTreeWindow and TreeOfContext)*/
public void broadCastAssignedID(MesquiteModule module, String assignedID){
if (assignedID == null)
return;
if (employees ==null)
return;
Enumeration enumeration=employees.elements();
while (enumeration.hasMoreElements()){
MesquiteModule mb = (MesquiteModule)enumeration.nextElement();
mb.broadCastAssignedID(module, assignedID);
}
}
/*.................................................................................................................*/
public void incrementNumStarts(){
getModuleInfo().incrementNumStarts();
}
/*.................................................................................................................*/
/** superStartJob is called automatically when an employee is hired. This is intended for use by superclasses of modules that need
their own constructor-like call, without relying on the subclass to be polite enough to call super.startJob().*/
public boolean superStartJob(String arguments, Object condition, boolean hiredByName){
return true;
}
/*.................................................................................................................*/
/** startJob is called automatically when an employee is hired. The parameter scripting indicates if the hiring occurs in the context
of automated scripting (e.g., on reading a Mesquite block of a NEXUS file). The module can limit user interface calls (e.g. dialog boxes)
when scripting occurs.<p>
The MesquiteModule should override this method, to add code to
initialize things it needs, and to hire relevant necessary employees. startJob must return
true if the module was successfully started; false otherwise. Thus, if the module needs a data matrix
but the file has none, it returns false and the hiring process is undone.<p>
Most modules will ignore the arguments and condition.*/
public abstract boolean startJob(String arguments, Object condition, boolean hiredByName);
/*.................................................................................................................*/
/** Resets the hiring condition, e.g. that matrices returned must be continuous. This may not always work as it was added in '09 in Stored Characters.*/
public void setHiringCondition(Object condition){
}
/*.................................................................................................................*/
/** endJob is called as a module is quitting; modules should put their clean up code here.*/
public void endJob() {
if (menuItemsSpecs != null) {
menuItemsSpecs.dispose(true);
}
menuItemsSpecs = null;
}
/*.................................................................................................................*/
public void finalize() throws Throwable {
totalFinalized++;
super.finalize();
}
/*.................................................................................................................*/
/** dispose is called automatically when an employee is fired. It fires all employees and their subemployees etc.
The MesquiteModule should call endJob to
finalize things it needs.. NOTE: if a module wants to quit on its own accord, it should call "iQuit" so that
the replacement hiring system can take effect.*/
protected void dispose() {
if (assignedMenuSpec !=null)
assignedMenuSpec.removeGuestModule(this);
if (moduleMenuSpec !=null)
moduleMenuSpec.removeGuestModule(this);
doomed = true;
MesquiteWindow w = getModuleWindow();
if (w !=null) {
if (!(w instanceof SystemWindow)){ //not needed, since quitting
w.removeAll();
}
w.setVisible(false);
}
boolean employerDoomed = (employer!=null && employer.doomed);
if (!employerDoomed)
incrementMenuResetSuppression();
//storePreferences();
if (pagingsEphemeral!=null)
pagingsEphemeral.removeAllElements();
if (pagingsPersistent!=null)
pagingsPersistent.removeAllElements();
disposeMenuSpecifications();
if (w !=null) {
if (!w.disposed()) {
w.dispose();
}
resetAllMenuBars();
}
// if (employer!=null && quit) //TODO: only call this if the employer quit on its own
// employer.employeeQuit(this);
if (MesquiteTrunk.trackActivity) MesquiteMessage.notifyProgrammer ("MesquiteModule " + getName() + " closing down ");
closeDownAllEmployees (this);
if (employer!=null && !employer.doomed && employer.employees!=null) {
employer.employees.removeElement(this, false);
}
if (!employerDoomed)
resetContainingMenuBar();
employer = null; //MEMORY: cut this out to promote memory leaks (tying modules together WHILE debugging NEW aug 99
if (employees!=null)
employees.dispose();
employees = null;
if (!employerDoomed)
decrementMenuResetSuppression();
proj = null;
totalDisposed++;
}
/*.................................................................................................................*/
/** Notifies all employees that a file is about to be closed.*/
public void fileCloseRequested () {
if (employees==null || doomed)
return;
Enumeration e = employees.elements();
while (e.hasMoreElements()) {
Object obj = e.nextElement();
MesquiteModule mbe = (MesquiteModule)obj;
if (mbe!=null) {
mbe.fileCloseRequested();
}
}
}
/*.................................................................................................................*/
/** To be called by a module to close down on its own (as opposed to being fired). This might happen, for
example, if conditions change so that the module can no longer function (e.g. all stored matrices are deleted
from a file, and so StoredMatrices can no longer supply matrices). A module could
also call its own endJob() method, but iQuit is to be preferred because it evokes the automatic replacement
hiring system if available. (See setHiringCommand of EmployerEmployee) */
public final void iQuit(){
iQuit(true);
}
public final void iQuit(boolean giveMessage){
incrementMenuResetSuppression();
MesquiteCommand command = getHiringCommand();
doomAll();
MesquiteModule employerMod = employer;
MesquiteModule localRefEmployer = employer;
boolean employerDoomed = (employer==null || employer.doomed || employerMod.quittingConditions());
if (!employerDoomed) {
localRefEmployer.incrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
localRefEmployer.refreshBrowser(MesquiteModule.class);
}
endJob();
dispose();
resetAllWindowsMenus();
/* if hiringCommand isn't null, then look among the module info's for possible replacements
and use the hiringCommand to attempt to hire them.
In looking for possible replacements:
-- use the hiringCondition to find compatible modules
-- don't choose again the current module
With each candidate replacement, call the command's doIt method, passing the name of
the candidate as an argument. If the Object returned by doIt is non-null and is an instance of the
candidate module, then it is assume the replacement was successful and the search for replacements is ended.
(It may make sense to notify the user of the replacement.)
*/
if (employerDoomed || employerMod.quittingConditions()) {
}
else if (command!=null){
resetContainingMenuBar();
if (giveMessage)
alert("Module \"" + getName() + "\" has quit; a replacement module will be sought."); //TODO: ask user
MesquiteModuleInfo c=null;
// boolean found = false;
if (getHiringCondition()==null){
String name =ListDialog.queryList(module.containerOfModule(), "Select replacement", "Select module to replace " + getName(), MesquiteString.helpString, getHiredAs(), null, employerMod);
if (StringUtil.blank(name)) {
//alert("Module \"" + getName() + "\" quit but none chosen to replace it. This may");
hiredAs = null;
hiringCondition = null;
employerMod.employeeQuit(this);
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
CommandRecord cr = new CommandRecord(false);
cr.setEmergencyRehire(true);
Object mb = command.doIt(StringUtil.tokenize(name));
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
if (giveMessage)
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
MesquiteModuleInfo prevC = null;
while ((c = MesquiteTrunk.mesquiteModulesInfoVector.findNextModule(getHiredAs(), c)) != null) { // if wasn't successful, find first that works.
if (c!=prevC){
cr = new CommandRecord(false);
cr.setEmergencyRehire(true);
CommandRecord prevR = MesquiteThread.getCurrentCommandRecord();
MesquiteThread.setCurrentCommandRecord(cr);
mb = command.doIt(StringUtil.tokenize(c.getName()));
MesquiteThread.setCurrentCommandRecord(prevR);
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
prevC = c;
}
}
}
else {
String name =ListDialog.queryList(module.containerOfModule(), "Select replacement", "Select module to replace " + getName(), MesquiteString.helpString, getHiredAs(), getHiringCondition(), employerMod);
if (StringUtil.blank(name)) {
hiredAs = null;
hiringCondition = null;
employerMod.employeeQuit(this);
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
Object mb = command.doIt(StringUtil.tokenize(name));
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
if (giveMessage)
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
MesquiteModuleInfo prevC = null;
while ((c = MesquiteTrunk.mesquiteModulesInfoVector.findNextModule(getHiredAs(), c, getHiringCondition(), getProject(), employerMod)) != null) { // if wasn't successful, find first that works.
if (c!=prevC){
mb = command.doIt(StringUtil.tokenize(c.getName()));
if (mb!=null && mb instanceof MesquiteModule && ((MesquiteModule)mb).getModuleInfo()!= getModuleInfo() && getHiredAs()!=null && getHiredAs().isAssignableFrom(mb.getClass())) {
if (giveMessage)
alert("Module \"" + ((Listable)mb).getName() + "\" hired to replace \"" + getName() + "\", which has quit");
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
return;
}
}
prevC = c;
}
}
alert("Employee quit but no replacement hire was found");
employerMod.employeeQuit(this);
}
else {
//alert("Module \"" + getName() + "\" has quit.");
employerMod.employeeQuit(this);
}
decrementMenuResetSuppression();
if (!employerDoomed) localRefEmployer.decrementEmployeeBrowserRefreshSuppression(MesquiteModule.class);
}
/*.................................................................................................................*/
/** Query module as to whether conditions are such that it will have to quit soon -- e.g. if its taxa block has been doomed. The tree window, data window,
etc. override this to return true if their object is doomed. This is useful in case MesquiteListener disposing method is not called for an employer before one of its
employees discovers that it needs to quit. If the employer is going to quit anyway,there is no use to use auto rehire for the quit employee.*/
public boolean quittingConditions(){
if (employer!=null) {
return employer.quittingConditions();
}
return false;
}
/*.................................................................................................................*/
/** A method called immediately after the file has been established but not yet read in.*/
public void projectEstablished() {
}
/*.................................................................................................................*/
/** A method called immediately after the file has been read in or completely set up (if a new file).*/
public void fileReadIn(MesquiteFile f) {
}
/*.................................................................................................................*/
/** A method called immediately before a Mesquite block is to be read */
public void aboutToReadMesquiteBlock(MesquiteFile f) {
}
/*.................................................................................................................*/
/** A method called immediately before a file is to be saved.*/
public void fileAboutToBeWritten(MesquiteFile f) {
}
/*.................................................................................................................*/
/** A method called when a FileElement added to the project; module can respond as needed (e.g.,
InitializeParsimony can add default model set to a CharacterData. (currently only called for Taxa and CharacterData additions).*/
public void fileElementAdded(FileElement element) {
}
/*.................................................................................................................*/
/** Returns duty Class the module belongs to; should be defined not by module itself but by abstract class representing duty */
public abstract Class getDutyClass();
/*.................................................................................................................*/
/** Returns module info for module*/
public MesquiteModuleInfo getModuleInfo(){
return moduleInfo;
}
/** Notifies all employees that a class field has changed.*/
public void classFieldChanged (Class c, String fieldName) {
if (employees==null || doomed)
return;
Enumeration e = employees.elements();
while (e.hasMoreElements()) {
Object obj = e.nextElement();
MesquiteModule mbe = (MesquiteModule)obj;
if (mbe!=null) {
mbe.classFieldChanged(c, fieldName);
}
}
}
/*.................................................................................................................*/
Listened optionalListened = null;
public Listened getParametersChangedNotifier(){
if (optionalListened == null)
optionalListened = new Listened();
return optionalListened;
}
/*.................................................................................................................*/
/** A generic call to tell employer that the module's parameters have changed
sufficiently that its basic calculations are no longer valid, and a recalculation should
be requested. The employer receives the message as a call to its employeeParametersChanged.
(Typically, this might follow an outputInvalid call, which */
public final void parametersChanged(Notification notification) {
//CommandRecord.tick("Parameters of module changed");
if (employer!=null && !doomed) {
if (!hasOldStyleEPC(employer))
employer.employeeParametersChanged(this, this, notification);
}
if (optionalListened != null)
optionalListened.notifyListeners(this, notification);
}
public final void parametersChanged() {
parametersChanged(null);
}
/*.................................................................................................................*/
/** A generic call to ask employer whether to handle something myself as employee */
public final boolean dearEmployerShouldIHandleThis(Notification notification) {
//CommandRecord.tick("Parameters of module changed");
if (employer!=null && !doomed) {
return employer.employeeRequestingIndependenceOfAction(this, this, notification);
}
return true;
}
/*.................................................................................................................*/
private boolean hasOldStyleEPC(MesquiteModule mb){
try {
mb.getClass().getMethod("employeeParametersChanged", new Class[] {MesquiteModule.class, MesquiteModule.class, CommandRecord.class});
}
catch(NoSuchMethodException e){
return false;
}
catch(SecurityException e){
return false; //hope for best
}
alert("The module " + employer.getName() +" appears to be old and incompatible with the current version of Mesquite.");
return true;
}
/*.................................................................................................................*/
/** Generated by an employee calling its parametersChanged method. The MesquiteModule should act accordingly, for instance, asking
the employee to do a recalculation. */
public void employeeParametersChanged(MesquiteModule employee, MesquiteModule source, Notification notification) {
//CommandRecord.tick("Parameters of employee module changed");
if (employer!=null && !doomed) {
if (!hasOldStyleEPC(employer))
employer.employeeParametersChanged(this, source, notification);
}
}
/*.................................................................................................................*/
/** Generated by an employee calling its dearEmployerShouldIHandleThis method. The MesquiteModule should respond false if the employer wants to handle it itself. */
public boolean employeeRequestingIndependenceOfAction(MesquiteModule employee, MesquiteModule source, Notification notification) {
if (employer!=null && !doomed) {
return employer.employeeRequestingIndependenceOfAction(this, source, notification);
}
return true;
}
/*.................................................................................................................*/
/** This passes an employeeOutputInvalid call to the employer, and so on, until some employer overrides it to do something about it.
The purpose of this is not to call for recalculations, but primarily to allow the output to be turned blank while
long recalculations are done. To force recalculation, parametersChanged should be called after outputInvalid is called*/
public final void outputInvalid() {
if (employer!=null && !doomed)
employer.employeeOutputInvalid(this, this);
}
/*.................................................................................................................*/
/** Generated by an employee calling its outputInvalide method. The MesquiteModule should blank any output. */
public void employeeOutputInvalid(MesquiteModule employee, MesquiteModule source) {
if (employer!=null && !doomed)
employer.employeeOutputInvalid(this, source);
}
/*.................................................................................................................*/
/** Generated by an employee who quit. The MesquiteModule should act accordingly. */
public void employeeQuit(MesquiteModule employee) {
}
/*.................................................................................................................*/
/** Sets this module to remain one of the last employees of its employers. */
public void setToLastEmployee(boolean last){
lastEmployee = last;
}
/*.................................................................................................................*/
/** Returns whether this module is to remain one of the last employees of its employers. */
public boolean getIfLastEmployee(){
return lastEmployee;
}
/*.................................................................................................................*/
/** Sets whether module has requested to enable auto-save of macros. */
public void setAutoSaveMacros(boolean aut){
autoSaveMacros = aut;
}
/*.................................................................................................................*/
/** Returns whether module has requested to enable auto-save of macros. */
public boolean getAutoSaveMacros(){
return autoSaveMacros;
}
/*.................................................................................................................*/
/** Called typically by employer to indicate that will be called soon, therefore don't update graphics. */
public void onHold() {
}
/*.................................................................................................................*/
/** Called typically by employer to turn off hold, therefore don't update graphics. */
public void offHold() {
}
/*.................................................................................................................*/
public String supportDirectoryPath (){
return getTempDirectoryPath() + MesquiteFile.fileSeparator + getShortClassName(this.getClass());
}
/*.................................................................................................................*/
public static String getTempDirectoryPath (){
return MesquiteTrunk.tempDirectory; //+ Math.abs(rng.nextInt()));
}
/*.................................................................................................................*/
private String prefsPath (){
return prefsDirectory + MesquiteFile.fileSeparator + getShortClassName(this.getClass()) +".pref";
}
/*.................................................................................................................*/
private String prefsPathXML (){
return prefsDirectory + MesquiteFile.fileSeparator + getShortClassName(this.getClass()) +".xml";
}
/*.................................................................................................................*/
public String createTempDirectory(MesquiteBoolean success){
boolean baseDirectoryExists = false;
String base = prefsDirectory + MesquiteFile.fileSeparator + "temp";
if (!MesquiteFile.fileOrDirectoryExists(base)) {
File f = new File(base);
baseDirectoryExists = f.mkdir();
} else
baseDirectoryExists = true;
if (success!=null && !baseDirectoryExists)
success.setValue(false);
base = prefsDirectory + MesquiteFile.fileSeparator + "temp" + MesquiteFile.fileSeparator + "temp" + MesquiteFile.massageStringToFilePathSafe(MesquiteTrunk.getUniqueIDBase()) ;
if (baseDirectoryExists) {
if (!MesquiteFile.fileOrDirectoryExists(base)) {
File f = new File(base);
boolean b = f.mkdir();
if (success!=null)
success.setValue(b);
} else if (success!=null)
success.setValue(true);
}
MesquiteTrunk.tempDirectory = base;
return base;
}
/*.................................................................................................................*/
public String createTempDirectory(){
return createTempDirectory(null);
}
/*.................................................................................................................*/
public void deleteTempDirectory(){
String directoryPath = getTempDirectoryPath();
MesquiteFile.deleteDirectory(directoryPath);
}
/*.................................................................................................................*/
public String createEmptySupportDirectory(MesquiteBoolean success){
String base = supportDirectoryPath();
if (MesquiteFile.fileOrDirectoryExists(base))
MesquiteFile.deleteDirectory(base);
if (!MesquiteFile.fileOrDirectoryExists(base)) {
File f = new File(base);
boolean b = f.mkdir();
if (success!=null)
success.setValue(b);
} else if (success!=null)
success.setValue(true);
return base;
}
/*.................................................................................................................*/
public String createSupportDirectory(MesquiteBoolean success){
String base = supportDirectoryPath();
if (!MesquiteFile.fileOrDirectoryExists(base)) {
File f = new File(base);
boolean b = f.mkdir();
if (success!=null)
success.setValue(b);
} else if (success!=null)
success.setValue(true);
return base;
}
/*.................................................................................................................*/
public String createSupportDirectory(){
return createSupportDirectory(null);
}
/*.................................................................................................................*/
public void deleteSupportDirectory(){
String directoryPath = supportDirectoryPath();
MesquiteFile.deleteDirectory(directoryPath);
}
/* XMLPreferencesDocumentation
* Herewith a description of how a module can use the simple, one-level deep XML preferences system:
1. in startjob, call loadPreferences();
2. call storePreferences(); where appropriate in the module (e.g., after you press ok on an options dialog box)
3. override preparePreferencesForXML() to prepare the XML to write
4. override processSingleXMLPreference(String, String) to read XML tag as it comes in.
Here are examples of preparePreferencesForXML and processSingleXMLPreference to use as models.
These presume we have three variables whose values we want to store:
boolean booleanValue;
String stringValue;
int intValue;
and that we want to name the tags the same as the variable names:
public String preparePreferencesForXML () {
StringBuffer buffer = new StringBuffer();
StringUtil.appendXMLTag(buffer, 2, "mesquiteBoolean", mesquiteBoolean);
StringUtil.appendXMLTag(buffer, 2, "booleanValue", booleanValue);
StringUtil.appendXMLTag(buffer, 2, "integerValue", integerValue);
StringUtil.appendXMLTag(buffer, 2, "stringValue", stringValue);
return buffer.toString();
}
public void processSingleXMLPreference (String tag, String content) {
if ("mesquiteBoolean".equalsIgnoreCase(tag))
mesquiteBoolean.setValue(content);
else if ("booleanValue".equalsIgnoreCase(tag))
booleanValue = MesquiteBoolean.fromTrueFalseString(content);
else if ("integerValue".equalsIgnoreCase(tag))
integerValue = MesquiteInteger.fromString(content);
else if ("stringValue".equalsIgnoreCase(tag))
stringValue = StringUtil.cleanXMLEscapeCharacters(content);
}
/*.................................................................................................................*/
public String getXMLModuleName (){
String moduleName = getShortClassName(this.getClass());
if (this == mesquiteTrunk)
moduleName = "MesquiteTrunk";
return moduleName;
}
/*.................................................................................................................*/
public String getStartOfXMLPrefs (int version){
StringBuffer buffer = new StringBuffer(60);
StringUtil.appendStartOfXMLFile(buffer);
buffer.append("<mesquite>\n");
buffer.append("\t<" + getXMLModuleName() + ">\n");
buffer.append("\t\t<version>" +version + "</version>\n");
return buffer.toString();
}
/*.................................................................................................................*/
public String getEndOfXMLPrefs (){
StringBuffer buffer = new StringBuffer(60);
buffer.append("\t</" + getXMLModuleName() + ">\n");
buffer.append("</mesquite>\n");
return buffer.toString();
}
/*.................................................................................................................*/
/** This causes the file "prefs" in the module's directory to be read, and the contents
are then sent to "processPreferencesFromFile".*/
public final void loadPreferences (MesquiteString xml) {
if (MesquiteFile.fileExists(prefsPathXML())){
String prefsStringXML = MesquiteFile.getFileContentsAsString(prefsPathXML());
if (prefsStringXML!=null) {
if (xml!=null)
xml.setValue(prefsStringXML);
if (!parseFullXMLDocument(prefsStringXML)) {
XMLUtil.readXMLPreferencesFromFile(this,this, prefsPathXML());
// XMLUtil.readXMLPreferences(this,this, prefsStringXML);
}
}
// the xml pref exists; check to see if the old one exists; if so, delete it
if (MesquiteFile.fileExists(prefsPath())){ //old one exists; delete it
MesquiteFile.deleteFile(prefsPath());
}
}
else if (MesquiteFile.fileExists(prefsPath())){ //note that the XML version thus supercedes the .prefs version
String[] prefsString = MesquiteFile.getFileContentsAsStrings(prefsPath());
if (prefsString!=null)
processPreferencesFromFile(prefsString);
}
//the following was added build 487 v 2. 6, to permit prefs that followed Mesquite_Folder to override (e.g., for classroom copies)
String overridePrefsPath = getInstallationSettingsPath() + "prefs.xml";
if (MesquiteFile.fileExists(overridePrefsPath)){
String prefsStringXML = MesquiteFile.getFileContentsAsString(overridePrefsPath);
if (prefsStringXML!=null) {
if (xml!=null)
xml.setValue(prefsStringXML);
if (!parseFullXMLDocument(prefsStringXML)) {
System.out.println("Prefs overridden via file in settings directory for module " + getName());
XMLUtil.readXMLPreferences(this,this, prefsStringXML);
}
}
}
}
/*.................................................................................................................*/
/** This causes the file "prefs" in the module's directory to be read, and the contents
are then sent to "processPreferencesFromFile".*/
public final void loadPreferences () {
loadPreferences(null);
}
protected static boolean isCorrectRootTag(String tagName, Class classObj) {
return getShortClassName(classObj).equalsIgnoreCase(tagName);
}
/**
* Hook for subclasses to provide their own xml preferences parsing implementations
* @return
*/
protected boolean parseFullXMLDocument(String xmlString) {
return false;
}
/*.................................................................................................................*/
/** This is called following a "processPreferencesFromXML" call by a module. A module can override it
to process an individual XML preferences string*/
/*.................................................................................................................*/
public void processSingleXMLPreference (String tag, String content) {
}
/*.................................................................................................................*/
/** This is called following a "loadPreferences" call by a module. A module can override it
to process the preferences string*/
public void processPreferencesFromFile (String[] prefs) {
}
/*.................................................................................................................*/
/** This causes the file "prefs" in the module's directory to be written, using contents
returned by the module via "preparePreferencesForFile"*/
public final void storePreferences () {
String prefsStringXML = preparePreferencesForXML();
if (prefsStringXML!=null) {
boolean isAlreadyFullDocument = prefsStringXML.startsWith("<?xml");
// if subclasses return a full document, just write that out.
// otherwise add the beginning and end of the document
String xmlToWrite = isAlreadyFullDocument ? prefsStringXML : getStartOfXMLPrefs(getXMLPrefsVersion()) + prefsStringXML+ getEndOfXMLPrefs();
MesquiteFile.putFileContents(prefsPathXML(), xmlToWrite, false);
} else {
String[] prefsString = preparePreferencesForFile();
if (prefsString!=null)
MesquiteFile.putFileContents(prefsPath(), prefsString, false);
}
}
/*.................................................................................................................*/
/** This is called following a "storePreferences" call by a module. A module should override it
to indicate the strings to save to its preferences file. */
public String[] preparePreferencesForFile () {
return null;
}
/*.................................................................................................................*/
public int getXMLPrefsVersion () {
return 1;
}
public boolean xmlPrefsVersionMustMatch() {
return false;
}
/*.................................................................................................................*/
/** This is called following a "storePreferences" call by a module. A module should override it
to indicate the strings to save to its preferences file. */
public String preparePreferencesForXML () {
return null;
}
/*.................................................................................................................*/
/** returns path to this module's directory for installation settings (i.e., belonging to Mesquite_Folder, not to the user)*/
public String getInstallationSettingsPath() {
if (this == MesquiteTrunk.mesquiteTrunk)
return getRootPath() + "settings" + MesquiteFile.fileSeparator;
String base = getRootPath() + "settings" + MesquiteFile.fileSeparator;
String modulePath = moduleInfo.getClassName();
modulePath = modulePath.substring(modulePath.indexOf(".")+1, modulePath.length());
modulePath = StringUtil.getAllButLastItem(modulePath, ".");
modulePath = StringUtil.replace(modulePath, ".", MesquiteFile.fileSeparator) +MesquiteFile.fileSeparator ;
//modulePath = modulePath.substring(9, modulePath.length());
return base + modulePath;
}
/*.................................................................................................................*/
/** makes module's directory for installation settings (i.e., belonging to Mesquite_Folder, not to the user)*/
public boolean makeInstallationSettingsPathIfNeeded() {
String path = getInstallationSettingsPath();
File mf = new File(path);
if (mf.exists())
return true;
return mf.mkdirs();
}
/*.................................................................................................................*/
/** returns path to this module's directory*/
public String getPath() {
if (this == MesquiteTrunk.mesquiteTrunk)
return getRootPath() + "mesquite" + MesquiteFile.fileSeparator;
if (moduleInfo == null)
return null;
return moduleInfo.getDirectoryPath();
}
/*.................................................................................................................*/
/** returns path to this module's package directory*/
public String getPackagePath() {
if (this == MesquiteTrunk.mesquiteTrunk)
return getRootPath() + "mesquite" + MesquiteFile.fileSeparator;
return moduleInfo.getPackagePath();
}
/*.................................................................................................................*/
/** returns path to the image directory for this module's images*/
public String getPackageImagesPath() {
if (this == MesquiteTrunk.mesquiteTrunk)
return getRootPath() + "mesquite" + MesquiteFile.fileSeparator;
return moduleInfo.getPackagePath() + "images"+ MesquiteFile.fileSeparator;
}
/*.................................................................................................................*/
/** returns path to the root directory of Mesquite (i.e., above mesquite, images, etc.)*/
public static String getRootPath() {
String s= StringUtil.getAllButLastItem(mesquiteDirectoryPath, MesquiteFile.fileSeparator);
if (s==null)
return null;
else
return s + MesquiteFile.fileSeparator;
}
/*.................................................................................................................*/
/** returns path to the root directory of Mesquite images*/
public static String getRootImageDirectoryPath() {
String s = getRootPath();
if (s==null)
return null;
else