<commit_before>﻿// 
// SaveDocumentImplmentationAction.cs
//  
// Author:
//       <NAME> <<EMAIL>>
// 
// Copyright (c) 2010 <NAME>
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using Gtk;
using Mono.Unix;
using Pinta.Core;
using System.IO;
using System.Collections.Generic;

namespace Pinta.Actions
{
	class SaveDocumentImplmentationAction : IActionHandler
	{
		private const string markup = "<span weight=\"bold\" size=\"larger\">{0}</span>\n\n{1}";

		#region IActionHandler Members
		public void Initialize ()
		{
			PintaCore.Actions.File.SaveDocument += Activated;
		}

		public void Uninitialize ()
		{
			PintaCore.Actions.File.SaveDocument -= Activated;
		}
		#endregion

		private void Activated (object sender, DocumentCancelEventArgs e)
		{
			// Document hasn't changed, don't re-save it
			if (!e.Document.IsDirty)
				return;

			if (e.Document.HasFile)
				// If the document already has a filename, just re-save it
				e.Cancel = !SaveFile (e.Document, null, null);
			else
				// The document has never been saved before
				e.Cancel = !SaveFileAs (e.Document);
		}

		// This is actually both for "Save As" and saving a file that never
		// been saved before.  Either way, we need to prompt for a filename.
		private bool SaveFileAs (Document document)
		{
			var fcd = new FileChooserDialog (Mono.Unix.Catalog.GetString ("Save Image File"),
									       PintaCore.Chrome.MainWindow,
									       FileChooserAction.Save,
									       Gtk.Stock.Cancel,
									       Gtk.ResponseType.Cancel,
									       Gtk.Stock.Save, Gtk.ResponseType.Ok);

			fcd.DoOverwriteConfirmation = true;
			fcd.SetCurrentFolder (PintaCore.System.LastDialogDirectory);
			fcd.AlternativeButtonOrder = new int[] { (int)ResponseType.Ok, (int)ResponseType.Cancel };

			bool hasFile = document.HasFile;

			if (hasFile)
				fcd.SetFilename (document.PathAndFileName);

			Dictionary<FileFilter, FormatDescriptor> filetypes = new Dictionary<FileFilter, FormatDescriptor> ();

			// Add all the formats we support to the save dialog
			foreach (var format in PintaCore.System.ImageFormats.Formats) {
				if (!format.IsReadOnly ()) {
					fcd.AddFilter (format.Filter);
					filetypes.Add (format.Filter, format);

					// Set the filter to anything we found
					// We want to ensure that *something* is selected in the filetype
					fcd.Filter = format.Filter;
				}
			}

			// If we already have a format, set it to the default.
			// If not, default to jpeg
			FormatDescriptor format_desc = null;

			if (hasFile)
				format_desc = PintaCore.System.ImageFormats.GetFormatByFile (document.Filename);

			if (format_desc == null) {
				format_desc = PintaCore.System.ImageFormats.GetDefaultSaveFormat ();

				// Gtk doesn't like it if we set the file name to an extension that we don't have
				// a filter for, so we change the extension to our default extension.
				if (hasFile)
					fcd.SetFilename (Path.ChangeExtension (document.PathAndFileName, format_desc.Extensions[0]));
			}

			fcd.Filter = format_desc.Filter;

			// Replace GTK's ConfirmOverwrite with our own, for UI consistency
			fcd.ConfirmOverwrite += (eventSender, eventArgs) => {
				if (this.ConfirmOverwrite (fcd, fcd.Filename))
					eventArgs.RetVal = FileChooserConfirmation.AcceptFilename;
				else
					eventArgs.RetVal = FileChooserConfirmation.SelectAgain;
			};

			while (fcd.Run () == (int)Gtk.ResponseType.Ok) {
				FormatDescriptor format = filetypes[fcd.Filter];
				string file = fcd.Filename;

				if (string.IsNullOrEmpty (Path.GetExtension (file))) {
					// No extension; add one from the format descriptor.
					file = string.Format ("{0}.{1}", file, format.Extensions[0]);
					fcd.CurrentName = Path.GetFileName (file);

					// We also need to display an overwrite confirmation message manually,
					// because MessageDialog won't do this for us in this case.
					if (File.Exists (file) && !ConfirmOverwrite (fcd, file))
						continue;
				}

				// Always follow the extension rather than the file type drop down
				// ie: if the user chooses to save a "jpeg" as "foo.png", we are going
				// to assume they just didn't update the dropdown and really want png
				var format_type = PintaCore.System.ImageFormats.GetFormatByFile (file);

				if (format_type != null)
					format = format_type;

				PintaCore.System.LastDialogDirectory = fcd.CurrentFolder;
				SaveFile (document, file, format);
				RecentManager.Default.AddFull (fcd.Uri, PintaCore.System.RecentData);
				PintaCore.System.ImageFormats.SetDefaultFormat (Path.GetExtension (file));

				document.HasFile = true;
				document.PathAndFileName = file;

				fcd.Destroy ();
				return true;
			}

			fcd.Destroy ();
			return false;
		}

