public bool Run (ExceptionDialogData data)
		{
			using (var alert = new NSAlert { AlertStyle = NSAlertStyle.Critical }) {
				alert.Icon = NSApplication.SharedApplication.ApplicationIconImage;
				
				alert.MessageText = data.Title ?? GettextCatalog.GetString ("Error");
				
				if (!string.IsNullOrEmpty (data.Message)) {
					alert.InformativeText = data.Message;
				}

				List<AlertButton> buttons = null;
				if (data.Buttons != null && data.Buttons.Length > 0)
					buttons = data.Buttons.Reverse ().ToList ();

				if (buttons != null) {
					foreach (var button in buttons) {
						var label = button.Label;
						if (button.IsStockButton)
							label = Gtk.Stock.Lookup (label).Label;
						label = label.Replace ("_", "");

						//this message seems to be a standard Mac message since alert handles it specially
						if (button == AlertButton.CloseWithoutSave)
							label = GettextCatalog.GetString ("Don't Save");

						alert.AddButton (label);
					}
				}

				if (data.Exception != null) {
					var scrollSize = new SizeF (400, 130);
					float spacing = 4;
					
					string title = GettextCatalog.GetString ("View details");
					string altTitle = GettextCatalog.GetString ("Hide details");
					
					var buttonFrame = new RectangleF (0, 0, 0, 0);
					var button = new NSButton (buttonFrame) {
						BezelStyle = NSBezelStyle.Disclosure,
						Title = "",
						AlternateTitle = "",
					};
					button.SetButtonType (NSButtonType.OnOff);
					button.SizeToFit ();
					
					var label = new MDClickableLabel (title) {
						Alignment = NSTextAlignment.Left,
					};
					label.SizeToFit ();
					
					button.SetFrameSize (new SizeF (button.Frame.Width, Math.Max (button.Frame.Height, label.Frame.Height)));
					label.SetFrameOrigin (new PointF (button.Frame.Width + 5, button.Frame.Y));
					
					var text = new MyTextView (new RectangleF (0, 0, float.MaxValue, float.MaxValue)) {
						HorizontallyResizable = true,
					};
					text.TextContainer.ContainerSize = new SizeF (float.MaxValue, float.MaxValue);
					text.TextContainer.WidthTracksTextView = true;
					text.InsertText (new NSString (data.Exception.ToString ()));
					text.Editable = false;

					var scrollView = new NSScrollView (new RectangleF (PointF.Empty, SizeF.Empty)) {
						HasHorizontalScroller = true,
						HasVerticalScroller = true,
					};
					
					var accessory = new NSView (new RectangleF (0, 0, scrollSize.Width, button.Frame.Height));
					accessory.AddSubview (scrollView);
					accessory.AddSubview (button);
					accessory.AddSubview (label);
					
					alert.AccessoryView = accessory;
					
					button.Activated += delegate {
						float change;
						if (button.State == NSCellStateValue.On) {
							change = scrollSize.Height + spacing;
							label.StringValue = altTitle;
							scrollView.Hidden = false;
							scrollView.Frame = new RectangleF (PointF.Empty, scrollSize);
							scrollView.DocumentView = text;
						} else {
							change = -(scrollSize.Height + spacing);
							label.StringValue = title;
							scrollView.Hidden = true;
							scrollView.Frame = new RectangleF (PointF.Empty, SizeF.Empty);
						}
						var f = accessory.Frame;
						f.Height += change;
						accessory.Frame = f;
						var lf = label.Frame;
						lf.Y += change;
						label.Frame = lf;
						var bf = button.Frame;
						bf.Y += change;
						button.Frame = bf;
						label.SizeToFit ();
						var panel = (NSPanel) alert.Window;
						var pf = panel.Frame;
						pf.Height += change;
						pf.Y -= change;
						panel.SetFrame (pf, true, true);
						//unless we assign the icon again, it starts nesting old icon into the warning icon
						alert.Icon = NSApplication.SharedApplication.ApplicationIconImage;
						alert.Layout ();
					};
					label.OnMouseUp += (sender, e) => button.PerformClick (e.Event);
				}

				int result = alert.RunModal () - (int)NSAlertButtonReturn.First;
				data.ResultButton = buttons != null ? buttons [result] : null;
				GtkQuartz.FocusWindow (data.TransientFor ?? MessageService.RootWindow);
			}
			
			return true;
		}
