win_gui 0.2.3 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -17,3 +17,11 @@
17
17
  == 0.2.3 / 2010-06-03
18
18
 
19
19
  * Minor cleanup/refactoring
20
+
21
+ == 0.2.4 / 2010-06-03
22
+
23
+ * Unified interface for Window.top_level and Window#child
24
+
25
+ == 0.2.5 / 2010-06-04
26
+
27
+ * Code brought to about Book-level quality
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.3
1
+ 0.2.5
@@ -2,75 +2,75 @@ module WinGui
2
2
 
3
3
  # This class is a wrapper around window handle
4
4
  class Window
5
- # Make convenience methods from both WinGui and Win::Gui available as both class and instance methods
6
- # Looks a bit circular though...
7
- # include WinGui
8
- # extend WinGui
9
5
 
10
6
  def initialize(handle)
11
7
  @handle = handle
8
+ # puts "Window #{handle} created "
9
+ # p self.class.ancestors
12
10
  end
13
11
 
14
12
  attr_reader :handle
15
13
 
16
- # Finds top level window by title/class, returns wrapped Window object or nil.
17
- # If timeout option given, waits for window to appear within timeout, returns nil if it didn't
18
- # Options:
19
- # :title:: window title
20
- # :class:: window class
21
- # :timeout:: timeout (seconds)
22
- def self.top_level(opts={})
23
- window_title = opts[:title]
24
- window_class = opts[:class]
25
- timeout = opts[:timeout] # || LOOKUP_TIMEOUT ? # no timeout by default
26
-
27
- if timeout
14
+ # Looks up window handle using code specified in attached block (either with or without :timeout)
15
+ # Returns either Window instance (for a found handle) or nil if nothing found
16
+ # Private method to dry up other window lookup methods
17
+ # :yields:
18
+ #
19
+ def self.lookup_window(opts)
20
+ # Need this to avoid handle considered local in begin..end block
21
+ handle = yield
22
+ if opts[:timeout]
28
23
  begin
29
- timeout(timeout) do
30
- sleep SLEEP_DELAY while (@handle = WinGui.find_window window_class, window_title) == nil
24
+ timeout(opts[:timeout]) do
25
+ sleep SLEEP_DELAY until handle = yield
31
26
  end
32
27
  rescue TimeoutError
33
28
  nil
34
29
  end
35
- else
36
- @handle = WinGui.find_window window_class, window_title
37
30
  end
38
- Window.new(@handle) if @handle
31
+ raise opts[:raise] if opts[:raise] && !handle
32
+ Window.new(handle) if handle
39
33
  end
40
34
 
41
- # find child window (control) by title, window class, or control ID:
42
- def child(id)
43
- result = case id
44
- when String
45
- by_title = find_window_ex 0, nil, id.gsub('_', '&' )
46
- by_class = find_window_ex 0, id, nil
47
- by_title ? by_title : by_class
48
- when Fixnum
49
- get_dlg_item id
50
- when nil
51
- find_window_ex 0, nil, nil
52
- else
53
- nil
35
+ # Find top level window by title/class, returns wrapped Window object or nil.
36
+ # If timeout option given, waits for window to appear within timeout, returns nil if it didn't
37
+ # Options:
38
+ # :title:: window title
39
+ # :class:: window class
40
+ # :timeout:: timeout (seconds)
41
+ def self.top_level(opts={})
42
+ lookup_window(opts) { WinGui.find_window opts[:class], opts[:title] }
43
+ end
44
+
45
+ # Find DIRECT child window (control) by either control ID or window class/title.
46
+ def child(opts={})
47
+ self.class.lookup_window(opts) do
48
+ opts[:id] ? get_dlg_item(opts[:id]) : find_window_ex(0, opts[:class], opts[:title])
54
49
  end
55
- raise "Control '#{id}' not found" unless result
56
- Window.new result
57
50
  end
58
51
 
59
- # returns array of Windows that are descendants (not only DIRECT children) of a given Window
52
+ # Return array of Windows that are descendants (not only DIRECT children) of a given Window
60
53
  def children
61
54
  enum_child_windows.map{|child_handle| Window.new child_handle}
62
55
  end
63
56
 
