PageRenderTime 46ms CodeModel.GetById 31ms app.highlight 10ms RepoModel.GetById 0ms app.codeStats 1ms

/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.Projects.OptionPanels/CodeFormattingPanel.cs

https://github.com/Shanto/monodevelop
C# | 426 lines | 343 code | 54 blank | 29 comment | 56 complexity | 7ec176a656497def8c1316a66df44155 MD5 | raw file
  1// 
  2// CodeFormattingPanelWidget.cs
  3//  
  4// Author:
  5//       Lluis Sanchez Gual <lluis@novell.com>
  6// 
  7// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
  8// 
  9// Permission is hereby granted, free of charge, to any person obtaining a copy
 10// of this software and associated documentation files (the "Software"), to deal
 11// in the Software without restriction, including without limitation the rights
 12// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 13// copies of the Software, and to permit persons to whom the Software is
 14// furnished to do so, subject to the following conditions:
 15// 
 16// The above copyright notice and this permission notice shall be included in
 17// all copies or substantial portions of the Software.
 18// 
 19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 22// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 23// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 24// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 25// THE SOFTWARE.
 26
 27using System;
 28using System.Collections;
 29using System.Collections.Generic;
 30using Mono.Addins;
 31using MonoDevelop.Ide.Gui.Dialogs;
 32using MonoDevelop.Ide.Extensions;
 33using MonoDevelop.Projects;
 34using MonoDevelop.Core;
 35using MonoDevelop.Projects.Policies;
 36using MonoDevelop.Components;
 37using System.Linq;
 38
 39namespace MonoDevelop.Ide.Projects.OptionPanels
 40{
 41	class CodeFormattingPanel: OptionsPanel
 42	{
 43		PolicyContainer policyContainer;
 44		Dictionary<string,MimeTypePanelData> typeSections = new Dictionary<string, MimeTypePanelData> ();
 45		List<string> globalMimeTypes;
 46		HashSet<string> mimeTypesWithPolicies = new HashSet<string> ();
 47		bool internalPolicyUpdate;
 48		CodeFormattingPanelWidget widget;
 49		
 50		public override void Initialize (MonoDevelop.Ide.Gui.Dialogs.OptionsDialog dialog, object dataObject)
 51		{
 52			base.Initialize (dialog, dataObject);
 53			
 54			foreach (MimeTypeOptionsPanelNode node in AddinManager.GetExtensionNodes ("/MonoDevelop/ProjectModel/Gui/MimeTypePolicyPanels"))
 55				mimeTypesWithPolicies.Add (node.MimeType);
 56			
 57			var provider = dataObject as IPolicyProvider;
 58			if (provider == null)
 59				provider = PolicyService.GetUserDefaultPolicySet ();
 60			
 61			policyContainer = provider.Policies;
 62			if (!(dataObject is SolutionItem) && !(dataObject is Solution)) {
 63				globalMimeTypes = new List<string> ();
 64				string userTypes = PropertyService.Get<string> ("MonoDevelop.Projects.GlobalPolicyMimeTypes", "");
 65				globalMimeTypes.AddRange (userTypes.Split (new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
 66			}
 67			
 68			foreach (string mt in GetItemMimeTypes ())
 69				AddPanel (mt);
 70			
 71			policyContainer.PolicyChanged += HandlePolicyContainerPolicyChanged;
 72		}
 73		
 74		public override void Dispose ()
 75		{
 76			base.Dispose ();
 77			policyContainer.PolicyChanged -= HandlePolicyContainerPolicyChanged;
 78		}
 79
 80		void HandlePolicyContainerPolicyChanged (object sender, PolicyChangedEventArgs e)
 81		{
 82			if (internalPolicyUpdate)
 83				return;
 84			
 85			// The policy container has changed externally. The panel data has to be reloaded
 86			
 87			foreach (MimeTypePanelData pd in typeSections.Values) {
 88				bool useParentPolicy = false;
 89				bool modified = false;
 90				foreach (IMimeTypePolicyOptionsPanel panel in pd.Panels) {
 91					// Reload the panel if it is handling the modified policy
 92					if (panel.HandlesPolicyType (e.PolicyType, e.Scope)) {
 93						panel.LoadSetPolicy (policyContainer);
 94						modified = true;
 95					}
 96					if (!panel.HasCustomPolicy)
 97						useParentPolicy = true;
 98				}
 99				if (modified)
100					pd.SetUseParentPolicy  (useParentPolicy, e.PolicyType, e.Scope);
101				if (pd.SectionLoaded) {
102					pd.SectionPanel.FillPolicies ();
103					pd.SectionPanel.UpdateSelectedNamedPolicy ();
104				}
105			}
106			if (widget != null)
107				widget.Refresh ();
108		}
109		
110		MimeTypePanelData AddPanel (string mt)
111		{
112			var chain = new List<string> (DesktopService.GetMimeTypeInheritanceChain (mt).Where (x => mimeTypesWithPolicies.Contains (x)));
113			if (chain.Count == 0)
114				return null;
115			MimeTypePanelData data = new MimeTypePanelData ();
116			OptionsDialogSection sec = new MimetypeOptionsDialogSection (mt);
117			sec.Fill = true;
118			data.Section = sec;
119			data.MimeType = mt;
120			data.TypeDescription = DesktopService.GetMimeTypeDescription (mt);
121			if (string.IsNullOrEmpty (data.TypeDescription))
122				data.TypeDescription = mt;
123			data.DataObject = DataObject;
124			data.PolicyContainer = policyContainer;
125			sec.Label = data.TypeDescription;
126			LoadPolicyTypeData (data, mt, chain);
127			typeSections [mt] = data;
128			ParentDialog.AddChildSection (this, sec, data);
129			return data;
130		}
131		
132		void RemovePanel (string mt)
133		{
134			MimeTypePanelData data = typeSections [mt];
135			typeSections.Remove (mt);
136			ParentDialog.RemoveSection (data.Section);
137		}
138		
139		internal MimeTypePanelData AddGlobalMimeType (string mt)
140		{
141			if (!globalMimeTypes.Contains (mt)) {
142				globalMimeTypes.Add (mt);
143				return AddPanel (mt);
144			}
145			return null;
146		}
147		
148		internal void RemoveGlobalMimeType (string mt)
149		{
150			if (globalMimeTypes.Remove (mt))
151				RemovePanel (mt);
152		}
153		
154		public IEnumerable<MimeTypePanelData> GetMimeTypeData ()
155		{
156			return typeSections.Values;
157		}
158		
159		public PolicyContainer PolicyContainer {
160			get { return policyContainer; }
161		}
162
163		void LoadPolicyTypeData (MimeTypePanelData data, string mimeType, List<string> types)
164		{
165			List<IMimeTypePolicyOptionsPanel> panels = new List<IMimeTypePolicyOptionsPanel> ();
166			
167			bool useParentPolicy = false;
168			foreach (MimeTypeOptionsPanelNode node in AddinManager.GetExtensionNodes ("/MonoDevelop/ProjectModel/Gui/MimeTypePolicyPanels")) {
169				if (!types.Contains (node.MimeType))
170					continue;
171				
172				IMimeTypePolicyOptionsPanel panel = (IMimeTypePolicyOptionsPanel) node.CreateInstance (typeof(IMimeTypePolicyOptionsPanel));
173				panel.Initialize (ParentDialog, DataObject);
174				panel.InitializePolicy (policyContainer, mimeType, mimeType == node.MimeType);
175				panel.Label = GettextCatalog.GetString (node.Label);
176				if (!panel.IsVisible ())
177					continue;
178				
179				if (!panel.HasCustomPolicy)
180					useParentPolicy = true;
181				
182				panels.Add (panel);
183			}
184			data.Panels = panels;
185			if (!policyContainer.IsRoot || ParentDialog is DefaultPolicyOptionsDialog)
186				data.UseParentPolicy = useParentPolicy;
187		}
188		
189		public override Gtk.Widget CreatePanelWidget ()
190		{
191			return widget = new CodeFormattingPanelWidget (this, ParentDialog);
192		}
193		
194		public override void ApplyChanges ()
195		{
196			if (globalMimeTypes != null) {
197				string types = string.Join (";", globalMimeTypes.ToArray ());
198				PropertyService.Set ("MonoDevelop.Projects.GlobalPolicyMimeTypes", types);
199			}
200			try {
201				internalPolicyUpdate = true;
202				// If a section is already loaded, changes will be committed in the panel
203				foreach (MimeTypePanelData pd in typeSections.Values) {
204					if (!pd.SectionLoaded)
205						pd.ApplyChanges ();
206				}
207			} finally {
208				internalPolicyUpdate = false;
209			}
210		}
211		
212		public IEnumerable<string> GetItemMimeTypes ()
213		{
214			HashSet<string> types = new HashSet<string> ();
215			if (DataObject is Solution)
216				GetItemMimeTypes (types, ((Solution)DataObject).RootFolder);
217			else if (DataObject is SolutionItem)
218				GetItemMimeTypes (types, (SolutionItem)DataObject);
219			else {
220				types.Add ("application/xml");
221				foreach (MimeTypeOptionsPanelNode node in AddinManager.GetExtensionNodes ("/MonoDevelop/ProjectModel/Gui/MimeTypePolicyPanels")) {
222					types.Add (node.MimeType);
223					globalMimeTypes.Remove (node.MimeType);
224				}
225				types.UnionWith (globalMimeTypes);
226			}
227			return types;
228		}
229		
230		public bool IsUserMimeType (string type)
231		{
232			return globalMimeTypes != null && globalMimeTypes.Contains (type);
233		}
234		
235		void GetItemMimeTypes (HashSet<string> types, SolutionItem item)
236		{
237			if (item is SolutionFolder) {
238				foreach (SolutionItem it in ((SolutionFolder)item).Items)
239					GetItemMimeTypes (types, it);
240			}
241			else if (item is Project) {
242				foreach (ProjectFile pf in ((Project)item).Files) {
243					string mt = DesktopService.GetMimeTypeForUri (pf.FilePath);
244					foreach (string mth in DesktopService.GetMimeTypeInheritanceChain (mt))
245						types.Add (mth);
246				}
247			}
248		}
249	}
250	
251	class MimetypeOptionsDialogSection : OptionsDialogSection
252	{
253		public MimetypeOptionsDialogSection (string mimetype): base (typeof(MimeTypePolicyOptionsSection))
254		{
255			this.MimeType = mimetype;
256		}
257		
258		//this is used by the options dialog to look up the icon as needed, at required scales
259		public string MimeType { get; private set; }
260	}
261	
262	[System.ComponentModel.ToolboxItem(true)]
263	partial class CodeFormattingPanelWidget : Gtk.Bin
264	{
265		CodeFormattingPanel panel;
266		Gtk.ListStore store;
267		OptionsDialog dialog;
268		
269		public CodeFormattingPanelWidget (CodeFormattingPanel panel, OptionsDialog dialog)
270		{
271			this.Build();
272			this.panel = panel;
273			this.dialog = dialog;
274			
275			store = new Gtk.ListStore (typeof(MimeTypePanelData), typeof(Gdk.Pixbuf), typeof(string));
276			tree.Model = store;
277			
278			boxButtons.Visible = panel.DataObject is PolicySet;
279			Gtk.CellRendererText crt = new Gtk.CellRendererText ();
280			Gtk.CellRendererPixbuf crp = new Gtk.CellRendererPixbuf ();
281			
282			Gtk.TreeViewColumn col = new Gtk.TreeViewColumn ();
283			col.Title = GettextCatalog.GetString ("File Type");
284			col.PackStart (crp, false);
285			col.PackStart (crt, true);
286			col.AddAttribute (crp, "pixbuf", 1);
287			col.AddAttribute (crt, "text", 2);
288			tree.AppendColumn (col);
289			store.SetSortColumnId (2, Gtk.SortType.Ascending);
290			
291			CellRendererComboBox comboCell = new CellRendererComboBox ();
292			comboCell.Changed += OnPolicySelectionChanged;
293			Gtk.TreeViewColumn polCol = tree.AppendColumn (GettextCatalog.GetString ("Policy"), comboCell, new Gtk.TreeCellDataFunc (OnSetPolicyData));
294			
295			tree.Selection.Changed += delegate {
296				Gtk.TreeIter it;
297				tree.Selection.GetSelected (out it);
298				Gtk.TreeViewColumn ccol;
299				Gtk.TreePath path;
300				tree.GetCursor (out path, out ccol);
301				if (ccol == polCol)
302					tree.SetCursor (path, ccol, true);
303			};
304
305			Fill ();
306			UpdateButtons ();
307			
308			tree.Selection.Changed += delegate {
309				UpdateButtons ();
310			};
311		}
312		
313		static readonly string parentPolicyText = GettextCatalog.GetString ("(Inherited Policy)");
314		static readonly string customPolicyText = GettextCatalog.GetString ("(Custom)");
315		
316		void OnSetPolicyData (Gtk.TreeViewColumn treeColumn, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
317		{
318			MimeTypePanelData mt = (MimeTypePanelData) store.GetValue (iter, 0);
319			
320			string selection;
321			if (mt.UseParentPolicy)
322				selection = parentPolicyText;
323			else {
324				PolicySet matchingSet = mt.GetMatchingSet (null);
325				if (matchingSet != null)
326					selection = matchingSet.Name;
327				else
328					selection = customPolicyText;
329			}
330			
331			CellRendererComboBox comboCell = (CellRendererComboBox) cell;
332			comboCell.Values = GetComboOptions (mt);
333			comboCell.Text = selection;
334		}
335		
336		string[] GetComboOptions (MimeTypePanelData mt)
337		{
338			List<string> values = new List<string> ();
339			
340			if (!this.panel.PolicyContainer.IsRoot)
341				values.Add (parentPolicyText);
342			
343			foreach (PolicySet set in mt.GetSupportedPolicySets ())
344				values.Add (set.Name);
345
346			values.Add (customPolicyText);
347			return values.ToArray ();
348		}
349		
350		void OnPolicySelectionChanged (object s, ComboSelectionChangedArgs args)
351		{
352			Gtk.TreeIter iter;
353			if (store.GetIter (out iter, new Gtk.TreePath (args.Path))) {
354				MimeTypePanelData mt = (MimeTypePanelData) store.GetValue (iter, 0);
355				if (args.Active != -1) {
356					string sel = args.ActiveText;
357					if (sel == parentPolicyText)
358						mt.UseParentPolicy = true;
359					else if (sel != customPolicyText) {
360						PolicySet pset = PolicyService.GetPolicySet (sel);
361						mt.AssignPolicies (pset);
362					}
363				}
364			}
365		}
366		
367		void Fill ()
368		{
369			foreach (MimeTypePanelData mt in panel.GetMimeTypeData ()) {
370				store.AppendValues (mt, DesktopService.GetPixbufForType (mt.MimeType, Gtk.IconSize.Menu), mt.TypeDescription);
371			}
372		}
373		
374		public void Refresh ()
375		{
376			tree.QueueDraw ();
377		}
378
379		protected void OnButtonEditClicked (object sender, System.EventArgs e)
380		{
381			Gtk.TreeIter iter;
382			if (tree.Selection.GetSelected (out iter)) {
383				MimeTypePanelData mt = (MimeTypePanelData) store.GetValue (iter, 0);
384				dialog.ShowPage (mt.Section);
385			}
386		}
387
388		protected virtual void OnButtonAddClicked (object sender, System.EventArgs e)
389		{
390			AddMimeTypeDialog dlg = new AddMimeTypeDialog (panel.GetItemMimeTypes ());
391			try {
392				if (MessageService.RunCustomDialog (dlg, this.Toplevel as Gtk.Window) == (int) Gtk.ResponseType.Ok) {
393					MimeTypePanelData mt = panel.AddGlobalMimeType (dlg.MimeType);
394					store.AppendValues (mt, DesktopService.GetPixbufForType (mt.MimeType, Gtk.IconSize.Menu), mt.TypeDescription);
395				}
396			} finally {
397				dlg.Destroy ();
398			}
399		}
400
401		protected virtual void OnButtonRemoveClicked (object sender, System.EventArgs e)
402		{
403			Gtk.TreeIter iter;
404			if (tree.Selection.GetSelected (out iter)) {
405				MimeTypePanelData mt = (MimeTypePanelData) store.GetValue (iter, 0);
406				if (MessageService.Confirm (GettextCatalog.GetString ("Are you sure you want to remove the formatting policy for the type '{0}'?", mt.TypeDescription), AlertButton.Delete)) {
407					panel.RemoveGlobalMimeType (mt.MimeType);
408					store.Remove (ref iter);
409				}
410			}
411		}
412		
413		void UpdateButtons ()
414		{
415			Gtk.TreeIter iter;
416			if (tree.Selection.GetSelected (out iter)) {
417				MimeTypePanelData mt = (MimeTypePanelData) store.GetValue (iter, 0);
418				if (panel.IsUserMimeType (mt.MimeType)) {
419					buttonRemove.Sensitive = buttonEdit.Sensitive = true;
420					return;
421				}
422			}
423			buttonRemove.Sensitive = buttonEdit.Sensitive = false;
424		}
425	}
426}