// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * @brief Implementation of the file dialog interfaces defined in filedialogimpl.h
 */
/* Authors:
 *   Bob Jamison
 *   Johan Engelen <johan@shouraizou.nl>
 *   Joel Holdsworth
 *   Bruno Dilly
 *   Others from The Inkscape Organization
 *
 * Copyright (C) 2004-2008 Authors
 * Copyright (C) 2004-2007 The Inkscape Organization
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#ifndef SEEN_FILE_DIALOG_IMPL_GTKMM_H
#define SEEN_FILE_DIALOG_IMPL_GTKMM_H

#include <gtkmm/checkbutton.h>
#include <vector>
#include <giomm/file.h>
#include <glibmm/ustring.h>

#ifdef LINUX_SNAP_PACKAGE
// the snap package uses the native file dialog (which is then redirected via XDG desktop portal)
#include <gtkmm/filechoosernative.h>
#else
#include <gtkmm/filechooserdialog.h>
#endif

#include "filedialog.h"
#include "ui/dialog/svg-preview.h"

namespace Gtk {
class Entry;
class FileFilter;
class Window;
} // namespace Gtk

namespace Inkscape {

class URI;

namespace UI {

namespace View {
class SVGViewWidget;
} // namespace View

namespace Dialog {

/*#########################################################################
### F I L E     D I A L O G    B A S E    C L A S S
#########################################################################*/

/**
 * This class is the base implementation for the others.  This
 * reduces redundancies and bugs.
 */
class FileDialogBaseGtk :
#ifdef LINUX_SNAP_PACKAGE
 public Gtk::FileChooserNative
#else
 public Gtk::FileChooserDialog
#endif
{
public:
    FileDialogBaseGtk(Gtk::Window &parentWindow, Glib::ustring const &title,
    		      Gtk::FileChooserAction dialogType, FileDialogType type,
                      char const *preferenceBase);
    ~FileDialogBaseGtk() override;

    /**
     * Add a Gtk filter to our specially controlled filter dropdown.
     */
    Glib::RefPtr<Gtk::FileFilter> addFilter(const Glib::ustring &name, Glib::ustring pattern = "",
                                            Inkscape::Extension::Extension *mod = nullptr);

    Glib::ustring extToPattern(const Glib::ustring &extension) const;

private:
#ifdef LINUX_SNAP_PACKAGE
    const char * accept_label(Gtk::FileChooserAction dialogType);
    const char * cancel_label();
#endif
protected:

    Glib::ustring const _preferenceBase;

    /**
     * What type of 'open' are we? (open, import, place, etc)
     */
    FileDialogType _dialogType;

    /**
     * Maps extension <-> filter.
     */
    std::map<Glib::RefPtr<Gtk::FileFilter>, Inkscape::Extension::Extension *> filterExtensionMap;
    std::map<Inkscape::Extension::Extension *, Glib::RefPtr<Gtk::FileFilter>> extensionFilterMap;
};

/*#########################################################################
### F I L E    O P E N
#########################################################################*/

/**
 * Our implementation class for the FileOpenDialog interface..
 */
class FileOpenDialogImplGtk final
    : public FileOpenDialog
    , public FileDialogBaseGtk
{
public:
    FileOpenDialogImplGtk(Gtk::Window& parentWindow,
                          const std::string &dir,
                          FileDialogType fileTypes,
                          const Glib::ustring &title);

    bool show() final;

    void setSelectMultiple(bool value) final { set_select_multiple(value); }
    std::vector<Glib::RefPtr<Gio::File>> getFiles() final { return get_files(); }
    Glib::RefPtr<Gio::File>        const getFile()  final { return get_file(); }

    std::string getCurrentDirectory() final { return get_current_folder(); }

    void addFilterMenu(const Glib::ustring &name, Glib::ustring pattern = "",
                       Inkscape::Extension::Extension *mod = nullptr) final
    {
        addFilter(name, pattern, mod);
    }

private:
    /**
     *  Create a filter menu for this type of dialog
     */
    void createFilterMenu();

#if true // for v1.4
    void updatePreviewCallback();
    SVGPreview _preview;
    Gtk::CheckButton previewCheckbox;
#endif
};

//########################################################################
//# F I L E    S A V E
//########################################################################

/**
 * Our implementation of the FileSaveDialog interface.
 */
class FileSaveDialogImplGtk final
    : public FileSaveDialog
    , public FileDialogBaseGtk
{
public:
    FileSaveDialogImplGtk(Gtk::Window &parentWindow,
                          const std::string &dir,
                          FileDialogType fileTypes,
                          const Glib::ustring &title,
                          const Glib::ustring &default_key,
                          const gchar* docTitle,
                          const Inkscape::Extension::FileSaveMethod save_method);

    bool show() final;

    // One at a time.
    const Glib::RefPtr<Gio::File> getFile() final { return get_file(); }

    void setCurrentName(Glib::ustring name) final { set_current_name(name); }
    std::string getCurrentDirectory() final { return get_current_folder(); }

    // Sets module for saving, updating GUI if necessary.
    bool setExtension(Glib::ustring const &filename_utf8);
    void setExtension(Inkscape::Extension::Extension *key) final;

    void addFilterMenu(const Glib::ustring &name, Glib::ustring pattern = {},
                       Inkscape::Extension::Extension *mod = nullptr) final
    {
        addFilter(name, pattern, mod);
    }

private:

    /**
     * The file save method (essentially whether the dialog was invoked by "Save as ..." or "Save a
     * copy ..."), which is used to determine file extensions and save paths.
     */
    Inkscape::Extension::FileSaveMethod save_method;

    /**
     *  Create a filter menu for this type of dialog
     */
    void createFilterMenu();

    /**
     * Callback for filefilter.
     */
    void filefilterChanged();

    /**
     * Callback for filename.
     */
    void filenameChanged();
    bool from_filename_changed = false;
};

} // namespace Dialog
} // namespace UI
} // namespace Inkscape

#endif // SEEN_FILE_DIALOG_IMPL_GTKMM_H

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