		private bool SaveFile (Document document, string file, FormatDescriptor format)
		{
			if (string.IsNullOrEmpty (file))
				file = document.PathAndFileName;

			if (format == null)
				format = PintaCore.System.ImageFormats.GetFormatByFile (file);

			if (format == null || format.IsReadOnly ()) {
				MessageDialog md = new MessageDialog (PintaCore.Chrome.MainWindow, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, Catalog.GetString ("Pinta does not support saving images in this file format."), file);
				md.Title = Catalog.GetString ("Error");

				md.Run ();
				md.Destroy ();
				return false;
			}

			// Commit any pending changes
			PintaCore.Tools.Commit ();

			format.Exporter.Export (document, file);

			document.Filename = Path.GetFileName (file);
			document.IsDirty = false;

			return true;
		}

		private bool ConfirmOverwrite (FileChooserDialog fcd, string file)
		{
			string primary = Catalog.GetString ("A file named \"{0}\" already exists. Do you want to replace it?");
			string secondary = Catalog.GetString ("The file already exists in \"{1}\". Replacing it will overwrite its contents.");
			string message = string.Format (markup, primary, secondary);

			MessageDialog md = new MessageDialog (fcd, DialogFlags.Modal | DialogFlags.DestroyWithParent,
				MessageType.Question, ButtonsType.None,
				true, message, System.IO.Path.GetFileName (file), fcd.CurrentFolder);

			md.AddButton (Stock.Cancel, ResponseType.Cancel);
			md.AddButton (Stock.Save, ResponseType.Ok);
			md.DefaultResponse = ResponseType.Cancel;
			md.AlternativeButtonOrder = new int[] { (int)ResponseType.Ok, (int)ResponseType.Cancel };

			int response = md.Run ();
			md.Destroy ();

			return response == (int)ResponseType.Ok;
		}

	}
}
<commit_msg>[Fixes bug #846755] Make the Save As action work properly (prompt for a filename)<commit_after>﻿// 
// SaveDocumentImplmentationAction.cs
//  
// Author:
//       <NAME> <<EMAIL>>
// 
// Copyright (c) 2010 <NAME>
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using Gtk;
using Mono.Unix;
using Pinta.Core;
using System.IO;
using System.Collections.Generic;

namespace Pinta.Actions
{
	class SaveDocumentImplmentationAction : IActionHandler
	{
		private const string markup = "<span weight=\"bold\" size=\"larger\">{0}</span>\n\n{1}";

		#region IActionHandler Members
		public void Initialize ()
		{
			PintaCore.Actions.File.SaveDocument += Activated;
		}

		public void Uninitialize ()
		{
			PintaCore.Actions.File.SaveDocument -= Activated;
		}
		#endregion

		private void Activated (object sender, DocumentCancelEventArgs e)
		{
            // Prompt for a new filename for "Save As", or a document that hasn't been saved before
            if (e.SaveAs || !e.Document.HasFile)
            {
                e.Cancel = !SaveFileAs (e.Document);
            }
            else
            {
                // Document hasn't changed, don't re-save it
                if (!e.Document.IsDirty)
                    return;
                
                // If the document already has a filename, just re-save it
                e.Cancel = !SaveFile (e.Document, null, null);
            }			
		}

		// This is actually both for "Save As" and saving a file that never
		// been saved before.  Either way, we need to prompt for a filename.
		private bool SaveFileAs (Document document)
		{
			var fcd = new FileChooserDialog (Mono.Unix.Catalog.GetString ("Save Image File"),
									       PintaCore.Chrome.MainWindow,
									       FileChooserAction.Save,
									       Gtk.Stock.Cancel,
									       Gtk.ResponseType.Cancel,
									       Gtk.Stock.Save, Gtk.ResponseType.Ok);

			fcd.DoOverwriteConfirmation = true;
			fcd.SetCurrentFolder (PintaCore.System.LastDialogDirectory);
			fcd.AlternativeButtonOrder = new int[] { (int)ResponseType.Ok, (int)ResponseType.Cancel };

			bool hasFile = document.HasFile;

			if (hasFile)
				fcd.SetFilename (document.PathAndFileName);

			Dictionary<FileFilter, FormatDescriptor> filetypes = new Dictionary<FileFilter, FormatDescriptor> ();

			// Add all the formats we support to the save dialog
			foreach (var format in PintaCore.System.ImageFormats.Formats) {
				if (!format.IsReadOnly ()) {
					fcd.AddFilter (format.Filter);
					filetypes.Add (format.Filter, format);

					// Set the filter to anything we found
					// We want to ensure that *something* is selected in the filetype
					fcd.Filter = format.Filter;
				}
			}

			// If we already have a format, set it to the default.
			// If not, default to jpeg
			FormatDescriptor format_desc = null;

			if (hasFile)
				format_desc = PintaCore.System.ImageFormats.GetFormatByFile (document.Filename);

			if (format_desc == null) {
				format_desc = PintaCore.System.ImageFormats.GetDefaultSaveFormat ();

				// Gtk doesn't like it if we set the file name to an extension that we don't have
				// a filter for, so we change the extension to our default extension.
				if (hasFile)
					fcd.SetFilename (Path.ChangeExtension (document.PathAndFileName, format_desc.Extensions[0]));
			}

			fcd.Filter = format_desc.Filter;

			// Replace GTK's ConfirmOverwrite with our own, for UI consistency
			fcd.ConfirmOverwrite += (eventSender, eventArgs) => {
				if (this.ConfirmOverwrite (fcd, fcd.Filename))
					eventArgs.RetVal = FileChooserConfirmation.AcceptFilename;
				else
					eventArgs.RetVal = FileChooserConfirmation.SelectAgain;
			};

			while (fcd.Run () == (int)Gtk.ResponseType.Ok) {
				FormatDescriptor format = filetypes[fcd.Filter];
				string file = fcd.Filename;

				if (string.IsNullOrEmpty (Path.GetExtension (file))) {
					// No extension; add one from the format descriptor.
					file = string.Format ("{0}.{1}", file, format.Extensions[0]);
					fcd.CurrentName = Path.GetFileName (file);

					// We also need to display an overwrite confirmation message manually,
					// because MessageDialog won't do this for us in this case.
					if (File.Exists (file) && !ConfirmOverwrite (fcd, file))
						continue;
				}

				// Always follow the extension rather than the file type drop down
				// ie: if the user chooses to save a "jpeg" as "foo.png", we are going
				// to assume they just didn't update the dropdown and really want png
				var format_type = PintaCore.System.ImageFormats.GetFormatByFile (file);

				if (format_type != null)
					format = format_type;

				PintaCore.System.LastDialogDirectory = fcd.CurrentFolder;
				SaveFile (document, file, format);
				RecentManager.Default.AddFull (fcd.Uri, PintaCore.System.RecentData);
				PintaCore.System.ImageFormats.SetDefaultFormat (Path.GetExtension (file));

				document.HasFile = true;
				document.PathAndFileName = file;

				fcd.Destroy ();
				return true;
			}

			fcd.Destroy ();
			return false;
		}

		private bool SaveFile (Document document, string file, FormatDescriptor format)
		{
			if (string.IsNullOrEmpty (file))
				file = document.PathAndFileName;

			if (format == null)
				format = PintaCore.System.ImageFormats.GetFormatByFile (file);

			if (format == null || format.IsReadOnly ()) {
				MessageDialog md = new MessageDialog (PintaCore.Chrome.MainWindow, DialogFlags.Modal, MessageType.Error, ButtonsType.Ok, Catalog.GetString ("Pinta does not support saving images in this file format."), file);
				md.Title = Catalog.GetString ("Error");

				md.Run ();
				md.Destroy ();
				return false;
			}

			// Commit any pending changes
			PintaCore.Tools.Commit ();

			format.Exporter.Export (document, file);

			document.Filename = Path.GetFileName (file);
			document.IsDirty = false;

			return true;
		}

		private bool ConfirmOverwrite (FileChooserDialog fcd, string file)
		{
			string primary = Catalog.GetString ("A file named \"{0}\" already exists. Do you want to replace it?");
			string secondary = Catalog.GetString ("The file already exists in \"{1}\". Replacing it will overwrite its contents.");
			string message = string.Format (markup, primary, secondary);

			MessageDialog md = new MessageDialog (fcd, DialogFlags.Modal | DialogFlags.DestroyWithParent,
				MessageType.Question, ButtonsType.None,
				true, message, System.IO.Path.GetFileName (file), fcd.CurrentFolder);

			md.AddButton (Stock.Cancel, ResponseType.Cancel);
			md.AddButton (Stock.Save, ResponseType.Ok);
			md.DefaultResponse = ResponseType.Cancel;
			md.AlternativeButtonOrder = new int[] { (int)ResponseType.Ok, (int)ResponseType.Cancel };

			int response = md.Run ();
			md.Destroy ();

			return response == (int)ResponseType.Ok;
		}

	}
}

{'fraction_non_alphanumeric': 0.10162972620599739, 'fraction_numerical': 0.001955671447196871, 'mean_word_length': 3.2250068851556044, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '672684', 'n_tokens_mistral': 5183, 'n_tokens_neox': 4308, 'n_words': 1453}