64
- # emulate click of the control identified by id
65
- def click(id)
66
- left, top, right, bottom = child(id).get_window_rect
67
- center = [(left + right) / 2, (top + bottom) / 2]
68
- WinGui.set_cursor_pos *center
69
- WinGui.mouse_event WinGui::MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
70
- WinGui.mouse_event WinGui::MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
57
+ # Emulate click of the control identified by opts (:id, :title, :class)
58
+ # Return true if click was presumably successful, false if it failed (control was not found)
59
+ def click(opts={})
60
+ control = child(opts)
61
+ if control
62
+ left, top, right, bottom = control.get_window_rect
63
+ center = [(left + right) / 2, (top + bottom) / 2]
64
+ WinGui.set_cursor_pos *center
65
+ WinGui.mouse_event WinGui::MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
66
+ WinGui.mouse_event WinGui::MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
67
+ true
68
+ else
69
+ false
70
+ end
71
71
  end
72
72
 
73
- def wait_for_close(timeout =CLOSE_TIMEOUT )
73
+ def wait_for_close(timeout=CLOSE_TIMEOUT )
74
74
  timeout(timeout) do
75
75
  sleep SLEEP_DELAY while window_visible?
76
76
  end
@@ -97,7 +97,8 @@ module WinGui
97
97
  # WinGui.function(*args)
98
98
  def method_missing(name, *args, &block)
99
99
  if WinGui.respond_to? name
100
- WinGui.send(name, @handle, *args, &block)
100
+ # puts "Window #{@handle} calling: #{name} #{@handle} #{args} &#{block}"
101
+ WinGui.send(name, @handle, *args, &block)
101
102
  else
102
103
  super
103
104
  end
data/lib/win_gui.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'version'
2
- require 'extension'
1
+ require_relative 'version'
2
+ require_relative 'extension'
3
3
 
4
4
  module WinGui
5
5
 
data/spec/spec_helper.rb CHANGED
@@ -75,7 +75,10 @@ module WinGuiTest
75
75
  while @test_app && find_window(nil, WIN_TITLE)
76
76
  @test_app.close
77
77
  # Dealing with closing confirmation modal dialog
78
- keystroke("N") if Window.top_level( title: "Steganos Locknote", timeout: SLEEP_DELAY*5)
78
+ if dialog = dialog( title: "Steganos Locknote", timeout: SLEEP_DELAY)
79
+ dialog.set_foreground_window
80
+ keystroke("N")
81
+ end
79
82
  end
80
83
  @test_app = nil
81
84
  end
@@ -87,4 +90,22 @@ module WinGuiTest
87
90
  close_test_app
88
91
  end
89
92
 
93
+ def with_dialog(type=:close)
94
+ case type
95
+ when :close
96
+ keystroke('A')
97
+ @app.close
98
+ title, key = "Steganos Locknote", "N"
99
+ when :save
100
+ keystroke(VK_ALT, 'F', 'A')
101
+ title, key = "Save As", VK_ESCAPE
102
+ end
103
+ sleep 0.01 until dialog = Window.top_level(title: title)
104
+ yield dialog
105
+ while dialog.window?
106
+ dialog.set_foreground_window
107
+ keystroke(key)
108
+ sleep 0.01
109
+ end
110
+ end
90
111
  end
@@ -7,38 +7,43 @@ module WinGuiTest
7
7
  after(:each) { close_test_app }
8
8
 
9
9
  describe '#dialog' do
10
- # Open "Save as" modal dialog
11
- before(:each){ keystroke(VK_ALT, 'F', 'A') }
12
- # Close modal dialog if it is opened
13
- after(:each) { keystroke(VK_ESCAPE) if Window.top_level( title: "Save As", timeout: 0.1) }
14
-
15
10
  it 'returns top-level dialog window with given title if no block attached' do
16
- dialog_window = dialog(title: DIALOG_TITLE, timeout: 0.1)
17
- dialog_window.should_not == nil
18
- dialog_window.should be_a Window
19
- dialog_window.text.should == DIALOG_TITLE
20
- end
21
-
22
- it 'yields found dialog window to block if block is attached' do
23
- dialog(title: DIALOG_TITLE) do |dialog_window|
11
+ with_dialog(:save) do
12
+ dialog_window = dialog(title: DIALOG_TITLE, timeout: 0.1)
24
13
  dialog_window.should_not == nil
