idb 2.9.0 → 2.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +30 -0
- data/Gemfile.lock +5 -0
- data/idb.gemspec +1 -0
- data/lib/gui/app_binary_tab_widget.rb +7 -14
- data/lib/gui/app_details_group_box.rb +63 -88
- data/lib/gui/app_list_dialog.rb +29 -35
- data/lib/gui/app_list_widget_item.rb +1 -5
- data/lib/gui/app_tab_widget.rb +17 -22
- data/lib/gui/binary_strings_widget.rb +7 -15
- data/lib/gui/ca_manager_dialog.rb +32 -54
- data/lib/gui/cache_db_widget.rb +21 -26
- data/lib/gui/certificate_item.rb +2 -2
- data/lib/gui/default_protection_class_group_widget.rb +7 -12
- data/lib/gui/device_info_group_box.rb +26 -23
- data/lib/gui/main_tab_widget.rb +2 -21
- data/lib/gui/shared_libraries_widget.rb +1 -1
- data/lib/gui/sqlite_widget.rb +1 -3
- data/lib/gui/weak_class_dump_widget.rb +1 -1
- data/lib/idb.rb +3 -3
- data/lib/idb/version.rb +1 -1
- data/lib/lib/abstract_device.rb +7 -11
- data/lib/lib/app.rb +49 -59
- data/lib/lib/app_binary.rb +18 -29
- data/lib/lib/ca_interface.rb +46 -59
- data/lib/lib/device.rb +68 -155
- data/lib/lib/device_ca_interface.rb +7 -13
- data/lib/lib/host_file_wrapper.rb +6 -8
- data/lib/lib/ios8_last_launch_services_map_wrapper.rb +11 -18
- data/lib/lib/local_operations.rb +24 -32
- data/lib/lib/otool_wrapper.rb +30 -33
- data/lib/lib/rsync_git_manager.rb +26 -22
- data/lib/lib/screen_shot_util.rb +20 -28
- data/lib/lib/settings.rb +14 -17
- data/lib/lib/simulator.rb +11 -16
- data/lib/lib/simulator_ca_interface.rb +1 -3
- data/lib/lib/ssh_operations.rb +49 -65
- data/lib/lib/ssh_port_forwarder.rb +9 -13
- data/lib/lib/tools.rb +3 -3
- data/lib/lib/url_scheme_fuzzer.rb +41 -49
- data/lib/lib/usb_muxd_wrapper.rb +6 -8
- data/lib/lib/weak_class_dump_wrapper.rb +15 -16
- metadata +19 -9
- data/lib/gui/console_widget.rb +0 -163
- data/lib/gui/cycript_console_widget.rb +0 -68
- data/lib/gui/cycript_thread.rb +0 -81
- data/lib/lib/console_launcher.rb +0 -24
- data/lib/lib/i_device_diagnostics_wrapper.rb +0 -90
- data/lib/lib/snoop_it_wrapper.rb +0 -80
data/lib/gui/app_tab_widget.rb
CHANGED
@@ -4,46 +4,43 @@ module Idb
|
|
4
4
|
signals "app_changed()"
|
5
5
|
signals "binary_analyzed()"
|
6
6
|
|
7
|
-
def initialize
|
8
|
-
super
|
7
|
+
def initialize(*args)
|
8
|
+
super(*args)
|
9
9
|
|
10
10
|
@layout = Qt::GridLayout.new self
|
11
11
|
setLayout(@layout)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
@layout.addWidget @select_app_button, 0,0
|
13
|
+
@layout.addWidget @select_app_button, 0, 0
|
16
14
|
|
17
15
|
# Box for App details
|
18
16
|
@app_details = AppDetailsGroupBox.new @central_widget
|
19
|
-
@app_details.connect(SIGNAL(:show_device_status))
|
17
|
+
@app_details.connect(SIGNAL(:show_device_status)) do
|
20
18
|
@device_status = DeviceStatusDialog.new
|
21
19
|
@device_status.exec
|
22
|
-
|
20
|
+
end
|
23
21
|
|
24
|
-
|
25
|
-
@layout.addWidget @app_details, 0,0,2,1
|
22
|
+
@layout.addWidget @app_details, 0, 0, 2, 1
|
26
23
|
|
27
24
|
# Entitlements
|
28
25
|
@app_entitlements = AppEntitlementsGroupBox.new @central_widget
|
29
|
-
@layout.addWidget @app_entitlements, 2,0, 1, 2
|
26
|
+
@layout.addWidget @app_entitlements, 2, 0, 1, 2
|
30
27
|
|
31
28
|
# App Binary Details
|
32
29
|
@app_binary = AppBinaryGroupBox.new @central_widget
|
33
|
-
@layout.addWidget @app_binary, 0,1
|
34
|
-
@app_binary.connect(SIGNAL('binary_analyzed()'))
|
35
|
-
emit binary_analyzed
|
36
|
-
|
37
|
-
|
38
|
-
@spacer_horizontal = Qt::SpacerItem.new 0,1,
|
30
|
+
@layout.addWidget @app_binary, 0, 1
|
31
|
+
@app_binary.connect(SIGNAL('binary_analyzed()')) do
|
32
|
+
emit binary_analyzed
|
33
|
+
end
|
34
|
+
|
35
|
+
@spacer_horizontal = Qt::SpacerItem.new 0, 1,
|
36
|
+
Qt::SizePolicy::Expanding,
|
37
|
+
Qt::SizePolicy::Fixed
|
39
38
|
@layout.addItem @spacer_horizontal, 0, 3
|
40
39
|
|
41
|
-
@spacer = Qt::SpacerItem.new 0,1, Qt::SizePolicy::Fixed, Qt::SizePolicy::Expanding
|
42
|
-
@spacer2 = Qt::SpacerItem.new 0,1, Qt::SizePolicy::Fixed, Qt::SizePolicy::Expanding
|
40
|
+
@spacer = Qt::SpacerItem.new 0, 1, Qt::SizePolicy::Fixed, Qt::SizePolicy::Expanding
|
41
|
+
@spacer2 = Qt::SpacerItem.new 0, 1, Qt::SizePolicy::Fixed, Qt::SizePolicy::Expanding
|
43
42
|
|
44
43
|
@layout.addItem @spacer, 3, 0
|
45
|
-
|
46
|
-
|
47
44
|
end
|
48
45
|
|
49
46
|
def app_changed
|
@@ -51,8 +48,6 @@ module Idb
|
|
51
48
|
@app_details.app_changed
|
52
49
|
@app_entitlements.clear
|
53
50
|
@app_entitlements.app_changed
|
54
|
-
|
55
51
|
end
|
56
|
-
|
57
52
|
end
|
58
53
|
end
|
@@ -1,33 +1,25 @@
|
|
1
1
|
module Idb
|
2
2
|
class BinaryStringsWidget < Qt::Widget
|
3
|
-
|
4
|
-
|
5
|
-
super *args
|
3
|
+
def initialize(*args)
|
4
|
+
super(*args)
|
6
5
|
@layout = Qt::GridLayout.new
|
7
6
|
setLayout(@layout)
|
8
7
|
|
9
8
|
@details = Qt::PlainTextEdit.new
|
10
9
|
@details.setReadOnly(true)
|
11
10
|
|
12
|
-
|
13
11
|
@extract = Qt::PushButton.new "Extract Strings"
|
14
|
-
@extract.connect(SIGNAL
|
12
|
+
@extract.connect(SIGNAL(:released)) do
|
15
13
|
@details.clear
|
16
14
|
strings = $selected_app.strings
|
17
15
|
@details.appendPlainText(strings)
|
18
|
-
|
19
|
-
|
20
|
-
@layout.addWidget @details, 0,0
|
21
|
-
@layout.addWidget @extract, 1,0
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
end
|
25
17
|
|
18
|
+
@layout.addWidget @details, 0, 0
|
19
|
+
@layout.addWidget @extract, 1, 0
|
26
20
|
end
|
27
21
|
|
28
22
|
def refresh
|
29
|
-
|
30
23
|
end
|
31
|
-
|
32
24
|
end
|
33
|
-
end
|
25
|
+
end
|
@@ -1,17 +1,13 @@
|
|
1
1
|
require_relative 'certificate_item'
|
2
2
|
|
3
3
|
module Idb
|
4
|
-
|
5
4
|
class CAManagerDialog < Qt::Dialog
|
6
|
-
|
7
|
-
|
8
|
-
super *args
|
5
|
+
def initialize(*args)
|
6
|
+
super(*args)
|
9
7
|
@layout = Qt::GridLayout.new
|
10
8
|
setLayout(@layout)
|
11
9
|
setWindowTitle("CA Certificate Management")
|
12
10
|
|
13
|
-
|
14
|
-
|
15
11
|
@model = Qt::StandardItemModel.new
|
16
12
|
|
17
13
|
@selection_model = Qt::ItemSelectionModel.new @model
|
@@ -22,50 +18,46 @@ module Idb
|
|
22
18
|
@cert_tab.setSelectionModel(@selection_model)
|
23
19
|
|
24
20
|
@cert_tab.setSelectionBehavior(Qt::AbstractItemView::SelectRows)
|
25
|
-
@cert_tab.setEditTriggers(Qt::AbstractItemView::NoEditTriggers
|
26
|
-
|
21
|
+
@cert_tab.setEditTriggers(Qt::AbstractItemView::NoEditTriggers)
|
27
22
|
|
28
|
-
@selection_model.connect(SIGNAL('selectionChanged(QItemSelection,QItemSelection)'))
|
29
|
-
if x.indexes.length
|
23
|
+
@selection_model.connect(SIGNAL('selectionChanged(QItemSelection,QItemSelection)')) do |x, _|
|
24
|
+
if x.indexes.length.zero?
|
30
25
|
@delete_button.setEnabled(false)
|
31
26
|
else
|
32
27
|
@delete_button.setEnabled(true)
|
33
28
|
@selected_row = x.indexes[0].row
|
34
29
|
end
|
35
|
-
|
36
|
-
}
|
37
|
-
|
30
|
+
end
|
38
31
|
|
39
32
|
@refresh_button = Qt::PushButton.new "Refresh"
|
40
|
-
@refresh_button.connect(SIGNAL(:released))
|
33
|
+
@refresh_button.connect(SIGNAL(:released)) do |_x|
|
41
34
|
refresh_table
|
42
|
-
|
35
|
+
end
|
43
36
|
|
44
37
|
@delete_button = Qt::PushButton.new "Delete"
|
45
38
|
@delete_button.setEnabled(false)
|
46
|
-
@delete_button.connect(SIGNAL(:released))
|
39
|
+
@delete_button.connect(SIGNAL(:released)) do |_x|
|
47
40
|
item_containing_cert = @model.takeRow(@selected_row)[0]
|
48
|
-
|
41
|
+
unless item_containing_cert.nil?
|
49
42
|
@if.remove_cert item_containing_cert.certificate
|
50
43
|
end
|
51
44
|
refresh_table
|
52
|
-
|
53
|
-
|
45
|
+
end
|
54
46
|
|
55
47
|
@import_button = Qt::PushButton.new "Import..."
|
56
48
|
@import_button.setToolTip("Import an existing certificate")
|
57
|
-
@import_button.connect(SIGNAL(:released))
|
49
|
+
@import_button.connect(SIGNAL(:released)) do |_x|
|
58
50
|
@file_dialog = Qt::FileDialog.new
|
59
51
|
@file_dialog.setAcceptMode(Qt::FileDialog::AcceptOpen)
|
60
|
-
filters =
|
52
|
+
filters = []
|
61
53
|
filters << "PEM Files (*.pem)"
|
62
54
|
filters << "Any files (*)"
|
63
|
-
@file_dialog.setNameFilters(filters)
|
55
|
+
@file_dialog.setNameFilters(filters)
|
64
56
|
|
65
|
-
@file_dialog.connect(SIGNAL('fileSelected(QString)'))
|
57
|
+
@file_dialog.connect(SIGNAL('fileSelected(QString)')) do |x|
|
66
58
|
begin
|
67
59
|
@if.server_cert(x)
|
68
|
-
rescue
|
60
|
+
rescue StandardError => e
|
69
61
|
error = Qt::MessageBox.new self
|
70
62
|
error.setInformativeText("Couldn't import certificate")
|
71
63
|
error.setDetailedText(e.message)
|
@@ -73,33 +65,29 @@ module Idb
|
|
73
65
|
error.exec
|
74
66
|
end
|
75
67
|
refresh_table
|
76
|
-
|
77
|
-
|
78
|
-
|
68
|
+
end
|
79
69
|
|
80
70
|
@file_dialog.exec
|
81
|
-
|
71
|
+
end
|
82
72
|
|
83
73
|
@close_button = Qt::PushButton.new "Close"
|
84
|
-
@close_button.connect(SIGNAL(:released))
|
74
|
+
@close_button.connect(SIGNAL(:released)) do |_x|
|
85
75
|
@if.stop_cert_server
|
86
|
-
reject
|
87
|
-
|
76
|
+
reject
|
77
|
+
end
|
88
78
|
|
89
79
|
@layout.addWidget @cert_tab, 0, 0, 4, 4
|
90
80
|
@layout.addWidget @refresh_button, 0, 4
|
91
|
-
@layout.addWidget @delete_button, 1,4
|
92
|
-
@layout.addWidget @import_button, 2,4
|
93
|
-
|
81
|
+
@layout.addWidget @delete_button, 1, 4
|
82
|
+
@layout.addWidget @import_button, 2, 4
|
83
|
+
spacer_item = Qt::SpacerItem.new(0, 1, Qt::SizePolicy::Fixed, Qt::SizePolicy::Expanding)
|
84
|
+
@layout.addItem spacer_item, 3, 4
|
94
85
|
@layout.addWidget @close_button, 4, 4
|
95
86
|
|
96
87
|
@if = $device.ca_interface
|
97
88
|
refresh_table
|
98
89
|
|
99
|
-
|
100
|
-
|
101
|
-
#setFixedHeight(sizeHint().height());
|
102
|
-
setMinimumSize(800,500)
|
90
|
+
setMinimumSize(800, 500)
|
103
91
|
end
|
104
92
|
|
105
93
|
def refresh_table
|
@@ -108,30 +96,20 @@ module Idb
|
|
108
96
|
@model.setHorizontalHeaderItem(1, Qt::StandardItem.new("Expiry"))
|
109
97
|
@model.setHorizontalHeaderItem(2, Qt::StandardItem.new("Issuer"))
|
110
98
|
|
111
|
-
@if.
|
112
|
-
row =
|
113
|
-
item = CertificateItem.new(cert.subject.to_a.map { |x| "#{x[0]}: #{x[1]}"}.join("\n"))
|
99
|
+
@if.certs.each do |cert|
|
100
|
+
row = []
|
101
|
+
item = CertificateItem.new(cert.subject.to_a.map { |x| "#{x[0]}: #{x[1]}" }.join("\n"))
|
114
102
|
item.certificate = cert
|
115
103
|
row << item
|
116
104
|
row << Qt::StandardItem.new(cert.not_after.to_s)
|
117
|
-
row << Qt::StandardItem.new(cert.issuer.to_a.map { |x| "#{x[0]}: #{x[1]}"}.join("\n"))
|
105
|
+
row << Qt::StandardItem.new(cert.issuer.to_a.map { |x| "#{x[0]}: #{x[1]}" }.join("\n"))
|
118
106
|
@model.appendRow(row)
|
119
|
-
|
107
|
+
end
|
120
108
|
@cert_tab.resizeColumnsToContents
|
121
109
|
@cert_tab.resizeRowsToContents
|
122
110
|
|
123
|
-
|
124
111
|
# puts "#{i.to_s.ljust(2)} - Subject: #{cert.subject}"
|
125
112
|
# puts " Details: #{cert.inspect}"
|
126
|
-
|
127
|
-
|
128
|
-
|
129
113
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
114
|
end
|
136
|
-
|
137
|
-
end
|
115
|
+
end
|
data/lib/gui/cache_db_widget.rb
CHANGED
@@ -1,33 +1,27 @@
|
|
1
1
|
module Idb
|
2
2
|
class CacheDbWidget < Qt::Widget
|
3
|
-
|
4
|
-
|
5
|
-
super *args
|
3
|
+
def initialize(*args)
|
4
|
+
super(*args)
|
6
5
|
|
7
6
|
@refresh = Qt::PushButton.new "Refresh"
|
8
|
-
@refresh.connect(SIGNAL
|
7
|
+
@refresh.connect(SIGNAL(:released)) do
|
9
8
|
refresh
|
10
|
-
|
9
|
+
end
|
11
10
|
|
12
11
|
@list = Qt::ListWidget.new self
|
13
|
-
@list.connect(SIGNAL('itemDoubleClicked(QListWidgetItem*)'))
|
14
|
-
# x = ConsoleLauncher.new
|
15
|
-
#TODO: find sqlite binary
|
16
|
-
#x.run "/usr/bin/sqlite3 #{Dir.getwd}/#{$selected_app.cache_file item.full_path}"
|
17
|
-
|
12
|
+
@list.connect(SIGNAL('itemDoubleClicked(QListWidgetItem*)')) do |item|
|
18
13
|
cache_name = $selected_app.cache_file item.full_path
|
19
14
|
if cache_name.nil?
|
20
|
-
$log.error "File #{item.full_path} could not be downloaded. Either
|
15
|
+
$log.error "File #{item.full_path} could not be downloaded. Either" \
|
16
|
+
"the file does not exist (e.g., dead symlink) or there " \
|
17
|
+
"is a permission problem."
|
18
|
+
elsif RbConfig::CONFIG['host_os'] =~ /linux/
|
19
|
+
Process.spawn "'#{$settings['sqlite_editor']}' '#{cache_name}'"
|
21
20
|
else
|
22
|
-
|
23
|
-
Process.spawn "'#{$settings['sqlite_editor']}' '#{cache_name}'"
|
24
|
-
else
|
25
|
-
Process.spawn "open -a '#{$settings['sqlite_editor']}' '#{cache_name}'"
|
26
|
-
end
|
21
|
+
Process.spawn "open -a '#{$settings['sqlite_editor']}' '#{cache_name}'"
|
27
22
|
end
|
28
|
-
|
29
|
-
|
30
|
-
# "Launch app"
|
23
|
+
end
|
24
|
+
# "Launch app"
|
31
25
|
@default_protection = DefaultProtectionClassGroupWidget.new self
|
32
26
|
layout = Qt::VBoxLayout.new do |v|
|
33
27
|
v.add_widget(@default_protection)
|
@@ -55,22 +49,23 @@ module Idb
|
|
55
49
|
@list.setEnabled true
|
56
50
|
@default_protection.update
|
57
51
|
cache_dbs = $selected_app.find_cache_dbs
|
58
|
-
cache_dbs.each
|
52
|
+
cache_dbs.each do |full_path|
|
59
53
|
item = PathListWidgetItem.new
|
60
54
|
if $device.simulator?
|
61
|
-
item.setText full_path.sub($selected_app.app_dir,'')
|
55
|
+
item.setText full_path.sub($selected_app.app_dir, '')
|
62
56
|
else
|
63
57
|
pc = $device.protection_class full_path
|
64
58
|
if full_path.start_with? $selected_app.app_dir
|
65
|
-
|
59
|
+
stripped_app_dir_path = full_path.sub($selected_app.app_dir, '')
|
60
|
+
item.setText "[App Bundle]" + stripped_app_dir_path + " => " + pc.strip
|
66
61
|
elsif full_path.start_with? $selected_app.data_dir
|
67
|
-
|
62
|
+
stripped_data_dir_path = full_path.sub($selected_app.data_dir, '')
|
63
|
+
item.setText "[Data Dir]" + stripped_data_dir_path + " => " + pc.strip
|
68
64
|
end
|
69
65
|
end
|
70
66
|
item.full_path = full_path
|
71
67
|
@list.addItem item
|
72
|
-
|
68
|
+
end
|
73
69
|
end
|
74
|
-
|
75
70
|
end
|
76
|
-
end
|
71
|
+
end
|
data/lib/gui/certificate_item.rb
CHANGED
@@ -1,18 +1,16 @@
|
|
1
1
|
module Idb
|
2
|
-
|
3
2
|
class DefaultProtectionClassGroupWidget < Qt::GroupBox
|
4
|
-
|
5
|
-
|
6
|
-
super *args
|
3
|
+
def initialize(args)
|
4
|
+
super(*args)
|
7
5
|
|
8
6
|
setTitle "Default Data Protection"
|
9
7
|
|
10
8
|
@layout = Qt::GridLayout.new
|
11
|
-
label =
|
12
|
-
@val =
|
9
|
+
label = Qt::Label.new "<b>Default Data Protection</b>", self, 0
|
10
|
+
@val = Qt::Label.new "No default set in the entitlements of this app.", self, 0
|
13
11
|
@layout.addWidget label, 0, 0
|
14
12
|
@layout.addWidget @val, 0, 1
|
15
|
-
spacer_horizontal = Qt::SpacerItem.new 0,1, Qt::SizePolicy::Expanding, Qt::SizePolicy::Fixed
|
13
|
+
spacer_horizontal = Qt::SpacerItem.new 0, 1, Qt::SizePolicy::Expanding, Qt::SizePolicy::Fixed
|
16
14
|
@layout.addItem spacer_horizontal, 0, 2
|
17
15
|
|
18
16
|
setLayout @layout
|
@@ -22,15 +20,12 @@ module Idb
|
|
22
20
|
if $device.ios_version < 8
|
23
21
|
@val.setText "Only available for iOS 8+"
|
24
22
|
else
|
25
|
-
$selected_app.services_map.entitlements_by_bundle_id($selected_app.bundle_id).each
|
23
|
+
$selected_app.services_map.entitlements_by_bundle_id($selected_app.bundle_id).each do |x|
|
26
24
|
if x[0].to_s == "com.apple.developer.default-data-protection"
|
27
25
|
@val.setText x[1].to_s
|
28
26
|
end
|
29
|
-
|
27
|
+
end
|
30
28
|
end
|
31
|
-
|
32
29
|
end
|
33
|
-
|
34
30
|
end
|
35
31
|
end
|
36
|
-
|
@@ -5,60 +5,63 @@ module Idb
|
|
5
5
|
signals "disconnect()"
|
6
6
|
signals "connect_clicked()"
|
7
7
|
|
8
|
-
def initialize
|
9
|
-
super
|
8
|
+
def initialize(*args)
|
9
|
+
super(*args)
|
10
10
|
|
11
11
|
# details on selected app
|
12
12
|
@layout = Qt::GridLayout.new
|
13
13
|
setLayout(@layout)
|
14
14
|
setTitle "Selected Device"
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
device_label = "<b><font color='red'>Please select a device from the " \
|
17
|
+
"'Devices' menu or click 'Connect'.</font></b>"
|
18
|
+
@device = Qt::Label.new device_label, self, 0
|
19
|
+
@layout.addWidget @device, 0, 0, 2, 1
|
18
20
|
@connect = Qt::PushButton.new "Connect to USB/SSH device"
|
19
|
-
@connect.connect(SIGNAL(:released))
|
20
|
-
emit connect_clicked
|
21
|
-
|
22
|
-
@layout.addWidget @connect, 0,1,2,1
|
21
|
+
@connect.connect(SIGNAL(:released)) do
|
22
|
+
emit connect_clicked
|
23
|
+
end
|
24
|
+
@layout.addWidget @connect, 0, 1, 2, 1
|
23
25
|
end
|
24
26
|
|
25
27
|
def update_device
|
26
28
|
if $device.device?
|
27
29
|
@connect.hide
|
28
|
-
uname = $device.ops.execute("/bin/uname -a")
|
29
|
-
ssh_connection_info = ""
|
30
30
|
if $device.mode == "usb"
|
31
|
-
|
32
|
-
|
31
|
+
usb_mode_text = "<b>USB device:</b> Manually connect via SSH as " \
|
32
|
+
"#{$settings.ssh_username}@localhost:#{$device.usb_ssh_port}"
|
33
|
+
@device.setText usb_mode_text
|
33
34
|
else
|
34
|
-
|
35
|
+
ssh_mode_text = "<b>SSH device:</b> " \
|
36
|
+
"ssh://#{$settings.ssh_username}:[redacted]@" \
|
37
|
+
"#{$settings.ssh_host}:#{$settings.ssh_port}"
|
38
|
+
@device.setText ssh_mode_text
|
35
39
|
end
|
36
40
|
|
37
41
|
@status = Qt::PushButton.new "Status"
|
38
|
-
@status.connect(SIGNAL(:released))
|
42
|
+
@status.connect(SIGNAL(:released)) do
|
39
43
|
@device_status = DeviceStatusDialog.new
|
40
44
|
@device_status.exec
|
41
|
-
|
45
|
+
end
|
42
46
|
@layout.addWidget @status, 0, 1
|
43
47
|
|
44
48
|
@disconnect = Qt::PushButton.new "Disconnect"
|
45
|
-
@disconnect.connect(SIGNAL(:released))
|
49
|
+
@disconnect.connect(SIGNAL(:released)) do
|
46
50
|
$device.close unless $device.nil?
|
47
51
|
$device = nil
|
48
|
-
emit disconnect
|
52
|
+
emit disconnect
|
49
53
|
@disconnect.hide
|
50
54
|
@connect.show
|
51
55
|
@status.hide
|
52
|
-
|
53
|
-
|
56
|
+
device_selection_text = "<b><font color='red'>Please select a device " \
|
57
|
+
"from the 'Devices' menu.</font></b>"
|
58
|
+
@device.setText(device_selection_text)
|
59
|
+
end
|
54
60
|
@layout.addWidget @disconnect, 1, 1
|
55
61
|
|
56
|
-
|
57
62
|
else
|
58
63
|
@device.setText "<b>Simulator:</b> #{$device.sim_dir}"
|
59
64
|
end
|
60
65
|
end
|
61
|
-
|
62
|
-
|
63
66
|
end
|
64
|
-
end
|
67
|
+
end
|