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'
30 class MainWindow < KDE::XmlGuiWindow
37 def initialize(loader, game)
41 @theme_loader = @loader.get_matching(:theme_loader).new
43 @factories = Hash.new do |h, interface|
44 @loader.get_matching(interface)
46 @factories[:table] = Factory.new do |parent|
47 Table.new(Scene.new, @loader, @theme_loader, parent)
49 @factories[:controller] = Factory.new do |parent|
50 Controller.new(parent, @field).tap do |c|
51 c.on(:changed_active_actions) do
52 update_active_actions(c)
55 update_game_actions(c)
64 new_game(Match.new(game), :new_tab => false)
70 controller.match.close
76 @view.current.controller
83 regular_action(:open_new,
84 :icon => 'document-new',
85 :text => KDE::i18n("&New..."),
86 :shortcut => KDE::std_shortcut(:new),
87 :tooltip => KDE::i18n("Start a new game...")) do
92 :icon => 'document-open',
93 :text => KDE::i18n("&Load..."),
94 :shortcut => KDE::std_shortcut(:open),
95 :tooltip => KDE::i18n("Open a saved game...")) do
100 :icon => 'application-exit',
101 :text => KDE::i18n("&Quit"),
102 :shortcut => KDE::std_shortcut(:quit),
103 :tooltip => KDE::i18n("Quit the program")) do
107 regular_action(:save,
108 :icon => 'document-save',
109 :text => KDE::i18n("&Save"),
110 :shortcut => KDE::std_shortcut(:save),
111 :tooltip => KDE::i18n("Save the current game")) do
115 regular_action(:save_as,
116 :icon => 'document-save-as',
117 :text => KDE::i18n("Save &As..."),
118 :tooltip => KDE::i18n("Save the current game to another file")) do
122 @actions[:back] = regular_action :back, :icon => 'go-previous',
123 :text => KDE.i18n("B&ack") do
126 @actions[:forward] = regular_action :forward, :icon => 'go-next',
127 :text => KDE.i18n("&Forward") do
131 regular_action :flip, :icon => 'object-rotate-left',
132 :text => KDE.i18n("F&lip") do
133 table = @view.current.table
134 table.flip(!table.flipped?)
137 regular_action :configure_engines,
138 :icon => 'help-hint',
139 :text => KDE.i18n("Configure &Engines...") do
140 dialog = EnginePrefs.new(@engine_loader, self)
144 regular_action :configure_themes,
145 :icon => 'games-config-theme',
146 :text => KDE.i18n("Configure &Themes...") do
147 dialog = ThemePrefs.new(@loader, @theme_loader, self)
148 dialog.on(:ok) { controller.reset }
152 @actions[:undo] = regular_action(:undo,
153 :icon => 'edit-undo',
154 :text => KDE::i18n("Und&o"),
155 :shortcut => KDE::std_shortcut(:undo),
156 :tooltip => KDE::i18n("Undo the last history operation")) do
160 @actions[:redo] = regular_action(:redo,
161 :icon => 'edit-redo',
162 :text => KDE::i18n("Re&do"),
163 :shortcut => KDE::std_shortcut(:redo),
164 :tooltip => KDE::i18n("Redo the last history operation")) do
169 def load_action_providers
170 @loader.get_all_matching(:action_provider).each do |provider_klass|
171 provider = provider_klass.new
172 ActionProviderClient.new(self, provider)
177 @field = AnimationField.new(20)
179 movelist_stack = Qt::StackedWidget.new(self)
180 movelist_dock = Qt::DockWidget.new(self)
181 movelist_dock.widget = movelist_stack
182 movelist_dock.window_title = KDE.i18n("History")
183 movelist_dock.object_name = "movelist"
184 add_dock_widget(Qt::LeftDockWidgetArea, movelist_dock, Qt::Vertical)
186 action_collection[:toggle_history] = movelist_dock.toggle_view_action
188 @view = MultiView.new(self, movelist_stack, @factories)
189 @view.create(:name => game.class.plugin_name)
190 @view.on(:changed) do
191 update_active_actions(controller)
193 update_game_actions(controller)
199 @engine_loader = @loader.get_matching(:engine_loader).new
200 @engine_loader.reload
202 @console = Console.new(nil)
203 console_dock = Qt::DockWidget.new(self)
204 console_dock.widget = @console
205 console_dock.focus_proxy = @console
206 console_dock.window_title = KDE.i18n("Console")
207 console_dock.object_name = "console"
208 add_dock_widget(Qt::BottomDockWidgetArea, console_dock, Qt::Horizontal)
209 console_dock.window_flags = console_dock.window_flags & ~Qt::WindowStaysOnTopHint
211 action_collection[:toggle_console] = console_dock.toggle_view_action
213 self.central_widget = @view
216 def new_game(match, opts = { })
217 setup_single_player(match)
218 controller.reset(match)
221 def setup_single_player(match)
222 controller.color = match.game.players.first
223 controller.premove = false
224 opponents = match.game.players[1..-1].map do |color|
225 DummyPlayer.new(color)
227 opponents.each do |p|
228 controller.add_controlled_player(p)
231 controller.controlled.values.each do |p|
234 controller.controlled.values.each do |p|
239 def create_game(opts = { })
240 current_game = if controller.match
241 controller.match.game
243 diag = NewGame.new(self, @engine_loader, current_game)
244 diag.on(:ok) do |data|
246 match = Match.new(game, :editable => data[:engines].empty?)
248 @view.create(:activate => true,
250 :name => game.class.plugin_name)
252 @view.set_tab_text(@view.index, game.class.plugin_name)
258 match.on(:started) do
262 # set up engine players
263 players = game.players
264 data[:engines].each do |player, engine|
265 e = engine.new(player, match)
269 # set up human players
270 if data[:humans].empty?
273 contr.color = data[:humans].first
274 contr.premove = data[:humans].size == 1
275 match.register(contr)
277 data[:humans][1..-1].each do |player|
278 p = DummyPlayer.new(player)
279 contr.add_controlled_player(p)
283 contr.controlled.values.each {|p| match.start(p) }
289 url = KDE::FileDialog.get_open_url(KDE::Url.new, '*.*', self,
290 KDE.i18n("Open game"))
292 return if url.is_empty or (not url.path)
294 puts "url = #{url.inspect}"
296 ext = File.extname(url.path)[1..-1]
298 readers = Game.to_enum.find_all do |_, game|
299 game.respond_to?(:game_extensions) and
300 game.game_extensions.include?(ext)
302 [game, game.game_reader]
306 warn "Unknown file extension #{ext}"
310 tmp_file = KDE::download_tempfile(url, self)
311 return unless tmp_file
317 readers.each do |g, reader|
319 data = File.open(tmp_file) do |f|
323 history = reader.read(data, i)
327 rescue ParseException
332 warn "Could not load file #{url.path}"
337 match = Match.new(game)
338 @view.create(:activate => true,
339 :name => game.class.plugin_name)
340 setup_single_player(match)
341 match.history = history
344 controller.reset(match)
348 match = controller.match
350 pattern = if match.game.respond_to?(:game_extensions)
351 match.game.game_extensions.map{|ext| "*.#{ext}"}.join(' ')
355 url = KDE::FileDialog.get_save_url(
356 KDE::Url.new, pattern, self, KDE.i18n("Save game"))
357 match.url = write_game(url)
362 match = controller.match
372 def write_game(url = nil)
373 return if url.is_empty or (not url.path)
375 match = controller.match
378 writer = match.game.game_writer
380 info[:players] = info[:players].inject({}) do |res, pl|
381 res[pl.color] = pl.name
384 result = writer.write(info, match.history)
385 write_file(url, result)
389 def update_game_actions(contr)
390 unplug_action_list(:game_actions)
392 game = contr.match.game
393 actions = if game.respond_to?(:actions)
394 game.actions(self, action_collection, contr.policy)
398 plug_action_list(:game_actions, actions)
403 self.caption = @view.current_name
406 def update_active_actions(contr)
407 if contr == controller
408 contr.active_actions.each do |id, enabled|
409 action = @actions[id]
411 action.enabled = enabled