25
14
  dialog_window.should be_a Window
26
15
  dialog_window.text.should == DIALOG_TITLE
27
16
  end
28
17
  end
29
18
 
19
+ it 'yields found dialog window to block if block is attached' do
20
+ with_dialog(:save) do
21
+ dialog(title: DIALOG_TITLE) do |dialog_window|
22
+ dialog_window.should_not == nil
23
+ dialog_window.should be_a Window
24
+ dialog_window.text.should == DIALOG_TITLE
25
+ end
26
+ end
27
+ end
28
+
30
29
  it 'returns nil if there is no dialog with given title' do
31
- dialog(title: IMPOSSIBLE, timeout: 0.1).should == nil
30
+ with_dialog(:save) do
31
+ dialog(title: IMPOSSIBLE, timeout: 0.1).should == nil
32
+ end
32
33
  end
33
34
 
34
35
  it 'yields nil to attached block if no dialog found' do
35
- dialog(title: IMPOSSIBLE, timeout: 0.1) do |dialog_window|
36
- dialog_window.should == nil
36
+ with_dialog(:save) do
37
+ dialog(title: IMPOSSIBLE, timeout: 0.1) do |dialog_window|
38
+ dialog_window.should == nil
39
+ end
37
40
  end
38
41
  end
39
42
 
40
43
  it 'considers all arguments optional' do
41
- use { dialog_window = dialog() }
44
+ with_dialog(:save) do
45
+ use { dialog_window = dialog() }
46
+ end
42
47
  end
43
48
  end # describe dialog
44
49
 
@@ -64,6 +69,5 @@ module WinGuiTest
64
69
  end # describe '#type_in'
65
70
 
66
71
  end # Input methods
67
-
68
- end
72
+ end # Convenience methods
69
73
  end
@@ -85,35 +85,75 @@ module WinGuiTest
85
85
  Window.top_level( title: IMPOSSIBLE, timeout: 0.5).should == nil
86
86
  (Time.now - start).should be_close 0.5, 0.02
87
87
  end
88
- end
88
+
89
+ it 'raises exception if asked to' do
90
+ expect{ Window.top_level( title: IMPOSSIBLE, raise: "Horror!")}.to raise_error "Horror!"
91
+ end
92
+ end # describe .top_level
89
93
 
90
94
  describe '#child' do
91
- spec { use { @control = @app.child(title_class_id = nil) }}
95
+ spec { use { @child = @app.child(title: "Title", class: "Class", id: 0) }}
92
96
 
93
- it 'finds any child window(control) if given nil' do
94
- @app.child(nil).should_not == nil
97
+ it 'returns nil immediately if specific child not found' do
98
+ start = Time.now
99
+ @app.child( title: IMPOSSIBLE).should == nil
100
+ (Time.now - start).should be_close 0, 0.02
95
101
  end
96
102
 
97
- it 'finds child window(control) by class' do
98
- @app.child(TEXTAREA_CLASS).should_not == nil
103
+ it 'returns nil after timeout if specific child not found' do
104
+ start = Time.now
105
+ @app.child( title: IMPOSSIBLE, timeout: 0.5).should == nil
106
+ (Time.now - start).should be_close 0.5, 0.02
99
107
  end
100
108
 
101
- it 'finds child window(control) by name' do
102
- pending 'Need to find control with short name'
103
- @app.child(TEXTAREA_TEXT).should_not == nil
109
+ it 'finds ANY child window without args' do
110
+ use { @child = @app.child() }
111
+ @child.should_not == nil
112
+ @app.child?(@child.handle).should == true
104
113
  end
105
114
 
106
- it 'finds child window(control) by control ID' do
107
- pending 'Need to find some control ID'
108
- @app.child(TEXTAREA_ID).should_not == nil
115
+ it 'finds child window by class and returns it as a Window object (no timeout)' do
116
+ child = @app.child( class: TEXTAREA_CLASS)
117
+ child.should_not == nil
118
+ @app.child?(child.handle).should == true
109
119
  end
110
120
 
