How to Tell If a PowerPoint Presentation Has Unsaved Changes?

My app allows the user to create and edit one or more presentations at a time. How can I tell if a presentation has any unsaved changes?

@kippow,

Could you please elaborate your query/requirements and provide more details on it? Additionally, kindly zip and attach sample presentation which has unsaved changes. If possible, please share some screenshots to demonstrate on how you could accomplish the task in PowerPoint options/commands manually. We will understand your needs precisely and then evaluate it.

I have a c# project which creates one or more presentations simultaneously based on interactive user selections. I need to be able to determine if any presentation has unsaved changes. I keep the presentations in a list and I need to know if any of them have changes that have not been saved before closing the application.

I can’t imagine what you mean when you ask for a sample presentation that has unsaved changes. That isn’t even possible.

In PowerPoint automation I would check the value of Presentation.Saved to determine whether the presenation has unsaved changes.

@kippow,

Thanks for providing further details.

I am afraid, there is no Presentation.Saved or relevant attribute in Aspose.Slides APIs. Anyways, we need to evaluate your requirements/issue in details. We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): SLIDESNET-44300

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Thank you. We currently use other Aspose products and are evaluating Aspose Slides.

It would also be very helpful for the Presentation class to have a FullFilePath property.

@kippow,

We need to evaluate if this can be supported. We have opened the following new ticket in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): SLIDESNET-44301

Once we have an update on it, we will let you know.

@kippow,

The changes proposed by you will have a negative impact on the API. The point is that the Presentation class does not represent the presentation file, but the presentation itself, so properties like FileName and IsSaved are irrelevant. Therefore, we can propose to you to use a wrapper over the Presentation class that implements the logic of the presentation file, which implements all the properties required by you:

class PresentationFile : IDisposable
{
    private string m_hash = "";
    private bool m_disposed = false;

    public Presentation Presentation { get; private set; }
    public bool Saved { get { return GetHash() == m_hash; } } // SLIDESNET-44300
    public string FileName { get { return Path.GetFileName(FullFileName); } } // SLIDESNET-44301
    public string FullFileName { get; private set; } // SLIDESNET-44301

    public PresentationFile()
    {
        FullFileName = m_hash = string.Empty;
        Presentation = new Presentation();
    }
    public PresentationFile(string path)
    {
        if (File.Exists(path))
        {
            FullFileName = Path.GetFullPath(path);
            Presentation = new Presentation(FullFileName);
            m_hash = GetHash();
        }
        else
            throw new ArgumentException();
    }
    public void Save()
    {
        if (!string.IsNullOrEmpty(FullFileName))
            SaveAs(FullFileName);
        else
            throw new Exception();
    }
    public void SaveAs(string fileName)
    {
        FullFileName = Path.GetFullPath(fileName);
        Presentation.Save(FullFileName, SaveFormat.Pptx);
        m_hash = GetHash();
    }
    private string GetHash()
    {
        using (MemoryStream ms = new MemoryStream())
        {
            // md5 is not most efficient way, but simplest one
            using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
            {
                Presentation.Save(ms, SaveFormat.Pptx);
                ms.Seek(0, SeekOrigin.Begin);
                byte[] hash = md5.ComputeHash(ms);
                return Convert.ToBase64String(hash);
            }
        }
    }
    public void Dispose()
    {
        if (!m_disposed && Presentation != null)
            Presentation.Dispose();

        m_disposed = true;
    }
}

This test shows an example of how to use this wrapper:

public void PresentationFile_Test()
{
    string path = "presentation.pptx";
    string path2 = "presentation2.pptx";

    // create new presentation
    using (PresentationFile pres = new PresentationFile())
    {
        // initially presentation is not saved
        Assert.IsFalse(pres.Saved);
        // if you try to save - exception will be thrown, because file name not set
        Assert.Throws<Exception>(() => pres.Save());
        // right way to FIRST save
        Assert.DoesNotThrow(() => pres.SaveAs(path));
        // now we can get FileName, and FullFileName
        Assert.AreEqual(path, pres.FileName);
        // Save() works - file name is set 
        Assert.DoesNotThrow(() => pres.Save());
        // Saved == true 
        Assert.IsTrue(pres.Saved);
        // make some change in presentation
        pres.Presentation.Slides.AddEmptySlide(pres.Presentation.LayoutSlides[0]);
        // and now Saved == false 
        Assert.IsFalse(pres.Saved);
        // you should save it
        Assert.DoesNotThrow(() => pres.Save());
    }

    // open presentation
    using (PresentationFile pres = new PresentationFile(path))
    {
        // initially presentation is saved
        Assert.IsTrue(pres.Saved);
        // Save() works - file name is set 
        Assert.DoesNotThrow(() => pres.Save());
        // save as copy
        Assert.DoesNotThrow(() => pres.SaveAs(path2));
        Assert.AreEqual(path2, pres.FileName);
        Assert.DoesNotThrow(() => pres.Save());
        // Saved == true 
        Assert.IsTrue(pres.Saved);
        // make some change in presentation
        pres.Presentation.Slides.RemoveAt(0);
        // and now Saved == false 
        Assert.IsFalse(pres.Saved);
        // you should save it
        Assert.DoesNotThrow(() => pres.Save());
    }
}

Let us know if it works for your needs.

Thanks. I actually did implement something very similar to this.