00001 using System;
00002 using Gtk;
00003 using Gdk;
00004 using Foodolini.Activities;
00005 using Foodolini.BusinessLogic;
00006 using Foodolini.Activities.ShoppingList;
00007 using System.Reflection;
00008 using System.IO;
00009 using System.Collections.Generic;
00010
00011 namespace Foodolini.Main{
00012
00013 public partial class MainWindow : Gtk.Window, IOwner
00014 {
00015 public MainWindow() : base(Gtk.WindowType.Toplevel)
00016 {
00017 Build();
00018
00019
00020 this.LoadPlugins();
00021
00022 Foodolini.BusinessLogic.Settings.Instance.OpenSqliteDatabase("foodolini.db3");
00023
00024 this.userCombobox.Changed += this.userCombobox_Changed;
00025 this.activityCombobox.Changed += this.activityCombobox_Changed;
00026
00027 PopulateUserCombobox();
00028
00029 LoadShoppingList();
00030
00031 this.HomeActivity();
00032 }
00033
00034 protected virtual void OnHomeButtonClicked (object sender, System.EventArgs e){
00035 this.HomeActivity();
00036 }
00037
00038 #region Plugin loading
00039
00040 private List<string> mainActivities;
00041 private Dictionary<string, ConstructorInfo> plugins;
00042 private Dictionary<string, Pixbuf> pluginIcons;
00043
00044 private void LoadPlugins(){
00045
00046 this.plugins = new Dictionary<string, ConstructorInfo>();
00047 this.mainActivities = new List<string>();
00048 this.pluginIcons = new Dictionary<string, Pixbuf>();
00049
00050 List<string> pluginsPaths = new List<string>();
00051 pluginsPaths.Add(System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
00052
00053
00054
00055 foreach(var pluginPath in pluginsPaths){
00056 foreach(var file in Directory.GetFiles(pluginPath, "*.dll")){
00057 try{
00058 Assembly assembly = Assembly.LoadFile(file);
00059 foreach(object attr in assembly.GetCustomAttributes(false)){
00060 if(attr is AssemblyFoodoliniPluginAttribute){
00061 foreach(Type type in assembly.GetTypes()){
00062 foreach(var at in type.GetCustomAttributes(false)){
00063 if(at is FoodoliniActivityAttribute){
00064 var att = (FoodoliniActivityAttribute)at;
00065
00066 this.plugins.Add(att.Name, type.GetConstructor(new Type[]{}));
00067 this.pluginIcons.Add(att.Name, att.GetIcon(assembly));
00068 if(!att.IsSubActivity)
00069 this.mainActivities.Add(att.Name);
00070 }
00071 }
00072 }
00073 }
00074 }
00075 }
00076 catch(Exception e){
00077 Console.WriteLine("Exception while trying to look for plugins in: " + file + "\n\t" + e.Message);
00078 }
00079 }
00080 }
00081
00082 if(mainActivities.Count == 0)
00083 throw new Exception("No main activities found!");
00084 }
00085
00086 #endregion
00087
00088 #region Activity handling
00089
00093 private Stack<IActivity> activities = new Stack<IActivity>();
00094
00098 private string ActivityName(IActivity activity){
00099 foreach(var at in activity.GetType().GetCustomAttributes(false)){
00100 if(at is FoodoliniActivityAttribute){
00101 var att = (FoodoliniActivityAttribute)at;
00102 return att.Name;
00103 }
00104 }
00105 return "Unknown";
00106 }
00107
00108 private Widget currentView = null;
00109
00113 void SetActivity(){
00114
00115 if(this.currentView != null){
00116 this.contentbox.Remove(this.currentView);
00117 this.currentView.Hide();
00118 }
00119
00120
00121 var activity = this.activities.Peek();
00122
00123
00124 this.currentView = activity.Widget;
00125
00126
00127 this.UpdateActivitiesComboBox();
00128
00129
00130 this.contentbox.Add(activity.Widget);
00131 activity.Widget.ShowAll();
00132 }
00133
00140 void InitializeActivity(string activity){
00141 if(!this.HasActivity(activity))
00142 throw new Exception("Couldn't initialize activity: " + activity);
00143
00144 var act = (IActivity)this.plugins[activity].Invoke(new object[]{});
00145
00146 act.Register(this);
00147
00148
00149 this.activities.Push(act);
00150 }
00151
00152 bool HasActivity(string activity){
00153 return this.plugins.ContainsKey(activity);
00154 }
00155
00160 bool CloseActivity(){
00161 if(this.activities.Count == 0)
00162 throw new Exception("Can't close activity when there's is no activity to close!");
00163
00164 if(this.ActivityUnloading != null){
00165 var peek = this.activities.Peek();
00166 var args = new ActivityUnloadedArgs(peek);
00167 this.ActivityUnloading(this, args);
00168 if(!args.Unload)
00169 return false;
00170 }
00171 var activity = this.activities.Pop();
00172
00173
00174 if(this.currentView != null && this.currentView == activity.Widget){
00175 this.contentbox.Remove(this.currentView);
00176 this.currentView = null;
00177 }
00178
00179 activity.Unregister();
00180 activity.Widget.Destroy();
00181 return true;
00182 }
00183
00184 #endregion
00185
00186 #region Activity combo box
00187
00188 private ListStore activityStore;
00189
00193 private void UpdateActivitiesComboBox(){
00194
00195 var activity = this.activities.Peek();
00196
00197
00198 ignoreComboBoxChanges = true;
00199
00200 string name = this.ActivityName(activity);
00201
00202 if(this.activityStore == null){
00203 this.activityStore = new ListStore(typeof(string), typeof(Pixbuf));
00204 this.activityCombobox.Model = this.activityStore;
00205 this.activityCombobox.Clear();
00206 var cp = new CellRendererPixbuf();
00207 var ct = new CellRendererText();
00208 this.activityCombobox.PackStart(cp, false);
00209 this.activityCombobox.PackStart(ct, true);
00210 this.activityCombobox.AddAttribute(cp, "pixbuf", 1);
00211 this.activityCombobox.AddAttribute(ct, "text", 0);
00212 }else
00213 this.activityStore.Clear();
00214
00215 Nullable<TreeIter> active = null;
00216 foreach(string entry in this.mainActivities){
00217 var iter = this.activityStore.AppendValues(entry, this.pluginIcons[entry]);
00218 if(entry == name)
00219 active = iter;
00220 }
00221
00222 if(active == null){
00223 Pixbuf icon = null;
00224 if(this.pluginIcons.ContainsKey(name))
00225 icon = this.pluginIcons[name];
00226 active = this.activityStore.AppendValues(name, icon);
00227 }
00228
00229 this.activityCombobox.SetActiveIter(active.Value);
00230
00231
00232 ignoreComboBoxChanges = false;
00233
00234
00235 this.activityCombobox.QueueResize();
00236 }
00237
00241 private bool ignoreComboBoxChanges = false;
00242
00243 void activityCombobox_Changed(object sender, EventArgs e){
00244
00245 if(!this.ignoreComboBoxChanges){
00246
00247 TreeIter iter;
00248 this.activityCombobox.GetActiveIter(out iter);
00249 var activity = (string)this.activityCombobox.Model.GetValue(iter, 0);
00250
00251 if(!this.LoadActivity(activity))
00252 this.UpdateActivitiesComboBox();
00253 }
00254 }
00255
00256 #endregion
00257
00258 #region User combo box
00259
00263 void userCombobox_Changed(object sender, EventArgs e){
00264 if(this.CurrentUserChanged != null)
00265 this.CurrentUserChanged(this, new PersonEventArgs(this.CurrentUser));
00266 }
00267
00271 private ListStore userStore;
00272
00276 void PopulateUserCombobox(){
00277
00278 Person active = this.CurrentUser;
00279 if(this.userStore == null){
00280 this.userStore = new ListStore(typeof(string), typeof(object));
00281 this.userCombobox.Model = this.userStore;
00282 }else
00283 this.userStore.Clear();
00284
00285
00286 TreeIter defaultSelection = userStore.AppendValues("[Anonymous]", null);
00287 foreach (var person in Person.ListUsers()) {
00288 TreeIter item = this.userStore.AppendValues(person.FullName, person);
00289 if (person == active)
00290 defaultSelection = item;
00291 }
00292
00293
00294 this.userCombobox.QueueResize();
00295
00296 this.userCombobox.SetActiveIter(defaultSelection);
00297 }
00298
00299 #endregion
00300
00301 private void OnDeleteEvent(object sender, DeleteEventArgs a){
00302 bool close = true;
00303 while(this.activities.Count != 0){
00304 if(!this.CloseActivity()){
00305 this.SetActivity();
00306 close = false;
00307 break;
00308 }
00309 }
00310 if(close){
00311 this.shoppingList.Unregister();
00312 this.shoppingList.Widget.Destroy();
00313 Foodolini.BusinessLogic.Settings.Instance.Dispose();
00314 Application.Quit();
00315 }
00316 a.RetVal = close;
00317 }
00318
00319 #region IOwner implementation
00320
00328 public void AddRecipe(Recipe recipe, double servings){
00329 (this.shoppingList as ShoppingListActivity).AddRecipe(recipe, servings);
00330 }
00331
00332 public void UpdateUserList(){
00333 this.PopulateUserCombobox();
00334 }
00335
00336
00346 public IActivity PushActivity(string activity){
00347 if(!this.HasActivity(activity))
00348 return null;
00349 this.InitializeActivity(activity);
00350 this.SetActivity();
00351
00352 return this.activities.Peek();
00353 }
00354
00361 public T PushActivity<T>() where T : class, new(){
00362 string name = null;
00363 foreach(var att in typeof(T).GetCustomAttributes(false)){
00364 if(att is FoodoliniActivityAttribute){
00365 name = ((FoodoliniActivityAttribute)att).Name;
00366 }
00367 }
00368 if(name == null)
00369 return null;
00370 return (T)this.PushActivity(name);
00371 }
00372
00382 public bool LoadActivity(string activity){
00383 if(!this.HasActivity(activity))
00384 return false;
00385 while(this.activities.Count != 0){
00386 if(!this.CloseActivity()){
00387 this.SetActivity();
00388 return false;
00389 }
00390 }
00391 this.InitializeActivity(activity);
00392 this.SetActivity();
00393 return true;
00394 }
00395
00402 public bool PopActivity(){
00403 if(this.CloseActivity()){
00404 if(this.activities.Count == 0)
00405 this.InitializeActivity("Home");
00406 this.SetActivity();
00407 return true;
00408 }
00409 return false;
00410 }
00411
00418 public bool HomeActivity(){
00419 return this.LoadActivity("Home");
00420 }
00421
00422
00423 public event EventHandler<PersonEventArgs> CurrentUserChanged;
00424 public event EventHandler<ActivityUnloadedArgs> ActivityUnloading;
00425
00429 public Person CurrentUser
00430 {
00431 get{
00432 TreeIter iter;
00433 if(!this.userCombobox.GetActiveIter(out iter))
00434 return null;
00435 return (Person)this.userCombobox.Model.GetValue(iter, 1);
00436 }
00437 }
00438
00442 public Gtk.Window Window{
00443 get{
00444 return this;
00445 }
00446 }
00447
00448 #endregion
00449
00450 #region Shopping shoppingList
00451
00452 private IActivity shoppingList;
00453 private bool shoppingListCollapsed = false;
00454
00455 private void LoadShoppingList(){
00456 shoppingList = (IActivity)this.plugins["Shopping shoppingList"].Invoke(new object[]{});
00457 shoppingList.Register(this);
00458 this.ShoppingListBox.Add(shoppingList.Widget);
00459 this.shoppingList.Widget.Show();
00460 ShowHideShoppingList();
00461 }
00462
00463
00464 public void ToggleShoppingList(bool state)
00465 {
00466 this.shoppingListCollapsed = state;
00467 ShowHideShoppingList();
00468 }
00469
00470 protected virtual void OnBtnShowHideShoppingListClicked (object sender, System.EventArgs e)
00471 {
00472 ShowHideShoppingList();
00473 }
00474
00475 private void ShowHideShoppingList(){
00476 this.ShoppingListHandleTable.Remove(this.ShoppingListLabel);
00477 if(this.shoppingListCollapsed){
00478
00479 this.ShoppingListLabel.Angle = 0.0;
00480 this.ShoppingListHandleTable.Attach(this.ShoppingListLabel, 1, 2, 0, 1);
00481 this.ShoppingListBox.Show();
00482 this.ShoppingListArrow.ArrowType = ArrowType.Down;
00483 }else{
00484
00485 this.ShoppingListLabel.Angle = 270;
00486 this.ShoppingListHandleTable.Attach(this.ShoppingListLabel, 0, 1, 1, 2);
00487 this.ShoppingListBox.Hide();
00488 this.ShoppingListArrow.ArrowType = ArrowType.Left;
00489 }
00490 this.shoppingListCollapsed = !this.shoppingListCollapsed;
00491 }
00492
00493
00494 #endregion
00495 }
00496 }