Initial chess engine support
[kaya.git] / lib / mainwindow.rb
blob96beb1bfe5524b5eff888deeb6a33b068520d96c
1 require 'qtutils'
2 require 'board/board'
3 require 'board/pool'
4 require 'board/table'
5 require 'board/scene'
6 require 'history'
7 require 'controller'
9 require 'interaction/match'
11 require 'ics/protocol'
12 require 'ics/match_handler'
13 require 'ics/connection'
14 require 'console'
16 require 'filewriter'
17 require 'newgame'
19 class MainWindow < KDE::XmlGuiWindow
20   include ActionHandler
21   include FileWriter
23   def initialize(loader, game)
24     super nil
25     
26     @loader = loader
27     @default_game = game
28     
29     startup
30     setup_actions
31     setupGUI
32     new_game(Match.new(game))
33   end
35 private
37   def setup_actions
38     std_action(:open_new) do
39       action = lambda do |game|
40         new_game(Match.new(game))
41       end
42       diag = NewGame.new(self, action)
43       diag.show
44     end
45     std_action(:open) { load_game }
46     std_action :quit, :slot => :close
47     std_action(:save) { save_game }
48     std_action(:saveAs) { save_game_as }
49     
50     regular_action :back, :icon => 'go-previous', 
51                           :text => KDE.i18n("B&ack") do
52       @controller.back
53     end
54     regular_action :forward, :icon => 'go-next', 
55                              :text => KDE.i18n("&Forward") do
56       @controller.forward
57     end
58     regular_action :connect, :icon => 'network-connect',
59                              :text => KDE.i18n("&Connect to ICS") do
60       connect_to_ics
61     end
62     regular_action :disconnect, :icon => 'network-disconnect',
63                                 :text => KDE.i18n("&Disconnect from ICS") do
64       if @connection
65         @connection.close
66         @connection = nil
67       end
68     end
69     
70     regular_action :flip, :icon => 'object-rotate-left',
71                           :text => KDE.i18n("F&lip") do
72       @table.flip(! @table.flipped?)
73     end
74   end
75   
76   def startup
77     scene = Scene.new
78     @table = Table.new scene, @loader, self
79     @controller = Controller.new(@table)
80     @table.observe(:reset) do |match|
81       update_game_actions(match)
82     end
84     movelist = @loader.get_matching(:movelist).new(@controller)
85     movelist_dock = Qt::DockWidget.new(self)
86     movelist_dock.widget = movelist
87     movelist_dock.window_title = KDE.i18n("History")
88     movelist_dock.object_name = "movelist"
89     add_dock_widget(Qt::LeftDockWidgetArea, movelist_dock, Qt::Vertical)
90     movelist_dock.show
92     @console = Console.new(nil)
93     console_dock = Qt::DockWidget.new(self)                                                      
94     console_dock.widget = @console                                                             
95     console_dock.focus_proxy = @console                                                        
96     console_dock.window_title = KDE.i18n("Console")                                              
97     console_dock.object_name = "console"                                                         
98     add_dock_widget(Qt::BottomDockWidgetArea, console_dock, Qt::Horizontal)                      
99     console_dock.window_flags = console_dock.window_flags & ~Qt::WindowStaysOnTopHint            
100     console_dock.show
101     
102     self.central_widget = @table
103   end
104   
105   def connect_to_ics
106     protocol = ICS::Protocol.new(:debug)
107     @connection = ICS::Connection.new('freechess.org', 23)
108     protocol.add_observer ICS::AuthModule.new(@connection, 'ujjajja', '')
109     protocol.add_observer ICS::StartupModule.new(@connection)
110     protocol.link_to @connection
112     protocol.observe :text do |text|
113       @console.append(text)
114     end
116     @console.observe :input do |text|
117       @connection.send_text text
118     end
120     handler = ICS::MatchHandler.new(@controller, protocol)
122     @connection.start
123   end
124   
125   def new_game(match)
126     setup_single_player(match)
127     @controller.reset(match)
128   end
129   
130   def setup_single_player(match)
131     @controller.color = match.game.players.first
132     opponents = match.game.players[1..-1].map do |color|
133       DummyPlayer.new(color)
134     end
135     opponents.each do |p| 
136       @controller.add_controlled_player(p)
137     end
139     @controller.controlled.values.each do |p|
140       match.register(p)
141     end
142     @controller.controlled.values.each do |p|
143       match.start(p)
144     end
145   end
146   
147   def load_game
148     url = KDE::FileDialog.get_open_url(KDE::Url.new, '*.*', self,
149       KDE.i18n("Open game"))
150     unless url.is_empty
151       # find readers
152       ext = File.extname(url.path)[1..-1]
153       return unless ext
154       readers = Game.to_enum.find_all do |_, game|
155         game.respond_to?(:game_extensions) and
156         game.game_extensions.include?(ext)
157       end.map do |_, game|
158         [game, game.game_reader]
159       end
160       
161       if readers.empty?
162         warn "Unknown file extension #{ext}"
163         return
164       end
165       
166       tmp_file = ""
167       return unless KIO::NetAccess.download(url, tmp_file, self)
169       history = nil
170       game = nil
171       info = nil
172       
173       readers.each do |g, reader|
174         begin
175           data = File.open(tmp_file) do |f|
176             f.read
177           end
178           i = {}
179           history = reader.read(data, i)
180           game = g
181           info = i
182           break
183         rescue ParseException
184         end
185       end
186       
187       unless history
188         warn "Could not load file #{url.path}"
189         return
190       end
191       
192       # create game
193       match = Match.new(game)
194       setup_single_player(match)
195       match.history = history
196       match.add_info(info)
197       match.url = url
198       @controller.reset(match)
199     end
200   end
201   
202   def save_game_as
203     match = @controller.match
204     if match
205       pattern = if match.game.respond_to?(:game_extensions)
206         match.game.game_extensions.map{|ext| "*.#{ext}"}.join(' ')
207       else
208         '*.*'
209       end
210       url = KDE::FileDialog.get_save_url(
211         KDE::Url.new, pattern, self, KDE.i18n("Save game"))
212       match.url = write_game(url)
213     end
214   end
215   
216   def save_game
217     match = @controller.match
218     if match
219       if match.url
220         write_game
221       else
222         save_game_as
223       end
224     end
225   end
226   
227   def write_game(url = nil)
228     match = @controller.match
229     if match
230       url ||= match.url
231       writer = match.game.game_writer
232       info = match.info
233       info[:players] = info[:players].inject({}) do |res, pl|
234         res[pl.color] = pl.name
235         res
236       end
237       result = writer.write(info, match.history)
238       write_file(url, result)
239     end
240   end
241   
242   def update_game_actions(match)
243     unplug_action_list('game_actions')
244     actions = if match.game.respond_to?(:actions)
245       match.game.actions(self, action_collection, @controller.policy)
246     else
247       []
248     end
249     plug_action_list('game_actions', actions)
250   end
253 class DummyPlayer
254   include Observer
255   include Player
256   
257   attr_reader :color
258   attr_accessor :name
259   
260   def initialize(color)
261     @color = color
262   end