changeset 14:61bc9b44a695

Re #242: Create Qt# UI for WarFoundry * Add log4net logging output * Output as "WarFoundry.exe" * Wrap execution in try...catch to try to debug occasional crashes * Refactor common "connect action to menu" method Re #247: Implement menu options in Qt# app * Implement "open" action * Make "create" check for closing the old army
author IBBoard <dev@ibboard.co.uk>
date Sat, 13 Feb 2010 11:56:14 +0000
parents dbe784f0802c
children 03ed32fdc706
files AssemblyInfo.cs IBBoard.WarFoundry.GUI.QtSharp.csproj Main.cs MainWindow.cs WarFoundry.exe.log4net
diffstat 5 files changed, 183 insertions(+), 35 deletions(-) [+]
line diff
     1.1 --- a/AssemblyInfo.cs	Sat Feb 13 10:34:41 2010 +0000
     1.2 +++ b/AssemblyInfo.cs	Sat Feb 13 11:56:14 2010 +0000
     1.3 @@ -27,3 +27,4 @@
     1.4  
     1.5  //[assembly: AssemblyDelaySign(false)]
     1.6  //[assembly: AssemblyKeyFile("")]
     1.7 +[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "log4net", Watch = true)]
     1.8 \ No newline at end of file
     2.1 --- a/IBBoard.WarFoundry.GUI.QtSharp.csproj	Sat Feb 13 10:34:41 2010 +0000
     2.2 +++ b/IBBoard.WarFoundry.GUI.QtSharp.csproj	Sat Feb 13 11:56:14 2010 +0000
     2.3 @@ -8,7 +8,8 @@
     2.4      <ProjectGuid>{299D84D6-C84A-45CD-B709-AF536FCBA937}</ProjectGuid>
     2.5      <OutputType>Exe</OutputType>
     2.6      <RootNamespace>IBBoard.WarFoundry.GUI.QtSharp</RootNamespace>
     2.7 -    <AssemblyName>IBBoard.WarFoundry.GUI.QtSharp</AssemblyName>
     2.8 +    <AssemblyName>WarFoundry</AssemblyName>
     2.9 +    <StartupObject>IBBoard.WarFoundry.GUI.QtSharp.MainClass</StartupObject>
    2.10    </PropertyGroup>
    2.11    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    2.12      <DebugSymbols>true</DebugSymbols>
    2.13 @@ -79,6 +80,9 @@
    2.14      <None Include="lib\log4net.dll">
    2.15        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    2.16      </None>
    2.17 +    <None Include="WarFoundry.exe.log4net">
    2.18 +      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    2.19 +    </None>
    2.20    </ItemGroup>
    2.21    <ItemGroup>
    2.22      <Folder Include="qt-gui\" />
     3.1 --- a/Main.cs	Sat Feb 13 10:34:41 2010 +0000
     3.2 +++ b/Main.cs	Sat Feb 13 11:56:14 2010 +0000
     3.3 @@ -19,14 +19,22 @@
     3.4  		
     3.5  		public static void Main (string[] args)
     3.6  		{
     3.7 -			new QApplication (args);
     3.8 -			
     3.9 -			SetUpWarFoundryEnvironment ();
    3.10 -			
    3.11 -			MainWindow win = new MainWindow ();
    3.12 -			win.Show ();
    3.13 -			
    3.14 -			QApplication.Exec ();
    3.15 +			try
    3.16 +			{
    3.17 +				new QApplication (args);
    3.18 +				
    3.19 +				SetUpWarFoundryEnvironment ();
    3.20 +				
    3.21 +				MainWindow win = new MainWindow ();
    3.22 +				win.Show ();
    3.23 +				
    3.24 +				QApplication.Exec ();
    3.25 +			}
    3.26 +			catch(Exception ex)
    3.27 +			{
    3.28 +				logger.Fatal(ex);
    3.29 +			}
    3.30 +				
    3.31  		}
    3.32  		
    3.33  		private static void SetUpWarFoundryEnvironment ()
     4.1 --- a/MainWindow.cs	Sat Feb 13 10:34:41 2010 +0000
     4.2 +++ b/MainWindow.cs	Sat Feb 13 11:56:14 2010 +0000
     4.3 @@ -2,11 +2,13 @@
     4.4  // 
     4.5  // The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license.
     4.6  using System;
     4.7 +using System.IO;
     4.8  using System.Collections.Generic;
     4.9  using Qyoto;
    4.10  using log4net;
    4.11  using IBBoard.Commands;
    4.12  using IBBoard.IO;
    4.13 +using IBBoard.Lang;
    4.14  using IBBoard.WarFoundry.API;
    4.15  using IBBoard.WarFoundry.API.Factories;
    4.16  using IBBoard.WarFoundry.API.Objects;
    4.17 @@ -23,6 +25,7 @@
    4.18  		private string loadedFilePath;
    4.19  		private CommandStack commandStack;
    4.20  		private QFileDialog saveArmyDialog;
    4.21 +		private QFileDialog openArmyDialog;
    4.22  		
    4.23  		public MainWindow ()
    4.24  		{
    4.25 @@ -32,6 +35,11 @@
    4.26  			SetAppTitle();
    4.27  			saveArmyDialog = new QFileDialog(this);
    4.28  			saveArmyDialog.acceptMode = QFileDialog.AcceptMode.AcceptSave;
    4.29 +			saveArmyDialog.fileMode = QFileDialog.FileMode.AnyFile;
    4.30 +			openArmyDialog = new QFileDialog(this);
    4.31 +			openArmyDialog.acceptMode = QFileDialog.AcceptMode.AcceptOpen;
    4.32 +			openArmyDialog.fileMode = QFileDialog.FileMode.ExistingFile;
    4.33 +			openArmyDialog.SetNameFilter("*.army");
    4.34  			SetUpActionIcons();
    4.35  			ConnectMenuActions();
    4.36  			SetUpToolbar();
    4.37 @@ -54,36 +62,45 @@
    4.38  			layout.actionAbout.icon = new QIcon("icons/ui/help-about.png");
    4.39  		}
    4.40  		
    4.41 -		private void ConnectMenuActions()
    4.42 +		private void ConnectMenuActions ()
    4.43  		{
    4.44 -			QObject.Connect(layout.actionCreateArmy, SIGNAL("triggered()"), CreateNewArmy);
    4.45 -			QObject.Connect(layout.actionUndo, SIGNAL("triggered()"), UndoAction);
    4.46 -			QObject.Connect(layout.actionRedo, SIGNAL("triggered()"), RedoAction);
    4.47 -			QObject.Connect(layout.actionSaveArmyAs, SIGNAL("triggered()"), DoSaveCurrentArmyAs);
    4.48 -			QObject.Connect(layout.actionSaveArmy, SIGNAL("triggered()"), DoSaveCurrentArmy);
    4.49 -			QObject.Connect(layout.actionCloseArmy, SIGNAL("triggered()"), CloseArmy);
    4.50 +			ConnectMenuAction (layout.actionCreateArmy, CreateNewArmy);
    4.51 +			ConnectMenuAction (layout.actionUndo, UndoAction);
    4.52 +			ConnectMenuAction (layout.actionRedo,RedoAction);
    4.53 +			ConnectMenuAction (layout.actionSaveArmyAs, DoSaveCurrentArmyAs);
    4.54 +			ConnectMenuAction (layout.actionSaveArmy, DoSaveCurrentArmy);
    4.55 +			ConnectMenuAction (layout.actionCloseArmy, DoCloseArmy);
    4.56 +			ConnectMenuAction (layout.actionOpenArmy, DoOpenArmy);
    4.57 +		}
    4.58 +		
    4.59 +		private void ConnectMenuAction (QAction menuAction, SlotFunc method)
    4.60 +		{
    4.61 +			QObject.Connect(menuAction, SIGNAL("triggered()"), method);
    4.62  		}
    4.63  		
    4.64  		private void CreateNewArmy()
    4.65  		{
    4.66 -			NewArmyDialog dialog = new NewArmyDialog(this);
    4.67 -			int result = dialog.Exec ();
    4.68 -			
    4.69 -			if (result == (int)QDialog.DialogCode.Accepted)
    4.70 +			if (CloseCurrentArmy())
    4.71  			{
    4.72 -				try
    4.73 +				NewArmyDialog dialog = new NewArmyDialog(this);
    4.74 +				int result = dialog.Exec ();
    4.75 +				
    4.76 +				if (result == (int)QDialog.DialogCode.Accepted)
    4.77  				{
    4.78 -					CurrentArmy = new Army(dialog.GetSelectedRace(), dialog.GetArmyName(), dialog.GetArmySize());
    4.79 -				}
    4.80 -				catch (RequiredDataMissingException ex)
    4.81 -				{
    4.82 -					log.Error("Required data missing from race file", ex);
    4.83 -					QMessageBox.Warning(this, "Invalid race file data", "the race file for the requested data could not be loaded as it did not contain some required data");
    4.84 -				}
    4.85 -				catch (InvalidFileException ex)
    4.86 -				{
    4.87 -					log.Error("Race file was invalid", ex);
    4.88 -					QMessageBox.Warning(this, ex.Message,  "invalid race file");
    4.89 +					try
    4.90 +					{
    4.91 +						CurrentArmy = new Army(dialog.GetSelectedRace(), dialog.GetArmyName(), dialog.GetArmySize());
    4.92 +					}
    4.93 +					catch (RequiredDataMissingException ex)
    4.94 +					{
    4.95 +						log.Error("Required data missing from race file", ex);
    4.96 +						QMessageBox.Warning(this, "Invalid race file data", "the race file for the requested data could not be loaded as it did not contain some required data");
    4.97 +					}
    4.98 +					catch (InvalidFileException ex)
    4.99 +					{
   4.100 +						log.Error("Race file was invalid", ex);
   4.101 +						QMessageBox.Warning(this, ex.Message,  "invalid race file");
   4.102 +					}
   4.103  				}
   4.104  			}
   4.105  		}
   4.106 @@ -167,6 +184,41 @@
   4.107  			}
   4.108  		}
   4.109  		
   4.110 +		private void DoOpenArmy()
   4.111 +		{
   4.112 +			OpenArmy();
   4.113 +		}
   4.114 +		
   4.115 +		private bool OpenArmy()
   4.116 +		{
   4.117 +			log.Debug("Opening army");
   4.118 +			string newFilePath = PromptForFilePath (openArmyDialog);
   4.119 +			bool openedFile = false;
   4.120 +
   4.121 +			if (newFilePath != null && CloseCurrentArmy())
   4.122 +			{
   4.123 +				try
   4.124 +				{
   4.125 +					log.DebugFormat("Opening {0}", newFilePath);
   4.126 +					CurrentArmy = WarFoundryLoader.GetDefault().LoadArmy(new FileInfo(newFilePath));
   4.127 +					loadedFilePath = newFilePath;
   4.128 +					openedFile = true;
   4.129 +				}
   4.130 +				catch (RequiredDataMissingException ex)
   4.131 +				{
   4.132 +					log.Error(ex);
   4.133 +					QMessageBox.Critical(this, Translation.GetTranslation("InvalidArmyFileBoxTitle", "invalid army file"), ex.Message);
   4.134 +				}
   4.135 +				catch (InvalidFileException ex)
   4.136 +				{
   4.137 +					log.Error(ex);
   4.138 +					QMessageBox.Critical(this, Translation.GetTranslation("InvalidArmyFileBoxTitle", "invalid army file"), ex.Message);
   4.139 +				}
   4.140 +			}
   4.141 +	
   4.142 +			return openedFile;
   4.143 +		}
   4.144 +		
   4.145  		private void DoSaveCurrentArmy()
   4.146  		{
   4.147  			SaveCurrentArmy();
   4.148 @@ -174,6 +226,7 @@
   4.149  
   4.150  		private bool SaveCurrentArmy()
   4.151  		{
   4.152 +			log.Debug("Save current army");
   4.153  			bool saved = false;
   4.154  
   4.155  			string filePath = loadedFilePath;
   4.156 @@ -198,6 +251,7 @@
   4.157  		
   4.158  		private bool SaveCurrentArmyAs()
   4.159  		{
   4.160 +			log.Debug("Saving current army as a different file");
   4.161  			bool saved = false;
   4.162  			string filePath = PromptForArmyFilePath();
   4.163  
   4.164 @@ -211,8 +265,11 @@
   4.165  
   4.166  		private bool SaveCurrentArmyToFile(string filePath)
   4.167  		{
   4.168 +			log.DebugFormat("Save to {0}", filePath);
   4.169 +			
   4.170  			if (WarFoundrySaver.GetSaver().Save(CurrentArmy, filePath))
   4.171  			{
   4.172 +				log.Debug("Army saved");
   4.173  				loadedFilePath = filePath;
   4.174  				layout.actionSaveArmy.Enabled = false;
   4.175  				CommandStack.setCleanMark();
   4.176 @@ -220,6 +277,7 @@
   4.177  			}
   4.178  			else
   4.179  			{
   4.180 +				log.Debug("Save failed");
   4.181  				QMessageBox.Critical(this, "file save failed", "file save failed - check log for details");
   4.182  				return false;
   4.183  			}
   4.184 @@ -227,7 +285,12 @@
   4.185  
   4.186  		private string PromptForArmyFilePath()
   4.187  		{
   4.188 -			int result = saveArmyDialog.Exec();
   4.189 +			return PromptForFilePath (saveArmyDialog);
   4.190 +		}
   4.191 +		
   4.192 +		private string PromptForFilePath(QFileDialog qFileDialog)
   4.193 +		{
   4.194 +			int result = qFileDialog.Exec();
   4.195  			string path = null;
   4.196  
   4.197  			if (result == (int)QDialog.DialogCode.Accepted)
   4.198 @@ -407,9 +470,58 @@
   4.199  			//TODO enable category buttons
   4.200  		}
   4.201  		
   4.202 -		private void CloseArmy()
   4.203 +		private void DoCloseArmy()
   4.204  		{
   4.205 -			CurrentArmy = null;
   4.206 +			CloseCurrentArmy();
   4.207 +		}
   4.208 +		
   4.209 +		private bool CloseCurrentArmy()
   4.210 +		{
   4.211 +			bool closed = false;
   4.212 +			
   4.213 +			if (CurrentArmy!=null)
   4.214 +			{
   4.215 +				log.Debug("Closing "+CurrentArmy.Name);
   4.216 +				bool canClose = false;
   4.217 +
   4.218 +				if (CommandStack.IsDirty() || true)
   4.219 +				{
   4.220 +					log.Debug("Unsaved changes");
   4.221 +					string saveChanges = Translation.GetTranslation("SaveChangesQuestion", "the army \"{0}\" has been modified\r\nsave changes before closing army?", CurrentArmy.Name);
   4.222 +					string saveChangesTitle = Translation.GetTranslation("SaveChangesTitle", "unsaved changes");
   4.223 +					QMessageBox.StandardButton response = QMessageBox.Question(this, saveChangesTitle, saveChanges, (uint) (QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No | QMessageBox.StandardButton.Cancel), QMessageBox.StandardButton.Cancel);
   4.224 +					
   4.225 +					if (response == QMessageBox.StandardButton.Yes)
   4.226 +					{
   4.227 +						canClose = SaveCurrentArmy();
   4.228 +					}
   4.229 +					else if (response == QMessageBox.StandardButton.No)
   4.230 +					{
   4.231 +						log.Debug("User didn't save army");
   4.232 +						canClose = true;
   4.233 +					}
   4.234 +					//else they said cancel and we default to "canClose = false" so do nothing
   4.235 +				}
   4.236 +				else
   4.237 +				{
   4.238 +					canClose = true;
   4.239 +				}
   4.240 +
   4.241 +				if (canClose)
   4.242 +				{
   4.243 +					CurrentArmy = null;
   4.244 +					closed = true;
   4.245 +				}
   4.246 +			}
   4.247 +			else
   4.248 +			{
   4.249 +				//pretend we succeeded
   4.250 +				closed = true;
   4.251 +			}
   4.252 +			
   4.253 +			log.Debug("Army "+(closed ? "" : "not")+" closed");
   4.254 +			
   4.255 +			return closed;
   4.256  		}
   4.257  	}
   4.258  }
   4.259 \ No newline at end of file
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/WarFoundry.exe.log4net	Sat Feb 13 11:56:14 2010 +0000
     5.3 @@ -0,0 +1,23 @@
     5.4 +<?xml version="1.0" encoding="utf-8" ?>
     5.5 +<log4net>
     5.6 +	<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
     5.7 +		<layout type="log4net.Layout.PatternLayout">
     5.8 +			<conversionPattern value="%-5p [%d{HH:MM:ss}]: %C{1}.%M() - Line: %L - %m%n" />
     5.9 +		</layout>
    5.10 +	</appender>
    5.11 +	<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
    5.12 +		<file value="logs/WarFoundry.log" />
    5.13 +		<appendToFile value="false" />
    5.14 +		<rollingStyle value="Size" />
    5.15 +		<maxSizeRollBackups value="-1" />
    5.16 +		<maximumFileSize value="100MB" />
    5.17 +		<layout type="log4net.Layout.PatternLayout">
    5.18 +			<conversionPattern value="%-5p [%d{HH:MM:ss}]: %C{1}.%M() - Line: %L - %m%n" />
    5.19 +		</layout>
    5.20 +	</appender>
    5.21 +	<root>
    5.22 +		<level value="DEBUG" />
    5.23 +		<appender-ref ref="ConsoleAppender" />
    5.24 +		<appender-ref ref="RollingLogFileAppender" />
    5.25 +	</root>
    5.26 +</log4net>
    5.27 \ No newline at end of file