Exemplo n.º 2
0
		public bool Run (AlertDialogData data)
		{
			using (var alert = new NSAlert ()) {
				alert.Window.Title = data.Title ?? BrandingService.ApplicationName;

				if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) {
					alert.AlertStyle = NSAlertStyle.Critical;
				} else if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Warning) {
					alert.AlertStyle = NSAlertStyle.Warning;
				} else { //if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) {
					alert.AlertStyle = NSAlertStyle.Informational;
				}
				
				//FIXME: use correct size so we don't get horrible scaling?
				if (!string.IsNullOrEmpty (data.Message.Icon)) {
					var pix = ImageService.GetPixbuf (data.Message.Icon, Gtk.IconSize.Dialog);
					byte[] buf = pix.SaveToBuffer ("tiff");
					unsafe {
						fixed (byte* b = buf) {
							alert.Icon = new NSImage (NSData.FromBytes ((IntPtr)b, (uint)buf.Length));
						}
					}
				} else {
					//for some reason the NSAlert doesn't pick up the app icon by default
					alert.Icon = NSApplication.SharedApplication.ApplicationIconImage;
				}
				
				alert.MessageText = data.Message.Text;
				alert.InformativeText = data.Message.SecondaryText ?? "";
				
				var buttons = data.Buttons.Reverse ().ToList ();
				
				for (int i = 0; i < buttons.Count - 1; i++) {
					if (i == data.Message.DefaultButton) {
						var next = buttons[i];
						for (int j = buttons.Count - 1; j >= i; j--) {
							var tmp = buttons[j];
							buttons[j] = next;
							next = tmp;
						}
						break;
					}
				}
				
				foreach (var button in buttons) {
					var label = button.Label;
					if (button.IsStockButton)
						label = Gtk.Stock.Lookup (label).Label;
					label = label.Replace ("_", "");

					//this message seems to be a standard Mac message since alert handles it specially
					if (button == AlertButton.CloseWithoutSave)
						label = GettextCatalog.GetString ("Don't Save");

					alert.AddButton (label);
				}
				
				
				NSButton[] optionButtons = null;
				if (data.Options.Count > 0) {
					var box = new MDBox (LayoutDirection.Vertical, 2, 2);
					optionButtons = new NSButton[data.Options.Count];
					
					for (int i = data.Options.Count - 1; i >= 0; i--) {
						var option = data.Options[i];
						var button = new NSButton () {
							Title = option.Text,
							Tag = i,
							State = option.Value? NSCellStateValue.On : NSCellStateValue.Off,
						};
						button.SetButtonType (NSButtonType.Switch);
						optionButtons[i] = button;
						box.Add (new MDAlignment (button, true) { XAlign = LayoutAlign.Begin });
					}
					
					box.Layout ();
					alert.AccessoryView = box.View;
				}
				
				NSButton applyToAllCheck = null;
				if (data.Message.AllowApplyToAll) {
					alert.ShowsSuppressionButton = true;
					applyToAllCheck = alert.SuppressionButton;
					applyToAllCheck.Title = GettextCatalog.GetString ("Apply to all");
				}
				
				// Hack up a slightly wider than normal alert dialog. I don't know how to do this in a nicer way
				// as the min size constraints are apparently ignored.
				var frame = ((NSPanel) alert.Window).Frame;
				((NSPanel) alert.Window).SetFrame (new RectangleF (frame.X, frame.Y, Math.Max (frame.Width, 600), frame.Height), true);
				alert.Layout ();
				
				bool completed = false;
				if (data.Message.CancellationToken.CanBeCanceled) {
					data.Message.CancellationToken.Register (delegate {
						alert.InvokeOnMainThread (() => {
							if (!completed) {
								NSApplication.SharedApplication.AbortModal ();
							}
						});
					});
				}
				
				if (!data.Message.CancellationToken.IsCancellationRequested) {
					int result = alert.RunModal () - (int)NSAlertButtonReturn.First;
					completed = true;
					if (result >= 0 && result < buttons.Count) {
						data.ResultButton = buttons [result];
					} else {
						data.ResultButton = null;
					}
				}
				
				if (data.ResultButton == null || data.Message.CancellationToken.IsCancellationRequested) {
					data.SetResultToCancelled ();
				}
				
				if (optionButtons != null) {
					foreach (var button in optionButtons) {
						var option = data.Options[button.Tag];
						data.Message.SetOptionValue (option.Id, button.State != 0);
					}
				}
				
				if (applyToAllCheck != null && applyToAllCheck.State != 0)
					data.ApplyToAll = true;
				
				GtkQuartz.FocusWindow (data.TransientFor ?? MessageService.RootWindow);
			}
			
			return true;
		}
		public bool Run (AlertDialogData data)
		{
			using (var alert = new NSAlert ()) {
				
				if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) {
					alert.AlertStyle = NSAlertStyle.Critical;
				} else if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Warning) {
					alert.AlertStyle = NSAlertStyle.Warning;
				} else if (data.Message.Icon == MonoDevelop.Ide.Gui.Stock.Information) {
					alert.AlertStyle = NSAlertStyle.Informational;
				}
				
				//FIXME: use correct size so we don't get horrible scaling?
				if (!string.IsNullOrEmpty (data.Message.Icon)) {
					var pix = ImageService.GetPixbuf (data.Message.Icon, Gtk.IconSize.Dialog);
					byte[] buf = pix.SaveToBuffer ("tiff");
					unsafe {
						fixed (byte* b = buf) {
							alert.Icon = new NSImage (NSData.FromBytes ((IntPtr)b, (uint)buf.Length));
						}
					}
				}
				
				alert.MessageText = data.Message.Text;
				alert.InformativeText = data.Message.SecondaryText ?? "";
				
				var buttons = data.Buttons.Reverse ().ToList ();
				
				for (int i = 0; i < buttons.Count - 1; i++) {
					if (i == data.Message.DefaultButton) {
						var next = buttons[i];
						for (int j = buttons.Count - 1; j >= i; j--) {
							var tmp = buttons[j];
							buttons[j] = next;
							next = tmp;
						}
						break;
					}
				}
				
				foreach (var button in buttons) {
					var label = button.Label;
					if (button.IsStockButton)
						label = Gtk.Stock.Lookup (label).Label;
					label = label.Replace ("_", "");
					
					//this message seems to be a standard Mac message since alert handles it specially
					if (button == AlertButton.CloseWithoutSave)
						label = GettextCatalog.GetString ("Don't Save");
					
					alert.AddButton (label);
				}
				
				
				NSButton[] optionButtons = null;
				if (data.Options.Count > 0) {
					var box = new MDBox (LayoutDirection.Vertical, 2, 2);
					optionButtons = new NSButton[data.Options.Count];
					
					for (int i = data.Options.Count - 1; i >= 0; i--) {
						var option = data.Options[i];
						var button = new NSButton () {
							Title = option.Text,
							Tag = i,
							State = option.Value? NSCellStateValue.On : NSCellStateValue.Off,
						};
						button.SetButtonType (NSButtonType.Switch);
						optionButtons[i] = button;
						box.Add (new MDAlignment (button, true) { XAlign = LayoutAlign.Begin });
					}
					
					box.Layout ();
					alert.AccessoryView = box.View;
				}
				
				NSButton applyToAllCheck = null;
				if (data.Message.AllowApplyToAll) {
					alert.ShowsSuppressionButton = true;
					applyToAllCheck = alert.SuppressionButton;
					applyToAllCheck.Title = GettextCatalog.GetString ("Apply to all");
				}
				
				alert.Layout ();
				
				int result = alert.RunModal () - (int)NSAlertButtonReturn.First;
				
				data.ResultButton = buttons [result];
				
				if (optionButtons != null) {
					foreach (var button in optionButtons) {
						var option = data.Options[button.Tag];
						data.Message.SetOptionValue (option.Id, button.State != 0);
					}
				}
				
				if (applyToAllCheck != null && applyToAllCheck.State != 0)
					data.ApplyToAll = true;
				
				GtkQuartz.FocusWindow (data.TransientFor ?? MessageService.RootWindow);
			}
			
			return true;
		}