111
- it 'raises error if wrong control is given' do
112
- expect { @app.child('Impossible Control')}.to raise_error "Control 'Impossible Control' not found"
121
+ it 'finds child window by class and returns it as a Window object (with timeout)' do
122
+ # p @app.find_window_ex(0, TEXTAREA_CLASS, nil)
123
+ # p @app.find_window_ex(0, STATUSBAR_CLASS, nil)
124
+ child = @app.child( class: TEXTAREA_CLASS, timeout: 0.5)
125
+ child.should_not == nil
126
+
127
+ @app.child?(child.handle).should == true
128
+ child = @app.child( class: STATUSBAR_CLASS, timeout: 0.5)
129
+ child.should_not == nil
130
+ @app.child?(child.handle).should == true
113
131
  end
114
132
 
115
- it 'substitutes & for _ when searching by title ("&Yes" type controls)' # Why?
116
- end
133
+ it 'finds child with specific text and returns it as a Window object' do
134
+ with_dialog(:save) do |dialog|
135
+ # @dialog.children.each{|child| puts "#{child.handle}, #{child.class_name}, #{child.window_text}"}
136
+ child = dialog.child( title: "Cancel")
137
+ child.should_not == nil
138
+ dialog.child?(child.handle).should == true
139
+ child.get_dlg_ctrl_id.should == IDCANCEL
140
+
141
+ child = dialog.child( title: "&Save")
142
+ child.should_not == nil
143
+ dialog.child?(child.handle).should == true
144
+ child.get_dlg_ctrl_id.should == IDOK
145
+ end
146
+ end
147
+
148
+ it 'finds child control with a given ID and returns it as a Window object' do
149
+ with_dialog(:save) do |dialog|
150
+ child = dialog.child( id: IDCANCEL)
151
+ child.should_not == nil
152
+ dialog.child?(child.handle).should == true
153
+ child.text.should == "Cancel"
154
+ end
155
+ end
156
+ end # describe child
117
157
 
118
158
  describe '#children' do
119
159
  spec { use { children = @app.children }}
@@ -126,26 +166,33 @@ module WinGuiTest
126
166
  children.each{|child| child?(@app.handle, child.handle).should == true }
127
167
  children.last.class_name.should == TEXTAREA_CLASS
128
168
  end
169
+ end # describe #children
129
170
 
130
- # it 'finds child window(control) by name' do
131
- # pending 'Need to find control with short name'
132
- # @app.child(TEXTAREA_TEXT).should_not == nil
133
- # end
134
- #
135
- # it 'finds child window(control) by control ID' do
136
- # pending 'Need to find some control ID'
137
- # @app.child(TEXTAREA_ID).should_not == nil
138
- # end
139
- #
140
- # it 'raises error if wrong control is given' do
141
- # expect { @app.child('Impossible Control')}.to raise_error "Control 'Impossible Control' not found"
142
- # end
143
- # it 'substitutes & for _ when searching by title ("&Yes" type controls)'
171
+ describe '#click' do
172
+ it 'emulates clicking of the control identified by id, returns true' do
173
+ with_dialog(:save) do |dialog|
174
+ dialog.click(id: IDCANCEL).should == true
175
+ sleep 0.5
176
+ dialog.window?.should == false
177
+ end
178
+ end
144
179
 
145
- end
180
+ it 'emulates clicking of the control identified by title, returns true' do
181
+ with_dialog(:save) do |dialog|
182
+ dialog.click(title: "Cancel").should == true
183
+ sleep 0.5
184
+ dialog.window?.should == false
185
+ end
186
+ end
146
187
 
147
- context '#click' do
148
- it 'emulates clicking of the control identified by id'
149
- end
188
+ it 'returns false if the specified control was not found' do
189
+ with_dialog(:save) do |dialog|
190
+ dialog.click(title: "Shpancel").should == false
191
+ dialog.click(id: 66).should == false
192
+ sleep 0.5
193
+ dialog.window?.should == true
194
+ end
195
+ end
196
+ end # describe #click
150
197
  end
151
198
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 3
9
- version: 0.2.3
8
+ - 5
9
+ version: 0.2.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - arvicco
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-03 00:00:00 +04:00
17
+ date: 2010-06-04 00:00:00 +04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency