1 # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
13 require 'interaction/history'
15 require 'dummy_player'
17 require 'interaction/match'
23 require 'engine_prefs'
31 class MainWindow < KDE::XmlGuiWindow
38 def initialize(loader, game)
42 @theme_loader = @loader.get_matching(:theme_loader).new
44 @factories = Hash.new do |h, interface|
45 @loader.get_matching(interface)
47 @factories[:table] = Factory.new do |parent|
48 Table.new(Scene.new, @loader, @theme_loader, parent)
50 @factories[:controller] = Factory.new do |parent|
51 Controller.new(parent, @field).tap do |c|
52 c.on(:changed_active_actions) do
53 update_active_actions(c)
56 update_game_actions(c)
65 new_game(Match.new(game), :new_tab => false)
71 controller.match.close
77 @view.current.controller
84 regular_action(:open_new,
85 :icon => 'document-new',
86 :text => KDE::i18n("&New..."),
87 :shortcut => KDE::std_shortcut(:new),
88 :tooltip => KDE::i18n("Start a new game...")) do
93 :icon => 'document-open',
94 :text => KDE::i18n("&Load..."),
95 :shortcut => KDE::std_shortcut(:open),
96 :tooltip => KDE::i18n("Open a saved game...")) do
100 regular_action(:quit,
101 :icon => 'application-exit',
102 :text => KDE::i18n("&Quit"),
103 :shortcut => KDE::std_shortcut(:quit),
104 :tooltip => KDE::i18n("Quit the program")) do
108 regular_action(:save,
109 :icon => 'document-save',
110 :text => KDE::i18n("&Save"),
111 :shortcut => KDE::std_shortcut(:save),
112 :tooltip => KDE::i18n("Save the current game")) do
116 regular_action(:save_as,
117 :icon => 'document-save-as',
118 :text => KDE::i18n("Save &As..."),
119 :tooltip => KDE::i18n("Save the current game to another file")) do
123 @actions[:back] = regular_action :back, :icon => 'go-previous',
124 :text => KDE.i18n("B&ack") do
127 @actions[:forward] = regular_action :forward, :icon => 'go-next',
128 :text => KDE.i18n("&Forward") do
132 regular_action :flip, :icon => 'object-rotate-left',
133 :text => KDE.i18n("F&lip") do
134 table = @view.current.table
135 table.flip(!table.flipped?)
138 regular_action :configure_engines,
139 :icon => 'help-hint',
140 :text => KDE.i18n("Configure &Engines...") do
141 dialog = EnginePrefs.new(@engine_loader, self)
145 regular_action :configure_themes,
146 :icon => 'games-config-theme',
147 :text => KDE.i18n("Configure &Themes...") do
148 dialog = ThemePrefs.new(@loader, @theme_loader, self)
149 dialog.on(:ok) { controller.reset }
153 @actions[:undo] = regular_action(:undo,
154 :icon => 'edit-undo',
155 :text => KDE::i18n("Und&o"),
156 :shortcut => KDE::std_shortcut(:undo),
157 :tooltip => KDE::i18n("Undo the last history operation")) do
161 @actions[:redo] = regular_action(:redo,
162 :icon => 'edit-redo',
163 :text => KDE::i18n("Re&do"),
164 :shortcut => KDE::std_shortcut(:redo),
165 :tooltip => KDE::i18n("Redo the last history operation")) do
170 def load_action_providers
171 @loader.get_all_matching(:action_provider).each do |provider_klass|
172 provider = provider_klass.new
173 ActionProviderClient.new(self, provider)
178 @field = AnimationField.new(20)
180 movelist_stack = Qt::StackedWidget.new(self)
181 movelist_dock = Qt::DockWidget.new(self)
182 movelist_dock.widget = movelist_stack
183 movelist_dock.window_title = KDE.i18n("History")
184 movelist_dock.object_name = "movelist"
185 add_dock_widget(Qt::LeftDockWidgetArea, movelist_dock, Qt::Vertical)
187 action_collection[:toggle_history] = movelist_dock.toggle_view_action
189 @view = MultiView.new(self, movelist_stack, @factories)
190 @view.create(:name => game.class.plugin_name)
191 @view.on(:changed) do
192 update_active_actions(controller)
194 update_game_actions(controller)
200 @engine_loader = @loader.get_matching(:engine_loader).new
201 @engine_loader.reload
203 @console = Console.new(nil)
204 console_dock = Qt::DockWidget.new(self)
205 console_dock.widget = @console
206 console_dock.focus_proxy = @console
207 console_dock.window_title = KDE.i18n("Console")
208 console_dock.object_name = "console"
209 add_dock_widget(Qt::BottomDockWidgetArea, console_dock, Qt::Horizontal)
210 console_dock.window_flags = console_dock.window_flags & ~Qt::WindowStaysOnTopHint
212 action_collection[:toggle_console] = console_dock.toggle_view_action
214 self.status_bar = StatusBar.new(self)
216 self.central_widget = @view
219 def new_game(match, opts = { })
220 setup_single_player(match)
221 controller.reset(match)
224 def setup_single_player(match)
225 controller.color = match.game.players.first
226 controller.premove = false
227 opponents = match.game.players[1..-1].map do |color|
228 DummyPlayer.new(color)
230 opponents.each do |p|
231 controller.add_controlled_player(p)
234 controller.controlled.values.each do |p|
237 controller.controlled.values.each do |p|
242 def create_game(opts = { })
243 current_game = if controller.match
244 controller.match.game
246 diag = NewGame.new(self, @engine_loader, current_game)
247 diag.on(:ok) do |data|
249 match = Match.new(game, :editable => data[:engines].empty?)
251 @view.create(:activate => true,
253 :name => game.class.plugin_name)
255 @view.set_tab_text(@view.index, game.class.plugin_name)
261 match.on(:started) do
265 # set up engine players
266 players = game.players
267 data[:engines].each do |player, engine|
268 e = engine.new(player, match)
272 # set up human players
273 if data[:humans].empty?
276 contr.color = data[:humans].first
277 contr.premove = data[:humans].size == 1
278 match.register(contr)
280 data[:humans][1..-1].each do |player|
281 p = DummyPlayer.new(player)
282 contr.add_controlled_player(p)
286 contr.controlled.values.each {|p| match.start(p) }
292 url = KDE::FileDialog.get_open_url(KDE::Url.new, '*.*', self,
293 KDE.i18n("Open game"))
295 return if url.is_empty or (not url.path)
297 puts "url = #{url.inspect}"
299 ext = File.extname(url.path)[1..-1]
301 readers = Game.to_enum.find_all do |_, game|
302 game.respond_to?(:game_extensions) and
303 game.game_extensions.include?(ext)
305 [game, game.game_reader]
309 warn "Unknown file extension #{ext}"
313 tmp_file = KDE::download_tempfile(url, self)
314 return unless tmp_file
320 readers.each do |g, reader|
322 data = File.open(tmp_file) do |f|
326 history = reader.read(data, i)
330 rescue ParseException
335 warn "Could not load file #{url.path}"
340 match = Match.new(game)
341 @view.create(:activate => true,
342 :name => game.class.plugin_name)
343 setup_single_player(match)
344 match.history = history
347 controller.reset(match)
351 match = controller.match
353 pattern = if match.game.respond_to?(:game_extensions)
354 match.game.game_extensions.map{|ext| "*.#{ext}"}.join(' ')
358 url = KDE::FileDialog.get_save_url(
359 KDE::Url.new, pattern, self, KDE.i18n("Save game"))
360 match.url = write_game(url)
365 match = controller.match
375 def write_game(url = nil)
376 return if url.is_empty or (not url.path)
378 match = controller.match
381 writer = match.game.game_writer
383 info[:players] = info[:players].inject({}) do |res, pl|
384 res[pl.color] = pl.name
387 result = writer.write(info, match.history)
388 write_file(url, result)
392 def update_game_actions(contr)
393 unplug_action_list(:game_actions)
395 game = contr.match.game
396 actions = if game.respond_to?(:actions)
397 game.actions(self, action_collection, contr.policy)
401 plug_action_list(:game_actions, actions)
406 self.caption = @view.current_name
409 def update_active_actions(contr)
410 if contr == controller
411 contr.active_actions.each do |id, enabled|
412 action = @actions[id]
414 action.enabled = enabled