-
Notifications
You must be signed in to change notification settings - Fork 154
Expand file tree
/
Copy pathosdagMainPage.py
More file actions
1041 lines (892 loc) · 50.6 KB
/
osdagMainPage.py
File metadata and controls
1041 lines (892 loc) · 50.6 KB
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
'''
INSTRUCTIONS TO USE OSDAG MAIN PAGE TEMPLATE(OsdagMainWindow):
----------------------------------------------------------------------------------------------------
Note: This code is designed to handle a 3 level structure, e.g. ,
..................................................................................................................
. Modules (Main Dictionary) .
. _______________________|______________________________________________________.......... . ((LEVEL 1))
. | | | | | | .
. Module_1 Module_2 Module_3 Module_4 Module_5 Module_6 (Keys of Main Dictionary)
........|..............|............|...........|....................|...............|............................
| | | | | |
| | | | | |
| | | [List/Tuple of Module Variants]| |
| | | | |
| | [List/Tuple of Module Variants] | |
| (UNDER DEVELOPMENT) (UNDER DEVELOPMENT) |
........|............................................................................|............................
. ____|________________________________..... ________________________|______...... (Sub Dictionaries)
. | | | | | | . ((LEVEL 2))
. Submodule_1 Submodule_2 Submodule_3 Submodule_1 Submodule_2 Submodule_3 (Keys of Sub Dictionaries)
. | | | | | | .
........|...............|...............|................|..................|..............|......................
| | | | | |
| | | | | |
| | | | | |
| | (UNDER DEVELOPMENT) | | |
| | [List/Tuple of Module Variants] | |
| [List/Tuple of Module Variants] | [List/Tuple of Module Variants]
| |
........|...................................................................|.....................................
. ____|________________________________..... _______________|_______________...... (Sub-Sub Dictionaries)
. | | | | | | . ((LEVEL 3))
. Sub-Submodule_1 Sub-Submodule_2 Sub-Submodule_3 Sub-Submodule_1 Sub-Submodule_2 Sub-Submodule_3 (Keys of Sub-Sub Dictionaries)
. | | | | | | .
........|...............|...............|....................|..................|..............|..................
| | | | | |
| (UNDER DEVELOPMENT) | [List/Tuple of Module Variants] | [List/Tuple of Module Variants]
| [List/Tuple of Module Variants] [List/Tuple of Module Variants]
[List/Tuple of Module Variants]
The Rules/Steps to use the template are(OsdagMainWindow):
-----------------------------------------------------------------------------
1) The data for the template structuring will go into a variable called self.Modules .
2) self.Modules must be a dictionary with keys as the name of modules in string format (LEVEL 1: Left Panel Buttons).
3) The values to these keys can be a dictionary(Modules), a List/Tuple(Module Variants) or self.Under_Development :
(i) If the value is a dictionary then it should contain keys as modules in string format and for values
read RULE 4 . (LEVEL 2: Tab for each module)
(ii) If the value is a List/Tuple then it should contain sub-lists/sub-tuples informing about the module variants :
(a) The module variants as sub-list/sub-tuple will have 3 values, Module_Name, Image_Path and Object_Name .
(b) The List/Tuple can have several sub-lists/sub-tuples but the last element should be a method,
which connects to the start button on the module variants' page and help launch a certain module.
(iii) If the value is self.Under_Development then that module/module variant is marked as UNDER DEVELOPMENT.
4) In case of RULE 3(i) if value of any sub-module key is a dictionary then that dictionary will follow the RULE 3
all over again and the values of the keys can be a dictionary(Sub-Modules), a List/Tuple(Sub-Module Variants) or
self.Under_Development:
(i) If the value is a dictionary then it should contain keys as sub-modules in string format and for values
read RULE 5 . (LEVEL 3 Sub Tab for each tab)
(ii) If the value is a List/Tuple then it should contain sub-lists/sub-tuples informing about the module variants :
(a) The module variants as sub-list/sub-tuple will have 3 values, Module_Name, Image_Path and Object_Name .
(b) The List/Tuple can have several sub-lists/sub-tuples but the last element should be a method,
which connects to the start button on the module variants' page and help launch a certain module.
(iii) If the value is self.Under_Development then that module/module variant is marked as UNDER DEVELOPMENT.
5) In case of RULE 4(i) if the value of any sub-module key is a dictionary then that dictionary will have keys as sub-sub-module
and the values can either be a List/Tuple(Sub-Sub-Module Variants) or self.Under_Development but not another dictionary:
(i) If the value is a List/Tuple then it should contain sub-lists/sub-tuples informing about the module variants :
(a) The module variants as sub-list/sub-tuple will have 3 values, Module_Name, Image_Path and Object_Name .
(b) The List/Tuple can have several sub-lists/sub-tuples but the last element should be a method,
which connects to the start button on the module variants' page and help launch a certain module.
(ii) If the value is self.Under_Development then that module/module variant is marked as UNDER DEVELOPMENT.
6) Object_Name, the third value in the sub-lists/sub-tuples, is used to tie to the Radiobuttons on each page thus making it easier to locate them. This is further used
in the methods to search the Radiobutton using it for the respective modules to be launched .
7) Any further Levels will result in an error .
'''
import os
from pathlib import Path
import re
import io
import traceback
import time
from importlib.resources import files
import urllib.request
from PyQt5.QtWidgets import QMessageBox,QApplication, QDialog, QMainWindow, QTextEdit
from .update_version_check import Update
#from Thread import timer
from .get_DPI_scale import scale
############################ Pre-Build Database Updation/Creation #################
# TODO: Is there a better way to create and use the sqlite file rather than directly in the installation?
sqlpath = files('osdag.data.ResourceFiles.Database').joinpath('Intg_osdag.sql')
sqlitepath = files('osdag.data.ResourceFiles.Database').joinpath('Intg_osdag.sqlite')
if sqlpath.exists():
if not sqlitepath.exists():
cmd = 'sqlite3 ' + str(sqlitepath) + ' < ' + str(sqlpath)
os.system(cmd)
sqlpath.touch()
print('Database Created')
elif sqlitepath.stat().st_size == 0 or sqlitepath.stat().st_mtime < sqlpath.stat().st_mtime - 1:
try:
sqlitenewpath = files('osdag.data.ResourceFiles.Database').joinpath('Intg_osdag_new.sqlite')
cmd = 'sqlite3 ' + str(sqlitenewpath) + ' < ' + str(sqlpath)
error = os.system(cmd)
print(error)
# if error != 0:
# raise Exception('SQL to SQLite conversion error 1')
# if sqlitenewpath.stat().st_size == 0:
# raise Exception('SQL to SQLite conversion error 2')
os.remove(sqlitepath)
sqlitenewpath.rename(sqlitepath)
sqlpath.touch()
print('Database Updated', sqlpath.stat().st_mtime, sqlitepath.stat().st_mtime)
except Exception as e:
sqlitenewpath.unlink()
print('Error: ', e)
#########################################################################################
from PyQt5 import uic
from PyQt5.QtCore import pyqtSlot,pyqtSignal, QObject, Qt,QSize, QFile, QTextStream, QCoreApplication
from PyQt5.QtWidgets import QMainWindow, QDialog,QMessageBox, QFileDialog, QApplication, QWidget, QLabel, QGridLayout, QVBoxLayout, QTabWidget, QRadioButton, QButtonGroup, QSizePolicy
from PyQt5.QtGui import QIcon
from PyQt5 import QtWidgets, QtCore, QtGui
import math
import sys
from .gui.ui_tutorial import Ui_Tutorial
from .gui.ui_aboutosdag import Ui_AboutOsdag
from .gui.ui_ask_question import Ui_AskQuestion
from .gui.ui_design_summary import Ui_DesignReport
from .gui.LeftPanel_Button import Ui_LPButton
from .gui.Submodule_Page import Ui_Submodule_Page
from .gui.ui_OsdagMainPage import Ui_MainWindow
from .gui.ExceptionDialog import CriticalExceptionDialog
# from .design_type.connection.fin_plate_connection import design_report_show
# from .design_type.connection.fin_plate_connection import DesignReportDialog
from .design_type.connection.fin_plate_connection import FinPlateConnection
from .design_type.connection.cleat_angle_connection import CleatAngleConnection
from .design_type.connection.seated_angle_connection import SeatedAngleConnection
from .design_type.connection.end_plate_connection import EndPlateConnection
from .design_type.connection.base_plate_connection import BasePlateConnection
from .design_type.connection.truss_connection_bolted import TrussConnectionBolted
from .design_type.connection.lap_joint_bolted import LapJointBolted
from .design_type.connection.lap_joint_welded import LapJointWelded
from .design_type.connection.butt_joint_bolted import ButtJointBolted
from .design_type.connection.butt_joint_welded import ButtJointWelded
from .design_type.connection.beam_cover_plate import BeamCoverPlate
from .design_type.connection.beam_cover_plate_weld import BeamCoverPlateWeld
from .design_type.connection.column_cover_plate_weld import ColumnCoverPlateWeld
from .design_type.connection.beam_column_end_plate import BeamColumnEndPlate
from .design_type.tension_member.tension_bolted import Tension_bolted
from .design_type.tension_member.tension_welded import Tension_welded
from .design_type.connection.beam_beam_end_plate_splice import BeamBeamEndPlateSplice
from .design_type.connection.column_cover_plate import ColumnCoverPlate
from .design_type.connection.column_end_plate import ColumnEndPlate
from .design_type.compression_member import Column
from .design_type.compression_member.compression import Compression
from .design_type.compression_member.Column import ColumnDesign
#from .design_type.beam_column.Beam_Colum_Compression import ColumnDesign
from .design_type.flexural_member.flexure import Flexure
from .design_type.flexural_member.flexure_cantilever import Flexure_Cantilever
from .design_type.flexural_member.flexure_purlin import Flexure_Purlin
from .design_type.flexural_member.flexure_othersupp import Flexure_Misc
from .design_type.plate_girder.weldedPlateGirder import PlateGirderWelded
# from .cad.cad_common import call_3DBeam
from .APP_CRASH.Appcrash import api as appcrash
import configparser
import os.path
import subprocess
if sys.platform == 'darwin':
print('its mac')
from .gui.ui_template_for_mac import Ui_ModuleWindow
else:
from .gui.ui_template import Ui_ModuleWindow
# from .gui.ui_template import Ui_ModuleWindow
class MyTutorials(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.ui = Ui_Tutorial()
self.ui.setupUi(self)
self.osdagmainwindow = parent
class MyAboutOsdag(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.ui = Ui_AboutOsdag()
self.ui.setupUi(self)
self.osdagmainwindow = parent
class MyAskQuestion(QDialog):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.ui = Ui_AskQuestion()
self.ui.setupUi(self)
self.osdagmainwindow = parent
class New_Tab_Widget(QTabWidget): # Empty Custom Tab Widget
def __init__(self):
super().__init__()
#self.setTabShape(QTabWidget.Triangular)
class Submodule_Page(QWidget): # Module Varaints' page with a GridLayout and a Start Button
def __init__(self):
super().__init__()
self.ui=Ui_Submodule_Page()
self.ui.setupUi(self)
class Submodule_Widget(QWidget): # Module Variant widget with a Name, RadioButton and an Image
def __init__(self,Iterative,parent):
super().__init__()
Module_Name,Image_Path,Object_Name=Iterative
layout=QVBoxLayout()
self.setLayout(layout)
label=QLabel(Module_Name)
layout.addWidget(label)
label.setObjectName('module_name_label')
self.rdbtn=QRadioButton()
self.rdbtn.setObjectName(Object_Name)
self.rdbtn.setIcon(QIcon(Image_Path))
self.rdbtn.setIconSize(QSize(int(scale*300), int(scale*300)))
layout.addWidget(self.rdbtn)
self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
class ModulePage(QWidget): # Empty Page with a layout
def __init__(self,margin=0):
super().__init__()
self.layout=QGridLayout()
self.setLayout(self.layout)
self.layout.setContentsMargins(0,0,0,0)
class LeftPanelButton(QWidget): # Custom Button widget for the Left Panel
def __init__(self,text):
super().__init__()
self.ui=Ui_LPButton()
self.ui.setupUi(self,scale)
self.ui.LP_Button.setText(text) #LP_Button is the QPushButton widget inside the LeftPanelButton Widget
class OsdagMainWindow(QMainWindow):
def __init__(self):
super().__init__()
resolution = QtWidgets.QDesktopWidget().screenGeometry()
width = resolution.width()
height = resolution.height()
self.ui=Ui_MainWindow()
self.ui.setupUi(self)
self.ui.switch.toggled.connect(self.change_theme)
self.ui.comboBox_help.currentIndexChanged.connect(self.selection_change)
self.ui.myStackedWidget.currentChanged.connect(self.current_changed)
self.Under_Development='UNDER DEVELOPMENT'
self.Modules={
'Connection' : {'Simple Connection' : [
('Lap Joint Bolted',str(files("osdag.data.ResourceFiles.images").joinpath("LapJointBolted.png")),'Lap_Joint_Bolted'),
('Lap Joint Welded',str(files("osdag.data.ResourceFiles.images").joinpath("LapJointWelded.png")),'Lap_Joint_Welded'),
('Butt Joint Bolted',str(files("osdag.data.ResourceFiles.images").joinpath("ButtJointBolted.png")),'Butt_Joint_Bolted'),
('Butt Joint Welded',str(files("osdag.data.ResourceFiles.images").joinpath("ButtJointWelded.png")),'Butt_Joint_Welded'),
self.show_simple_connection,
],
'Shear Connection' : [
('Fin Plate',str(files("osdag.data.ResourceFiles.images").joinpath("finplate.png")),'Fin_Plate'),
('Cleat Angle',str(files("osdag.data.ResourceFiles.images").joinpath("cleatAngle.png")),'Cleat_Angle'),
('End Plate',str(files("osdag.data.ResourceFiles.images").joinpath("endplate.png")),'End_Plate'),
('Seated Angle',str(files("osdag.data.ResourceFiles.images").joinpath("seatedAngle1.png")),'Seated_Angle'),
self.show_shear_connection,
],
'Moment Connection' :{
'Beam-to-Beam Splice' :[
('Cover Plate Bolted',str(files("osdag.data.ResourceFiles.images").joinpath("bbcoverplatebolted.png")),'B2B_Cover_Plate_Bolted'),
('Cover Plate Welded',str(files("osdag.data.ResourceFiles.images").joinpath("bbcoverplatewelded.png")),'B2B_Cover_Plate_Welded'),
('End Plate', str(files("osdag.data.ResourceFiles.images").joinpath("bb_splice.png")), 'B2B_End_Plate_Splice'),
self.show_moment_connection,
],
'Beam-to-Column': [
('End Plate', str(files("osdag.data.ResourceFiles.images").joinpath("BC-EBW_GUI.png")),'BC_End_Plate'),
self.show_moment_connection_bc
],
'Column-to-Column Splice' :[
('Cover Plate Bolted',str(files("osdag.data.ResourceFiles.images").joinpath("cccoverplatebolted.png")),'C2C_Cover_Plate_Bolted'),
('Cover Plate Welded',str(files("osdag.data.ResourceFiles.images").joinpath("cccoverplatewelded.png")),'C2C_Cover_Plate_Welded'),
('End Plate',str(files("osdag.data.ResourceFiles.images").joinpath("ccep_flush.png")),'C2C_End_Plate_Connection'),
self.show_moment_connection_cc,
],
'PEB' : self.Under_Development,
},
'Base Plate':[
('Base Plate Connection', str(files("osdag.data.ResourceFiles.images").joinpath("base_plate.png")), 'Base_Plate'),
self.show_base_plate,
],
'Truss Connection' : self.Under_Development,
# [
# ('Truss Connection Bolted', str(files("osdag.data.ResourceFiles.images").joinpath("broken.png")), 'Truss_Bolted'),
# ('Truss Connection Welded', str(files("osdag.data.ResourceFiles.images").joinpath("broken.png")), 'Truss_Welded'),
# self.show_truss_bolted,
# ],
},
'Tension Member' : [
('Bolted to End Gusset',str(files("osdag.data.ResourceFiles.images").joinpath("bolted_ten.png")),'Tension_Bolted'),
('Welded to End Gusset',str(files("osdag.data.ResourceFiles.images").joinpath("welded_ten.png")),'Tension_Welded'),
self.show_tension_module,
],
'Compression Member': [('Axially Loaded Columns', str(files("osdag.data.ResourceFiles.images").joinpath("CompressionMembers_ColumnsInFrames")), 'Column_Design'),
# ('Beam-Column Design', str(files("osdag.data.ResourceFiles.images").joinpath("BC_CF-BW-Flush.png")), 'Beam_Column_Design'),
('Struts in Trusses', str(files("osdag.data.ResourceFiles.images").joinpath("strut.jpg")), 'Strut_Design'),
self.show_compression_module,
],
'Flexural Member' : [
('Simply Supported Beam', str(files("osdag.data.ResourceFiles.images").joinpath("simply-supported-beam.jpg")), 'Beam_flexure'),
('Cantilever Beam', str(files("osdag.data.ResourceFiles.images").joinpath("cantilever-beam.jpg")), 'Beam_flexure2'),
('Purlin', str(files("osdag.data.ResourceFiles.images").joinpath("purlin.jpg")), 'Beam_flexure4'),
# ('Other Beams', str(files("osdag.data.ResourceFiles.images").joinpath("fixed-beam.png")), 'Beam_flexure3'),
# ('Laterally Unsupported Beam', str(files("osdag.data.ResourceFiles.images").joinpath("broken.png")), 'Truss_Welded'),
self.show_flexure_module,
],
'Beam-Column' : self.Under_Development,
'Plate Girder' : self.Under_Development,
# TODO @rutvik
# 'Beam-Column' :[
# ('Beam-Column Design', str(files("osdag.data.ResourceFiles.images").joinpath("broken.png")), 'Beam_Column_Design'),
# self.show_beamcolumn_module,
# ],
'Truss' : self.Under_Development,
'2D Frame' : self.Under_Development,
'3D Frame' : self.Under_Development,
'Group Design' : self.Under_Development,
}
####################################### UI Formation ################################
for ModuleName in self.Modules: #Level 1 dictionary handling
Button= LeftPanelButton(ModuleName)
self.ButtonConnection(Button,list(self.Modules.keys()),ModuleName)
self.ui.verticalLayout.addWidget(Button)
# print(f"Here1{ModuleName}")
if(type(self.Modules[ModuleName])==dict): #level 2 dictionary handling
Page= ModulePage()
self.ui.myStackedWidget.addWidget(Page)
Current_Module=self.Modules[ModuleName]
Tab_Widget=New_Tab_Widget()
Page.layout.addWidget(Tab_Widget)
# print(f"Here2{self.Modules[ModuleName]}")
for Submodule in Current_Module:
# print(f"Here3{Submodule}")
if(type(Current_Module[Submodule])==dict): #Level 3 dictionary handling
New_Tab=ModulePage()
Tab_Widget.addTab(New_Tab,Submodule)
Sub_Page= ModulePage()
New_Tab.layout.addWidget(Sub_Page)
Current_SubModule=Current_Module[Submodule]
Sub_Tab_Widget=New_Tab_Widget()
Sub_Page.layout.addWidget(Sub_Tab_Widget)
# print(f"Here4{Submodule}")
for Sub_Sub_Module in Current_SubModule:
# print(f"Here5{Sub_Sub_Module}")
if(type(Current_SubModule[Sub_Sub_Module]) in [list,tuple]): # Final List/tuple Handling
New_Sub_Tab=Submodule_Page()
Sub_Tab_Widget.addTab(New_Sub_Tab,Sub_Sub_Module)
group=QButtonGroup(QWidget(Page))
row,col=0,0
n=math.floor((len(Current_SubModule[Sub_Sub_Module])-2)/2)
for Selection in Current_SubModule[Sub_Sub_Module][:-1]:
widget=Submodule_Widget(Selection,New_Sub_Tab)
group.addButton(widget.rdbtn)
New_Sub_Tab.ui.gridLayout.addWidget(widget,row,col)
if(col==n and len(Current_SubModule[Sub_Sub_Module])!=3):
row+=1
col=0
else:
col+=1
New_Sub_Tab.ui.StartButton.clicked.connect(Current_SubModule[Sub_Sub_Module][-1])
elif(Current_SubModule[Sub_Sub_Module]==self.Under_Development): # Final Under Development Handling
Sub_Tab_Widget.addTab(self.UnderDevelopmentModule(),Sub_Sub_Module)
else:
raise ValueError
elif(type(Current_Module[Submodule]) in [list,tuple]): #Level 3 list/tuple handling
New_Tab=Submodule_Page()
Tab_Widget.addTab(New_Tab,Submodule)
group=QButtonGroup(QWidget(Page))
row,col=0,0
n=math.floor((len(Current_Module[Submodule])-2)/2)
# print(f"Here6")
for Selection in Current_Module[Submodule][:-1]:
widget=Submodule_Widget(Selection,New_Tab)
group.addButton(widget.rdbtn)
New_Tab.ui.gridLayout.addWidget(widget,row,col)
if(col==n and len(Current_Module[Submodule])!=3):
row+=1
col=0
else:
col+=1
New_Tab.ui.StartButton.clicked.connect(Current_Module[Submodule][-1])
elif(Current_Module[Submodule]==self.Under_Development): #Level 3 Under Development handling
Tab_Widget.addTab(self.UnderDevelopmentModule(),Submodule)
else:
raise ValueError
elif(type(self.Modules[ModuleName]) in [list,tuple]): # Level 2 list/tuple handling
Page= Submodule_Page()
self.ui.myStackedWidget.addWidget(Page)
group=QButtonGroup(QWidget(Page))
row,col=0,0
n=math.floor((len(self.Modules[ModuleName])-2)/2)
# print(f"Here7")
for Selection in self.Modules[ModuleName][:-1]:
widget=Submodule_Widget(Selection,Page)
group.addButton(widget.rdbtn)
Page.ui.gridLayout.addWidget(widget,row,col)
if(col==n and len(self.Modules[ModuleName])!=3):
row+=1
col=0
else:
col+=1
Page.ui.StartButton.clicked.connect(self.Modules[ModuleName][-1])
elif(self.Modules[ModuleName]==self.Under_Development): #Level 2 Under Development handling
self.ui.myStackedWidget.addWidget(self.UnderDevelopmentModule())
else:
raise ValueError
self.resize(int(width*(0.85)), int(height*(0.75)))
self.center()
self.show()
def center(self):
frameGm = self.frameGeometry()
screen = QtWidgets.QApplication.desktop().screenNumber(QtWidgets.QApplication.desktop().cursor().pos())
centerPoint = QtWidgets.QApplication.desktop().screenGeometry(screen).center()
frameGm.moveCenter(centerPoint)
self.move(frameGm.topLeft())
@pyqtSlot(int)
def current_changed(self, index):
l = list(self.Modules.keys())
items = list(self.ui.verticalLayout.itemAt(i) for i in range(self.ui.verticalLayout.count()))
# print(items,"hfhh")
for item in range(len(items)):
if item == index-1:
items[item].widget().ui.LP_Button.setStyleSheet('''
background-color: qradialgradient(cx: 0.5, cy: 0.5, radius: 2, fx: 0.5, fy: 1, stop: 0 rgba(130, 36, 38,190), stop: 0.2 rgb(171, 39, 42), stop: 0.4 rgba(255,30,30,32));
''')
else:
items[item].widget().ui.LP_Button.setStyleSheet(";")
################################ UI Methods ###############################################
def closeEvent(self, event):
try:
sqlitepath = Path('ResourceFiles/Database/Intg_osdag.sqlite')
sqlpath = Path('ResourceFiles/Database/Intg_osdag.sql')
precisionscript = 'ResourceFiles/Database/precision.awk'
if sqlitepath.exists() and (
not sqlpath.exists() or sqlpath.stat().st_size == 0 or sqlpath.stat().st_mtime < sqlitepath.stat().st_mtime - 1):
sqlnewpath = Path('ResourceFiles/Database/Intg_osdag_new.sql')
cmd = 'sqlite3 ' + str(sqlitepath) + ' .dump | gawk -f ' + precisionscript + ' > ' + str(sqlnewpath)
error = os.system(cmd)
# if error != 0:
# raise Exception('SQLite conversion to SQL error 1')
# if sqlnewpath.stat().st_size == 0:
# raise Exception('SQLite conversion to SQL error 2')
os.remove(sqlpath)
sqlnewpath.rename(sqlpath)
sqlitepath.touch()
print('DUMP updated')
except Exception as e:
sqlnewpath.unlink()
print('Error: ', e)
def selection_change(self):
loc = self.ui.comboBox_help.currentText()
if loc == "Design Examples":
self.design_examples()
elif loc == "Video Tutorials":
self.open_tutorials()
elif loc == "About Osdag":
self.about_osdag()
elif loc == "Ask Us a Question":
self.ask_question()
elif loc == "Check for Update":
self.updater = Update()
try:
update_avl, msg = self.updater.notifi()
except ConnectionError as e:
QMessageBox.critical(self, "Network Error", str(e))
return
# QMessageBox.information(self, 'Info',msg)
box = QMessageBox(self)
box.setIcon(QMessageBox.Information)
box.setWindowTitle("Update Status")
box.setText(msg)
if update_avl:
update_now_btn = box.addButton("Update Now", QMessageBox.AcceptRole)
later_btn = box.addButton("Update Later", QMessageBox.RejectRole)
else:
ok_btn = box.addButton("OK", QMessageBox.AcceptRole)
box.exec_()
if update_avl and box.clickedButton() == update_now_btn:
confirm_update = QMessageBox(self)
confirm_update.setIcon(QMessageBox.Information)
confirm_update.setWindowTitle("Confirm Update")
confirm_update.setText("This may take some time....\nDo you want to continue?")
confirm_update.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
confirm_update.setDefaultButton(QMessageBox.No)
result = confirm_update.exec_()
if result == QMessageBox.Yes:
self.progress_dialog = QDialog(self)
self.progress_dialog.setWindowTitle("Updating Osdag")
layout = QVBoxLayout()
self.progress_label = QLabel("Updating, please wait...")
layout.addWidget(self.progress_label)
self.progress_text = QTextEdit()
self.progress_text.setReadOnly(True)
self.progress_text.verticalScrollBar().setValue(
self.progress_text.verticalScrollBar().maximum()
)
layout.addWidget(self.progress_text)
self.progress_dialog.setLayout(layout)
self.progress_dialog.setModal(True)
self.progress_dialog.setWindowFlags(self.progress_dialog.windowFlags() | Qt.WindowStaysOnTopHint)
self.progress_dialog.show()
self.updater.output_signal.connect(lambda text: self.progress_text.append(text))
self.updater.finished_signal.connect(self.handle_update_finished)
self.updater.update_to_latest()
# if update_status:
# QMessageBox.information(self, "Update", msg)
# else:
# QMessageBox.warning(self, "Update Failed", msg)
# elif loc == "FAQ":
# pass
def handle_update_finished(self,success, msg):
self.progress_dialog.close()
if success:
QMessageBox.information(self, "Update Completed", msg)
else:
QMessageBox.warning(self, "Update Failed", msg)
def select_workspace_folder(self):
# This function prompts the user to select the workspace folder and returns the name of the workspace folder
config = configparser.ConfigParser()
config.read_file(open(r'Osdag.config'))
desktop_path = config.get("desktop_path", "path1")
folder = QFileDialog.getExistingDirectory(self, "Select Workspace Folder (Don't use spaces in the folder name)", desktop_path)
return folder
@staticmethod
def UnderDevelopmentModule():
Page= ModulePage()
label=QLabel('This Module is Currently Under Development')
Page.layout.addWidget(label)
label.setAlignment(Qt.AlignCenter)
label.setObjectName('under_development_label')
return Page
def ButtonConnection(self,Button,Modules,ModuleName):
Button.ui.LP_Button.clicked.connect(lambda : self.ui.myStackedWidget.setCurrentIndex(Modules.index(ModuleName)+1))
#################################### Module Launchers ##########################################
@pyqtSlot()
def show_simple_connection(self):
if self.findChild(QRadioButton, 'Lap_Joint_Bolted').isChecked():
module_class =LapJointBolted # Import from simple_connection.py
elif self.findChild(QRadioButton, 'Lap_Joint_Welded').isChecked():
module_class = LapJointWelded # You might adjust parameters if needed
elif self.findChild(QRadioButton, 'Butt_Joint_Bolted').isChecked():
module_class = ButtJointBolted
elif self.findChild(QRadioButton, 'Butt_Joint_Welded').isChecked():
module_class = ButtJointWelded
else:
QMessageBox.about(self, "INFO", "Please select an appropriate variant")
return
# Launch the module's UI window using the corresponding design class.
self.hide()
self.ui2 = Ui_ModuleWindow(module_class, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
@pyqtSlot()
def show_shear_connection(self):
button_name_window_type_pairs = \
[("Fin_Plate", FinPlateConnection),
("Cleat_Angle", CleatAngleConnection),
("Seated_Angle", SeatedAngleConnection),
("End_Plate", EndPlateConnection),]
for (button_name, window_type) in button_name_window_type_pairs:
btn = self.findChild(QRadioButton, button_name)
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(window_type, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
QMessageBox.about(self, "INFO", "Please select appropriate connection")
def show_moment_connection(self):
button_name_window_type_pairs = \
[("B2B_Cover_Plate_Bolted", BeamCoverPlate),
("B2B_Cover_Plate_Welded", BeamCoverPlateWeld),
# ("B2B_End_Plate_Connection", BeamBeamEndPlateSplice),
("B2B_End_Plate_Splice", BeamBeamEndPlateSplice),]
for (button_name, window_type) in button_name_window_type_pairs:
btn = self.findChild(QRadioButton, button_name)
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(window_type, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
QMessageBox.about(self, "INFO", "Please select appropriate connection")
def show_moment_connection_bc(self):
btn = self.findChild(QRadioButton, "BC_End_Plate")
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(BeamColumnEndPlate, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
else:
QMessageBox.about(self, "INFO", "Please select appropriate connection")
def show_base_plate(self):
btn = self.findChild(QRadioButton, "Base_Plate")
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(BasePlateConnection, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
else:
QMessageBox.about(self, "INFO", "Please select appropriate connection")
def show_truss_bolted(self):
button_name_window_type_pairs = \
[
("Truss_Bolted", TrussConnectionBolted),
# ("Truss_Welded", BasePlateConnection),
]
for (button_name, window_type) in button_name_window_type_pairs:
btn = self.findChild(QRadioButton, button_name)
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(window_type, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
QMessageBox.about(self, "INFO", "Please select appropriate connection")
def show_moment_connection_cc(self):
button_name_window_type_pairs = \
[("C2C_Cover_Plate_Bolted", ColumnCoverPlate),
("C2C_Cover_Plate_Welded", ColumnCoverPlateWeld),
("C2C_End_Plate_Connection", ColumnEndPlate),]
for (button_name, window_type) in button_name_window_type_pairs:
btn = self.findChild(QRadioButton, button_name)
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(window_type, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
QMessageBox.about(self, "INFO", "Please select appropriate connection")
# def show_compression_module(self):
# # folder = self.select_workspace_folder()
# # folder = str(folder)
# # if not os.path.exists(folder):
# # if folder == '':
# # pass
# # else:
# # os.mkdir(folder, 0o755)
# #
# # root_path = folder
# # images_html_folder = ['images_html']
# # flag = True
# # for create_folder in images_html_folder:
# # if root_path == '':
# # flag = False
# # return flag
# # else:
# # try:
# # os.mkdir(os.path.join(root_path, create_folder))
# # except OSError:
# # shutil.rmtree(os.path.join(folder, create_folder))
# # os.mkdir(os.path.join(root_path, create_folder))
# if self.findChild(QRadioButton,'Compression_Bolted').isChecked():
# self.hide()
# self.ui2 = Ui_ModuleWindow(Compression, ' ')
# self.ui2.show()
# self.ui2.closed.connect(self.show)
#
# elif self.findChild(QRadioButton,'Compression_Welded').isChecked():
# self.hide()
# self.ui2 = Ui_ModuleWindow(Compression, ' ')
# self.ui2.show()
# self.ui2.closed.connect(self.show)
def show_tension_module(self):
button_name_window_type_pairs = \
[("Tension_Bolted", Tension_bolted),
("Tension_Welded", Tension_welded),]
for (button_name, window_type) in button_name_window_type_pairs:
btn = self.findChild(QRadioButton, button_name)
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(window_type, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
QMessageBox.about(self, "INFO", "Please select appropriate tension module")
def show_compression_module(self):
""" Create radio buttons for the sub-modules under the compression module"""
column_design_button = self.findChild(QRadioButton, 'Column_Design')
if column_design_button is not None and column_design_button.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(ColumnDesign, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
strut_design_button = self.findChild(QRadioButton, 'Strut_Design')
if strut_design_button is not None and strut_design_button.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(Compression, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
QMessageBox.about(self, "INFO", "Please select appropriate compression module")
def show_flexure_module(self):
""" Create radio buttons for the sub-modules under the compression module"""
button_name_window_type_pairs = \
[("Beam_flexure", Flexure),
("Beam_flexure2", Flexure_Cantilever),
("Beam_flexure3", Flexure_Misc),
("Beam_flexure4", Flexure_Purlin)]
for (button_name, window_type) in button_name_window_type_pairs:
btn = self.findChild(QRadioButton, button_name)
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(window_type, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
QMessageBox.about(self, "INFO", "Please select appropriate flexure module")
def show_beamcolumn_module(self):
btn = self.findChild(QRadioButton, "Beam_flexure")
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(Flexure, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
def show_girder_design(self):
btn = self.findChild(QRadioButton, "Welded_Girder_Design")
if btn is not None and btn.isChecked():
self.hide()
self.ui2 = Ui_ModuleWindow(PlateGirderWelded, ' ')
self.ui2.show()
self.ui2.closed.connect(self.show)
return
################################# Help Actions ############################################
def about_osdag(self):
dialog = MyAboutOsdag(self)
dialog.show()
def open_osdag(self):
self.about_osdag()
def tutorials(self):
dialog = MyTutorials(self)
dialog.show()
def open_tutorials(self):
self.tutorials()
def ask_question(self):
dialog = MyAskQuestion(self)
dialog.show()
def open_question(self):
self.ask_question()
def design_examples(self):
root_path = files('osdag.data.ResourceFiles.html_page._build').joinpath('html')
for html_file in os.listdir(root_path):
# if html_file.startswith('index'):
print(os.path.splitext(html_file)[1])
if os.path.splitext(html_file)[1] == '.html':
if sys.platform == ("win32" or "win64"):
os.startfile(os.path.join(root_path, html_file))
else:
opener ="open" if sys.platform == "darwin" else "xdg-open"
subprocess.call([opener, "%s/%s" % (root_path, html_file)])
def change_theme(self):
state = self.ui.switch.isChecked()
toggle_stylesheet(state)
# class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
#
# def __init__(self, icon, parent=None):
# QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
# self.parent = parent
# menu = QtWidgets.QMenu(self.parent)
# self.setContextMenu(menu)
# menu.addAction("Exit", self.exit)
#
#
# def exit(self):
# QCoreApplication.exit()
######################### UpDateNotifi ################
# class Update(QMainWindow):
# def __init__(self, old_version):
# super().__init__()
# self.old_version=old_version
# def notifi(self):
# try:
# url = "https://anshulsingh-py.github.io/test/version.txt"
# file = urllib.request.urlopen(url)
# for line in file:
# decoded_line = line.decode("utf-8")
# new_version = decoded_line.split("=")[1]
# if int(new_version) > self.old_version:
# print("update")
# msg = QMessageBox.information(self, 'Update available','<a href=https://google.com>Click to downlaod<a/>')
# except:
# print("No internet connection")
def toggle_stylesheet(state):
app = QApplication.instance()
if app is None:
raise RuntimeError("No Qt Application found.")
if state:
path = 'darkstyle.qss'
else:
path = 'light.qss'
theme_path = str(files("osdag.data.themes").joinpath(path))
file = QFile(theme_path)
file.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(file)
app.setStyleSheet(stream.readAll())
def hook_exception(exc_type, exc_value, tracebackobj):
instance = QApplication.instance()
# KeyboardInterrupt is a special case.
# We don't raise the error dialog when it occurs.
if issubclass(exc_type, KeyboardInterrupt):
if instance:
instance.closeAllWindows()
return
separator = '-' * 80
notice = \
"""An unhandled exception occurred. Please report the problem\n""" \
"""using the error reporting dialog or raise the issue to {}.\n""" \
"""\n\nError information:\n""".format('github.com/osdag-admin/Osdag')
time_string = time.strftime("%Y-%m-%d, %H:%M:%S")
tbinfofile = io.StringIO()
traceback.print_tb(tracebackobj, None, tbinfofile)
tbinfofile.seek(0)
tbinfo = tbinfofile.read()
errmsg = '%s: \n%s' % (str(exc_type), str(exc_value))
sections = [separator, time_string, separator, errmsg, separator, tbinfo]
msg = '\n'.join(sections)
error_box.text_edit.setText(str(notice) + str(msg))
error_box.titlebar.save_log.clicked.connect(save_log(str(notice)+str(msg)))
error_box.titlebar.report_issue.clicked.connect(send_crash_report)
error_box.setWindowModality(QtCore.Qt.ApplicationModal)
if not error_box.exec_():
instance.quit()
def save_log(log):
def save_():
file_type = "log (*.log)"
filename, _ = QFileDialog.getSaveFileName(QFileDialog(), "Save File As", '', file_type)
if filename:
with open(filename,'w') as file:
file.write(log)
QMessageBox.information(QMessageBox(), "Information", "Log saved successfully.")
return save_
def get_system_info():
return 'OS: %s\nPython: %r' % (sys.platform, sys.version_info)
def get_application_log():
return error_box.text_edit.toPlainText()
def send_crash_report():
appcrash.get_application_log = get_application_log
appcrash.get_system_information = get_system_info
appcrash.show_report_dialog()
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self, icon, parent=None):
QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
self.parent = parent
menu = QtWidgets.QMenu(self.parent)
self.setContextMenu(menu)
menu.addAction("Exit", self.exit)
def exit(self):
QCoreApplication.exit()
# FIXME: This is created in `do_stuff` and used above. Find better alternatives.
error_box = None
def do_stuff():
# from .cad.common_logic import CommonDesignLogic
from multiprocessing import Pool
import multiprocessing
# app = QApplication(sys.argv)
# screen = app.screens()[0]
# dpi = screen.physicalDotsPerInch()
# scale = round(dpi/140.0,1)
#
# print('scale', dpi, scale,scale*300)
path = str(files("osdag.data.themes").joinpath('light.qss'))
file = QFile(path)
file.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(file)
app = QApplication(sys.argv)
app.setStyleSheet(stream.readAll())
app.setStyle('Fusion')
# path = os.path.join(os.path.dirname(__file__), 'ResourceFiles', 'images', 'Osdag.png')
window = OsdagMainWindow()
# print("Here0")
# trayIcon = SystemTrayIcon(QtGui.QIcon(path), window)