summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJoel Holdsworth <joel@airwebreathe.org.uk>2008-02-23 12:56:59 +0000
committerjoelholdsworth <joelholdsworth@users.sourceforge.net>2008-02-23 12:56:59 +0000
commit9d8ae74ac16a9a8023c476ad0dc7f95792abe7f5 (patch)
tree7f13097645af6641b3351decc199fb9c8c87f8a8 /src
parentpartial fix sent by jfb for bug #188814 (diff)
downloadinkscape-9d8ae74ac16a9a8023c476ad0dc7f95792abe7f5.tar.gz
inkscape-9d8ae74ac16a9a8023c476ad0dc7f95792abe7f5.zip
Merged in Native File Dialogs for Windows Branch
(bzr r4830)
Diffstat (limited to 'src')
-rw-r--r--src/dialogs/filedialog-win32.cpp381
-rw-r--r--src/file.cpp99
-rw-r--r--src/inkscape.rc3
-rw-r--r--src/inkview.rc2
-rw-r--r--src/ui/dialog/filedialog.cpp103
-rw-r--r--src/ui/dialog/filedialog.h65
-rw-r--r--src/ui/dialog/filedialogimpl-gtkmm.cpp118
-rw-r--r--src/ui/dialog/filedialogimpl-gtkmm.h43
-rw-r--r--src/ui/dialog/filedialogimpl-win32.cpp1461
-rw-r--r--src/ui/dialog/filedialogimpl-win32.h348
10 files changed, 2046 insertions, 577 deletions
diff --git a/src/dialogs/filedialog-win32.cpp b/src/dialogs/filedialog-win32.cpp
deleted file mode 100644
index ca9ce5f6c..000000000
--- a/src/dialogs/filedialog-win32.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include "filedialog.h"
-
-//#include "extension/internal/win32.h"
-
-#include <windows.h>
-
-#include <glib.h>
-
-#include <extension/extension.h>
-#include <extension/db.h>
-
-#define UNSAFE_SCRATCH_BUFFER_SIZE 4096
-
-namespace Inkscape
-{
-namespace UI
-{
-namespace Dialogs
-{
-
-/*#################################
-# U T I L I T Y
-#################################*/
-static gboolean
-win32_is_os_wide()
-{
- static gboolean initialized = FALSE;
- static gboolean is_wide = FALSE;
- static OSVERSIONINFOA osver;
-
- if ( !initialized )
- {
- BOOL result;
-
- initialized = TRUE;
-
- memset (&osver, 0, sizeof(OSVERSIONINFOA));
- osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
- result = GetVersionExA (&osver);
- if (result)
- {
- if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
- is_wide = TRUE;
- }
- // If we can't even call to get the version, fall back to ANSI API
- }
-
- return is_wide;
-}
-
-/*#################################
-# F I L E O P E N
-#################################*/
-
-struct FileOpenNativeData_def {
- char *dir;
- FileDialogType fileTypes;
- char *title;
-};
-
-FileOpenDialog::FileOpenDialog(
- const char *dir, FileDialogType fileTypes, const char *title) {
-
- nativeData = (FileOpenNativeData *)
- g_malloc(sizeof (FileOpenNativeData));
- if ( !nativeData ) {
- // do we want exceptions?
- return;
- }
-
- if ( !dir )
- dir = "";
- nativeData->dir = g_strdup(dir);
- nativeData->fileTypes = fileTypes;
- nativeData->title = g_strdup(title);
-
- extension = NULL;
- filename = NULL;
-}
-
-
-
-FileOpenDialog::~FileOpenDialog() {
-
- //do any cleanup here
- if ( nativeData ) {
- g_free(nativeData->dir);
- g_free(nativeData->title);
- g_free(nativeData);
- }
-
- if (filename) g_free(filename);
- extension = NULL;
-}
-
-
-
-bool
-FileOpenDialog::show() {
-
- if ( !nativeData ) {
- //error
- return FALSE;
- }
-
- gint retval = FALSE;
-
-
- //Jon's UNICODE patch
- if ( win32_is_os_wide() ) {
- gunichar2 fnbufW[UNSAFE_SCRATCH_BUFFER_SIZE * sizeof(gunichar2)] = {0};
- gunichar2* dirW =
- g_utf8_to_utf16( nativeData->dir, -1, NULL, NULL, NULL );
- gunichar2 *filterW = (gunichar2 *) L"";
- if ( nativeData->fileTypes == SVG_TYPES )
- filterW = (gunichar2 *) L"SVG files\0*.svg;*.svgz\0All files\0*\0";
- else if ( nativeData->fileTypes == IMPORT_TYPES )
- filterW = (gunichar2 *) L"Image files\0*.svg;*.png;*.jpg;*.jpeg;*.bmp;*.gif;*.tiff;*.xpm\0"
- L"SVG files\0*.svg\0"
- L"All files\0*\0";
- gunichar2* titleW =
- g_utf8_to_utf16( nativeData->title, -1, NULL, NULL, NULL );
- OPENFILENAMEW ofn = {
- sizeof (OPENFILENAMEW),
- NULL, // hwndOwner
- NULL, // hInstance
- (const WCHAR *)filterW, // lpstrFilter
- NULL, // lpstrCustomFilter
- 0, // nMaxCustFilter
- 1, // nFilterIndex
- (WCHAR *)fnbufW, // lpstrFile
- sizeof (fnbufW) / sizeof(WCHAR), // nMaxFile
- NULL, // lpstrFileTitle
- 0, // nMaxFileTitle
- (const WCHAR *)dirW, // lpstrInitialDir
- (const WCHAR *)titleW, // lpstrTitle
- OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // Flags
- 0, // nFileOffset
- 0, // nFileExtension
- NULL, // lpstrDefExt
- 0, // lCustData
- NULL, // lpfnHook
- NULL // lpTemplateName
- };
-
- retval = GetOpenFileNameW (&ofn);
- if (retval)
- filename = g_utf16_to_utf8( fnbufW, -1, NULL, NULL, NULL );
-
- g_free( dirW );
- g_free( titleW );
-
- } else {
- gchar *dir = nativeData->dir;
- gchar *title = nativeData->title;
- gchar fnbuf[UNSAFE_SCRATCH_BUFFER_SIZE] = {0};
-
- gchar *filter = "";
- if ( nativeData->fileTypes == SVG_TYPES )
- filter = "SVG files\0*.svg;*.svgz\0All files\0*\0";
- else if ( nativeData->fileTypes == IMPORT_TYPES )
- filter = "Image files\0*.svg;*.png;*.jpg;*.jpeg;*.bmp;*.gif;*.tiff;*.xpm\0"
- "SVG files\0*.svg\0"
- "All files\0*\0";
-
- OPENFILENAMEA ofn = {
- sizeof (OPENFILENAMEA),
- NULL, // hwndOwner
- NULL, // hInstance
- (const CHAR *)filter, // lpstrFilter
- NULL, // lpstrCustomFilter
- 0, // nMaxCustFilter
- 1, // nFilterIndex
- fnbuf, // lpstrFile
- sizeof (fnbuf), // nMaxFile
- NULL, // lpstrFileTitle
- 0, // nMaxFileTitle
- (const CHAR *)dir, // lpstrInitialDir
- (const CHAR *)title, // lpstrTitle
- OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // Flags
- 0, // nFileOffset
- 0, // nFileExtension
- NULL, // lpstrDefExt
- 0, // lCustData
- NULL, // lpfnHook
- NULL // lpTemplateName
- };
-
- retval = GetOpenFileNameA (&ofn);
- if ( retval ) {
- filename = g_strdup( fnbuf );
- /* ### We need to try something like this instead:
- GError *err = NULL;
- filename = g_filename_to_utf8(fnbuf, -1, NULL, NULL, &err);
- if ( !filename && err ) {
- g_warning("Charset conversion in show()[%d]%s\n",
- err->code, err->message);
- }
- */
- }
- }
-
- if ( !retval ) {
- //int errcode = CommDlgExtendedError();
- return FALSE;
- }
-
- return TRUE;
-
-}
-
-
-
-/*#################################
-# F I L E S A V E
-#################################*/
-
-struct FileSaveNativeData_def {
- OPENFILENAME ofn;
- gchar filter[UNSAFE_SCRATCH_BUFFER_SIZE];
- gchar fnbuf[4096];
-};
-
-
-
-FileSaveDialog::FileSaveDialog(
- const char *dir, FileDialogType fileTypes, const char *title, const char * default_key) {
-
- nativeData = (FileSaveNativeData *)
- g_malloc(sizeof (FileSaveNativeData));
- if ( !nativeData ) {
- //do we want exceptions?
- return;
- }
-
- extension = NULL;
- filename = NULL;
-
- int default_item = 0;
-
- GSList* extension_list = Inkscape::Extension::db.get_output_list();
- g_assert (extension_list != NULL);
-
- /* Make up the filter string for the save dialogue using the list
- ** of available output types.
- */
-
- gchar *p = nativeData->filter;
- int N = UNSAFE_SCRATCH_BUFFER_SIZE;
-
- int n = 1;
- for (GSList* i = g_slist_next (extension_list); i != NULL; i = g_slist_next(i)) {
-
- Inkscape::Extension::DB::IOExtensionDescription* d =
- reinterpret_cast<Inkscape::Extension::DB::IOExtensionDescription*>(i->data);
-
- if (!d->sensitive)
- continue;
-
- int w = snprintf (p, N, "%s", d->name);
- N -= w + 1;
- p += w + 1;
-
- w = snprintf (p, N, "*");
- N -= w + 1;
- p += w + 1;
-
- g_assert (N >= 0);
-
- /* Look to see if this extension is the default */
- if (default_key &&
- d->extension->get_id() &&
- strcmp (default_key, d->extension->get_id()) == 0) {
- default_item = n;
- extension = d->extension;
- }
-
- n++;
- }
-
- *p = '\0';
-
- nativeData->fnbuf[0] = '\0';
-
- if (dir) {
- /* We must check that dir is not something like
- ** c:\foo\ (ie with a trailing \). If it is,
- ** GetSaveFileName will give an error.
- */
- int n = strlen(dir);
- if (n > 0 && dir[n - 1] != '\\') {
- strncpy(nativeData->fnbuf, dir, sizeof(nativeData->fnbuf));
- }
- }
-
- OPENFILENAME ofn = {
- sizeof (OPENFILENAME),
- NULL, // hwndOwner
- NULL, // hInstance
- nativeData->filter, // lpstrFilter
- NULL, // lpstrCustomFilter
- 0, // nMaxCustFilter
- default_item, // nFilterIndex
- nativeData->fnbuf, // lpstrFile
- sizeof (nativeData->fnbuf), // nMaxFile
- NULL, // lpstrFileTitle
- 0, // nMaxFileTitle
- (const CHAR *)dir, // lpstrInitialDir
- (const CHAR *)title, // lpstrTitle
- OFN_HIDEREADONLY | OFN_NOCHANGEDIR, // Flags
- 0, // nFileOffset
- 0, // nFileExtension
- NULL, // lpstrDefExt
- 0, // lCustData
- NULL, // lpfnHook
- NULL // lpTemplateName
- };
-
- nativeData->ofn = ofn;
-}
-
-FileSaveDialog::~FileSaveDialog() {
-
- //do any cleanup here
- g_free(nativeData);
- if (filename) g_free(filename);
- extension = NULL;
-}
-
-bool
-FileSaveDialog::show() {
-
- if (!nativeData)
- return FALSE;
- int retval = GetSaveFileName (&(nativeData->ofn));
- if (!retval) {
- //int errcode = CommDlgExtendedError();
- return FALSE;
- }
-
- GSList* extension_list = Inkscape::Extension::db.get_output_list();
- g_assert (extension_list != NULL);
-
- /* Work out which extension corresponds to the user's choice of
- ** file type.
- */
- int n = nativeData->ofn.nFilterIndex - 1;
- GSList* i = g_slist_next (extension_list);
-
- while (n > 0 && i) {
- n--;
- i = g_slist_next(i);
- }
-
- Inkscape::Extension::DB::IOExtensionDescription* d =
- reinterpret_cast<Inkscape::Extension::DB::IOExtensionDescription*>(i->data);
-
- extension = d->extension;
-
- filename = g_strdup (nativeData->fnbuf);
- return TRUE;
-}
-
-
-
-
-
-
-
-
-} //namespace Dialogs
-} //namespace UI
-} //namespace Inkscape
-
-
-
-
diff --git a/src/file.cpp b/src/file.cpp
index c3e7e7583..b41d61426 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -367,8 +367,6 @@ void dump_ustr(Glib::ustring const &ustr)
g_message("---------------");
}
-static Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance = NULL;
-
/**
* Display an file Open selector. Open a document if OK is pressed.
* Can select single or multiple files for opening.
@@ -376,76 +374,85 @@ static Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance = NULL;
void
sp_file_open_dialog(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/)
{
-
//# Get the current directory for finding files
- Glib::ustring open_path;
- char *attr = (char *)prefs_get_string_attribute("dialogs.open", "path");
- if (attr)
- open_path = attr;
-
-
+ static Glib::ustring open_path;
+
+ if(open_path.empty())
+ {
+ gchar const *attr = prefs_get_string_attribute("dialogs.open", "path");
+ if (attr)
+ open_path = attr;
+ }
+
//# Test if the open_path directory exists
if (!Inkscape::IO::file_test(open_path.c_str(),
(GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
open_path = "";
-
+
//# If no open path, default to our home directory
- if (open_path.size() < 1)
- {
+ if (open_path.empty())
+ {
open_path = g_get_home_dir();
open_path.append(G_DIR_SEPARATOR_S);
- }
-
+ }
+
//# Create a dialog if we don't already have one
- if (!openDialogInstance) {
- openDialogInstance =
+ Inkscape::UI::Dialog::FileOpenDialog *openDialogInstance =
Inkscape::UI::Dialog::FileOpenDialog::create(
- parentWindow,
- open_path,
+ parentWindow, open_path,
Inkscape::UI::Dialog::SVG_TYPES,
- (char const *)_("Select file to open"));
- }
-
-
+ _("Select file to open"));
+
//# Show the dialog
bool const success = openDialogInstance->show();
+
+ //# Save the folder the user selected for later
+ open_path = openDialogInstance->getCurrentDirectory();
+
if (!success)
+ {
+ delete openDialogInstance;
return;
-
+ }
+
//# User selected something. Get name and type
Glib::ustring fileName = openDialogInstance->getFilename();
+
Inkscape::Extension::Extension *selection =
openDialogInstance->getSelectionType();
-
- //# Code to check & open iff multiple files.
- std::vector<Glib::ustring> flist=openDialogInstance->getFilenames();
-
+
+ //# Code to check & open if multiple files.
+ std::vector<Glib::ustring> flist = openDialogInstance->getFilenames();
+
+ //# We no longer need the file dialog object - delete it
+ delete openDialogInstance;
+ openDialogInstance = NULL;
+
//# Iterate through filenames if more than 1
if (flist.size() > 1)
+ {
+ for (unsigned int i = 0; i < flist.size(); i++)
{
- for (unsigned int i=1 ; i<flist.size() ; i++)
- {
- Glib::ustring fName = flist[i];
-
- if (Glib::file_test(fileName, Glib::FILE_TEST_IS_DIR)) {
- Glib::ustring newFileName = Glib::filename_to_utf8(fName);
+ fileName = flist[i];
+
+ Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
if ( newFileName.size() > 0 )
- fName = newFileName;
+ fileName = newFileName;
else
g_warning( "ERROR CONVERTING OPEN FILENAME TO UTF-8" );
#ifdef INK_DUMP_FILENAME_CONV
- g_message("Opening File %s\n",fileName);
+ g_message("Opening File %s\n", fileName.c_str());
#endif
sp_file_open(fileName, selection);
- }
}
+
return;
}
- if (fileName.size() > 0) {
-
+ if (!fileName.empty())
+ {
Glib::ustring newFileName = Glib::filename_to_utf8(fileName);
if ( newFileName.size() > 0)
@@ -699,7 +706,7 @@ sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, bool is_copy)
if ( save_loc_local.size() > 0)
save_loc = save_loc_local;
-
+
//# Show the SaveAs dialog
char const * dialog_title;
if (is_copy) {
@@ -712,20 +719,12 @@ sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, bool is_copy)
parentWindow,
save_loc,
Inkscape::UI::Dialog::SVG_TYPES,
- (char const *) _("Select file to save to"),
+ dialog_title,
default_extension
);
-
- saveDialog->change_title(dialog_title);
+
saveDialog->setSelectionType(extension);
-
- // allow easy access to the user's own templates folder
- gchar *templates = profile_path ("templates");
- if (Inkscape::IO::file_test(templates, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
- dynamic_cast<Gtk::FileChooser *>(saveDialog)->add_shortcut_folder(templates);
- }
- g_free (templates);
-
+
bool success = saveDialog->show();
if (!success) {
delete saveDialog;
diff --git a/src/inkscape.rc b/src/inkscape.rc
index 3e5b61548..d48b68c43 100644
--- a/src/inkscape.rc
+++ b/src/inkscape.rc
@@ -25,3 +25,6 @@ BEGIN
VALUE "Translation", 1033, 437
END
END
+
+1000 BITMAP "./show-preview.bmp"
+
diff --git a/src/inkview.rc b/src/inkview.rc
index 245bdc68b..9f643eb4c 100644
--- a/src/inkview.rc
+++ b/src/inkview.rc
@@ -25,3 +25,5 @@ BEGIN
VALUE "Translation", 1033, 437
END
END
+
+1000 BITMAP "./show-preview.bmp"
diff --git a/src/ui/dialog/filedialog.cpp b/src/ui/dialog/filedialog.cpp
index c3ca49c99..103b62485 100644
--- a/src/ui/dialog/filedialog.cpp
+++ b/src/ui/dialog/filedialog.cpp
@@ -14,6 +14,7 @@
#include "filedialog.h"
#include "filedialogimpl-gtkmm.h"
+#include "filedialogimpl-win32.h"
#include "gc-core.h"
#include <dialogs/dialog-events.h>
@@ -26,6 +27,49 @@ namespace Dialog
{
/*#########################################################################
+### U T I L I T Y
+#########################################################################*/
+
+bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext)
+{
+ int strLen = str.length();
+ int extLen = ext.length();
+ if (extLen > strLen)
+ return false;
+ int strpos = strLen-1;
+ for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--)
+ {
+ Glib::ustring::value_type ch = str[strpos];
+ if (ch != ext[extpos])
+ {
+ if ( ((ch & 0xff80) != 0) ||
+ static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] )
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool isValidImageFile(const Glib::ustring &fileName)
+{
+ std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats();
+ for (unsigned int i=0; i<formats.size(); i++)
+ {
+ Gdk::PixbufFormat format = formats[i];
+ std::vector<Glib::ustring>extensions = format.get_extensions();
+ for (unsigned int j=0; j<extensions.size(); j++)
+ {
+ Glib::ustring ext = extensions[j];
+ if (hasSuffix(fileName, ext))
+ return true;
+ }
+ }
+ return false;
+}
+
+/*#########################################################################
### F I L E O P E N
#########################################################################*/
@@ -35,10 +79,20 @@ namespace Dialog
FileOpenDialog *FileOpenDialog::create(Gtk::Window &parentWindow,
const Glib::ustring &path,
FileDialogType fileTypes,
- const Glib::ustring &title)
+ const char *title)
{
+#ifdef WIN32
+ FileOpenDialog *dialog = new FileOpenDialogImplWin32(parentWindow, path, fileTypes, title);
+#else
FileOpenDialog *dialog = new FileOpenDialogImplGtk(parentWindow, path, fileTypes, title);
- return dialog;
+#endif
+
+ return dialog;
+}
+
+Glib::ustring FileOpenDialog::getFilename()
+{
+ return myFilename;
}
//########################################################################
@@ -51,13 +105,54 @@ FileOpenDialog *FileOpenDialog::create(Gtk::Window &parentWindow,
FileSaveDialog *FileSaveDialog::create(Gtk::Window& parentWindow,
const Glib::ustring &path,
FileDialogType fileTypes,
- const Glib::ustring &title,
+ const char *title,
const Glib::ustring &default_key)
{
+#ifdef WIN32
+ FileSaveDialog *dialog = new FileSaveDialogImplWin32(parentWindow, path, fileTypes, title, default_key);
+#else
FileSaveDialog *dialog = new FileSaveDialogImplGtk(parentWindow, path, fileTypes, title, default_key);
+#endif
return dialog;
}
+Glib::ustring FileSaveDialog::getFilename()
+{
+ return myFilename;
+}
+
+//void FileSaveDialog::change_path(const Glib::ustring& path)
+//{
+// myFilename = path;
+//}
+
+void FileSaveDialog::appendExtension(Glib::ustring& path, Inkscape::Extension::Output* outputExtension)
+{
+ try {
+ bool appendExtension = true;
+ Glib::ustring utf8Name = Glib::filename_to_utf8( path );
+ Glib::ustring::size_type pos = utf8Name.rfind('.');
+ if ( pos != Glib::ustring::npos ) {
+ Glib::ustring trail = utf8Name.substr( pos );
+ Glib::ustring foldedTrail = trail.casefold();
+ if ( (trail == ".")
+ | (foldedTrail != Glib::ustring( outputExtension->get_extension() ).casefold()
+ && ( knownExtensions.find(foldedTrail) != knownExtensions.end() ) ) ) {
+ utf8Name = utf8Name.erase( pos );
+ } else {
+ appendExtension = false;
+ }
+ }
+
+ if (appendExtension) {
+ utf8Name = utf8Name + outputExtension->get_extension();
+ myFilename = Glib::filename_from_utf8( utf8Name );
+ }
+ } catch ( Glib::ConvertError& e ) {
+ // ignore
+ }
+}
+
//########################################################################
//# F I L E E X P O R T
//########################################################################
@@ -68,7 +163,7 @@ FileSaveDialog *FileSaveDialog::create(Gtk::Window& parentWindow,
FileExportDialog *FileExportDialog::create(Gtk::Window& parentWindow,
const Glib::ustring &path,
FileDialogType fileTypes,
- const Glib::ustring &title,
+ const char *title,
const Glib::ustring &default_key)
{
FileExportDialog *dialog = new FileExportDialogImpl(parentWindow, path, fileTypes, title, default_key);
diff --git a/src/ui/dialog/filedialog.h b/src/ui/dialog/filedialog.h
index 75c6f0080..a3d5c0ea9 100644
--- a/src/ui/dialog/filedialog.h
+++ b/src/ui/dialog/filedialog.h
@@ -16,17 +16,16 @@
#include <glibmm.h>
#include <vector>
+#include <set>
#include <gtkmm.h>
namespace Inkscape {
namespace Extension {
class Extension;
+class Output;
}
}
-
-
-
namespace Inkscape
{
namespace UI
@@ -34,8 +33,6 @@ namespace UI
namespace Dialog
{
-
-
/**
* Used for setting filters and options, and
* reading them back from user selections.
@@ -54,12 +51,18 @@ typedef enum {
SVG_NAMESPACE_WITH_EXTENSIONS
} FileDialogSelectionType;
+
/**
- * Architecture-specific data
+ * Return true if the string ends with the given suffix
*/
-typedef struct FileOpenNativeData_def FileOpenNativeData;
+bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext);
/**
+ * Return true if the image is loadable by Gdk, else false
+ */
+bool isValidImageFile(const Glib::ustring &fileName);
+
+/**
* This class provides an implementation-independent API for
* file "Open" dialogs. Using a standard interface obviates the need
* for ugly #ifdefs in file open code
@@ -87,7 +90,7 @@ public:
static FileOpenDialog *create(Gtk::Window& parentWindow,
const Glib::ustring &path,
FileDialogType fileTypes,
- const Glib::ustring &title);
+ const char *title);
/**
@@ -100,7 +103,7 @@ public:
* Show an OpenFile file selector.
* @return the selected path if user selected one, else NULL
*/
- virtual bool show() =0;
+ virtual bool show() = 0;
/**
* Return the 'key' (filetype) of the selection, if any
@@ -109,10 +112,18 @@ public:
*/
virtual Inkscape::Extension::Extension * getSelectionType() = 0;
- virtual Glib::ustring getFilename () =0;
-
- virtual std::vector<Glib::ustring> getFilenames () = 0;
+ Glib::ustring getFilename();
+ virtual std::vector<Glib::ustring> getFilenames() = 0;
+
+ virtual Glib::ustring getCurrentDirectory() = 0;
+
+protected:
+ /**
+ * Filename that was given
+ */
+ Glib::ustring myFilename;
+
}; //FileOpenDialog
@@ -146,9 +157,9 @@ public:
* @param key a list of file types from which the user can select
*/
static FileSaveDialog *create(Gtk::Window& parentWindow,
- const Glib::ustring &path,
+ const Glib::ustring &path,
FileDialogType fileTypes,
- const Glib::ustring &title,
+ const char *title,
const Glib::ustring &default_key);
@@ -174,17 +185,27 @@ public:
virtual void setSelectionType( Inkscape::Extension::Extension * key ) = 0;
- virtual Glib::ustring getFilename () =0;
-
/**
- * Change the window title.
+ * Get the file name chosen by the user. Valid after an [OK]
*/
- virtual void change_title(const Glib::ustring& title) =0;
+ Glib::ustring getFilename ();
+
+ virtual Glib::ustring getCurrentDirectory() = 0;
+protected:
+
+ /**
+ * Filename that was given
+ */
+ Glib::ustring myFilename;
+
/**
- * Change the default save path location.
+ * List of known file extensions.
*/
- virtual void change_path(const Glib::ustring& path) =0;
+ std::set<Glib::ustring> knownExtensions;
+
+
+ void appendExtension(Glib::ustring& path, Inkscape::Extension::Output* outputExtension);
}; //FileSaveDialog
@@ -226,9 +247,9 @@ public:
* @param key a list of file types from which the user can select
*/
static FileExportDialog *create(Gtk::Window& parentWindow,
- const Glib::ustring &path,
+ const Glib::ustring &path,
FileDialogType fileTypes,
- const Glib::ustring &title,
+ const char *title,
const Glib::ustring &default_key);
diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp
index a1773d39a..1405e11aa 100644
--- a/src/ui/dialog/filedialogimpl-gtkmm.cpp
+++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp
@@ -495,55 +495,6 @@ void SVGPreview::showTooLarge(long fileLength)
}
-
-/**
- * Return true if the string ends with the given suffix
- */
-static bool
-hasSuffix(Glib::ustring &str, Glib::ustring &ext)
-{
- int strLen = str.length();
- int extLen = ext.length();
- if (extLen > strLen)
- return false;
- int strpos = strLen-1;
- for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--)
- {
- Glib::ustring::value_type ch = str[strpos];
- if (ch != ext[extpos])
- {
- if ( ((ch & 0xff80) != 0) ||
- static_cast<Glib::ustring::value_type>( g_ascii_tolower( static_cast<gchar>(0x07f & ch) ) ) != ext[extpos] )
- {
- return false;
- }
- }
- }
- return true;
-}
-
-
-/**
- * Return true if the image is loadable by Gdk, else false
- */
-static bool
-isValidImageFile(Glib::ustring &fileName)
-{
- std::vector<Gdk::PixbufFormat>formats = Gdk::Pixbuf::get_formats();
- for (unsigned int i=0; i<formats.size(); i++)
- {
- Gdk::PixbufFormat format = formats[i];
- std::vector<Glib::ustring>extensions = format.get_extensions();
- for (unsigned int j=0; j<extensions.size(); j++)
- {
- Glib::ustring ext = extensions[j];
- if (hasSuffix(fileName, ext))
- return true;
- }
- }
- return false;
-}
-
bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
{
@@ -677,7 +628,7 @@ void FileDialogBaseGtk::_updatePreviewCallback()
return;
}
- svgPreview.set(fileName, dialogType);
+ svgPreview.set(fileName, _dialogType);
}
@@ -692,7 +643,7 @@ FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow,
const Glib::ustring &dir,
FileDialogType fileTypes,
const Glib::ustring &title) :
- FileDialogBaseGtk(parentWindow, title, fileTypes, "dialogs.open")
+ FileDialogBaseGtk(parentWindow, title, Gtk::FILE_CHOOSER_ACTION_OPEN, fileTypes, "dialogs.open")
{
@@ -712,7 +663,7 @@ FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window& parentWindow,
myFilename = "";
/* Set our dialog type (open, import, etc...)*/
- dialogType = fileTypes;
+ _dialogType = fileTypes;
/* Set the pwd and/or the filename */
@@ -864,7 +815,7 @@ FileOpenDialogImplGtk::getSelectionType()
Glib::ustring
FileOpenDialogImplGtk::getFilename (void)
{
- return g_strdup(myFilename.c_str());
+ return myFilename;
}
@@ -881,7 +832,10 @@ std::vector<Glib::ustring>FileOpenDialogImplGtk::getFilenames()
return result;
}
-
+Glib::ustring FileOpenDialogImplGtk::getCurrentDirectory()
+{
+ return get_current_folder();
+}
@@ -915,7 +869,7 @@ FileSaveDialogImplGtk::FileSaveDialogImplGtk( Gtk::Window &parentWindow,
myFilename = "";
/* Set our dialog type (save, export, etc...)*/
- dialogType = fileTypes;
+ _dialogType = fileTypes;
/* Set the pwd and/or the filename */
if (dir.size() > 0)
@@ -974,7 +928,13 @@ FileSaveDialogImplGtk::FileSaveDialogImplGtk( Gtk::Window &parentWindow,
expander->set_expanded(true);
}
-
+ // allow easy access to the user's own templates folder
+ gchar *templates = profile_path ("templates");
+ if (Inkscape::IO::file_test(templates, (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)))
+ add_shortcut_folder(templates);
+ g_free (templates);
+
+
//if (extension == NULL)
// checkbox.set_sensitive(FALSE);
@@ -1179,22 +1139,17 @@ void FileSaveDialogImplGtk::setSelectionType( Inkscape::Extension::Extension * k
}
}
-
-/**
- * Get the file name chosen by the user. Valid after an [OK]
- */
-Glib::ustring
-FileSaveDialogImplGtk::getFilename()
+Glib::ustring FileSaveDialogImplGtk::getCurrentDirectory()
{
- return myFilename;
+ return get_current_folder();
}
-void
+/*void
FileSaveDialogImplGtk::change_title(const Glib::ustring& title)
{
- this->set_title(title);
-}
+ set_title(title);
+}*/
/**
* Change the default save path location.
@@ -1202,7 +1157,8 @@ FileSaveDialogImplGtk::change_title(const Glib::ustring& title)
void
FileSaveDialogImplGtk::change_path(const Glib::ustring& path)
{
- myFilename = path;
+ myFilename = path;
+
if (Glib::file_test(myFilename, Glib::FILE_TEST_IS_DIR)) {
//fprintf(stderr,"set_current_folder(%s)\n",myFilename.c_str());
set_current_folder(myFilename);
@@ -1243,30 +1199,8 @@ void FileSaveDialogImplGtk::updateNameAndExtension()
Inkscape::Extension::Output* newOut = extension ? dynamic_cast<Inkscape::Extension::Output*>(extension) : 0;
if ( fileTypeCheckbox.get_active() && newOut ) {
- try {
- bool appendExtension = true;
- Glib::ustring utf8Name = Glib::filename_to_utf8( myFilename );
- Glib::ustring::size_type pos = utf8Name.rfind('.');
- if ( pos != Glib::ustring::npos ) {
- Glib::ustring trail = utf8Name.substr( pos );
- Glib::ustring foldedTrail = trail.casefold();
- if ( (trail == ".")
- | (foldedTrail != Glib::ustring( newOut->get_extension() ).casefold()
- && ( knownExtensions.find(foldedTrail) != knownExtensions.end() ) ) ) {
- utf8Name = utf8Name.erase( pos );
- } else {
- appendExtension = false;
- }
- }
-
- if (appendExtension) {
- utf8Name = utf8Name + newOut->get_extension();
- myFilename = Glib::filename_from_utf8( utf8Name );
- change_path(myFilename);
- }
- } catch ( Glib::ConvertError& e ) {
- // ignore
- }
+ // Append the file extension if it's not already present
+ appendExtension(myFilename, newOut);
}
}
@@ -1402,7 +1336,7 @@ FileExportDialogImpl::FileExportDialogImpl( Gtk::Window& parentWindow,
myFilename = "";
/* Set our dialog type (save, export, etc...)*/
- dialogType = fileTypes;
+ _dialogType = fileTypes;
/* Set the pwd and/or the filename */
if (dir.size()>0)
diff --git a/src/ui/dialog/filedialogimpl-gtkmm.h b/src/ui/dialog/filedialogimpl-gtkmm.h
index e5058d0c2..5bac9aa5b 100644
--- a/src/ui/dialog/filedialogimpl-gtkmm.h
+++ b/src/ui/dialog/filedialogimpl-gtkmm.h
@@ -23,7 +23,6 @@
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
-#include <set>
#include <libxml/parser.h>
#include <libxml/tree.h>
@@ -164,10 +163,10 @@ public:
*
*/
FileDialogBaseGtk(Gtk::Window& parentWindow, const Glib::ustring &title,
- FileDialogType type, gchar const* preferenceBase) :
- Gtk::FileChooserDialog(parentWindow, title),
+ Gtk::FileChooserAction dialogType, FileDialogType type, gchar const* preferenceBase) :
+ Gtk::FileChooserDialog(parentWindow, title, dialogType),
preferenceBase(preferenceBase ? preferenceBase : "unknown"),
- dialogType(type)
+ _dialogType(type)
{
internalSetup();
}
@@ -175,11 +174,11 @@ public:
/**
*
*/
- FileDialogBaseGtk(Gtk::Window& parentWindow, const Glib::ustring &title,
+ FileDialogBaseGtk(Gtk::Window& parentWindow, const char *title,
Gtk::FileChooserAction dialogType, FileDialogType type, gchar const* preferenceBase) :
Gtk::FileChooserDialog(parentWindow, title, dialogType),
preferenceBase(preferenceBase ? preferenceBase : "unknown"),
- dialogType(type)
+ _dialogType(type)
{
internalSetup();
}
@@ -197,14 +196,16 @@ protected:
/**
* What type of 'open' are we? (open, import, place, etc)
*/
- FileDialogType dialogType;
+ FileDialogType _dialogType;
/**
* Our svg preview widget
*/
SVGPreview svgPreview;
- //# Child widgets
+ /**
+ * Child widgets
+ */
Gtk::CheckButton previewCheckbox;
private:
@@ -248,7 +249,9 @@ public:
Glib::ustring getFilename();
- std::vector<Glib::ustring> getFilenames ();
+ std::vector<Glib::ustring> getFilenames();
+
+ Glib::ustring getCurrentDirectory();
private:
@@ -267,11 +270,6 @@ private:
*/
Inkscape::Extension::Extension *extension;
- /**
- * Filename that was given
- */
- Glib::ustring myFilename;
-
};
@@ -300,14 +298,13 @@ public:
Inkscape::Extension::Extension *getSelectionType();
virtual void setSelectionType( Inkscape::Extension::Extension * key );
- Glib::ustring getFilename();
+ Glib::ustring getCurrentDirectory();
- void change_title(const Glib::ustring& title);
+private:
+ //void change_title(const Glib::ustring& title);
void change_path(const Glib::ustring& path);
void updateNameAndExtension();
-private:
-
/**
* Fix to allow the user to type the file name
*/
@@ -351,16 +348,6 @@ private:
* Callback for user input into fileNameEntry
*/
void fileNameEntryChangedCallback();
-
- /**
- * Filename that was given
- */
- Glib::ustring myFilename;
-
- /**
- * List of known file extensions.
- */
- std::set<Glib::ustring> knownExtensions;
};
diff --git a/src/ui/dialog/filedialogimpl-win32.cpp b/src/ui/dialog/filedialogimpl-win32.cpp
new file mode 100644
index 000000000..63301862d
--- /dev/null
+++ b/src/ui/dialog/filedialogimpl-win32.cpp
@@ -0,0 +1,1461 @@
+/**
+ * Implementation of the file dialog interfaces defined in filedialog.h for Win32
+ *
+ * Authors:
+ * Joel Holdsworth
+ * The Inkscape Organization
+ *
+ * Copyright (C) 2004-2007 The Inkscape Organization
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef WIN32
+
+//General includes
+#include <list>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <set>
+#include <gdk/gdkwin32.h>
+#include <glib/gstdio.h>
+#include <glibmm/i18n.h>
+#include <gtkmm/window.h>
+
+//Inkscape includes
+#include "inkscape.h"
+#include "prefs-utils.h"
+#include <dialogs/dialog-events.h>
+#include <extension/input.h>
+#include <extension/output.h>
+#include <extension/db.h>
+
+#include <libnr/nr-pixops.h>
+#include <libnr/nr-translate-scale-ops.h>
+#include <display/nr-arena-item.h>
+#include <display/nr-arena.h>
+#include "sp-item.h"
+#include "canvas-arena.h"
+
+#include "filedialog.h"
+#include "filedialogimpl-win32.h"
+
+#include <zlib.h>
+#include <cairomm/win32_surface.h>
+#include <cairomm/context.h>
+
+using namespace std;
+using namespace Glib;
+using namespace Cairo;
+using namespace Gdk::Cairo;
+
+namespace Inkscape
+{
+namespace UI
+{
+namespace Dialog
+{
+
+const int PreviewWidening = 150;
+const char PreviewWindowClassName[] = "PreviewWnd";
+const unsigned long MaxPreviewFileSize = 1344; // kB
+
+#define IDC_SHOW_PREVIEW 1000
+
+// Windows 2000 version of OPENFILENAMEW
+struct OPENFILENAMEEXW : public OPENFILENAMEW {
+ void * pvReserved;
+ DWORD dwReserved;
+ DWORD FlagsEx;
+};
+
+struct Filter
+{
+ gunichar2* name;
+ glong name_length;
+ gunichar2* filter;
+ glong filter_length;
+ Inkscape::Extension::Extension* mod;
+};
+
+ustring utf16_to_ustring(const wchar_t *utf16string, int utf16length = -1)
+{
+ gchar *utf8string = g_utf16_to_utf8((const gunichar2*)utf16string,
+ utf16length, NULL, NULL, NULL);
+ ustring result(utf8string);
+ g_free(utf8string);
+
+ return result;
+}
+
+/*#########################################################################
+### F I L E D I A L O G B A S E C L A S S
+#########################################################################*/
+
+FileDialogBaseWin32::FileDialogBaseWin32(Gtk::Window &parent,
+ const Glib::ustring &dir, const gchar *title,
+ FileDialogType type, gchar const* /*preferenceBase*/) :
+ dialogType(type),
+ parent(parent),
+ _current_directory(dir)
+{
+ //_mutex = NULL;
+ _main_loop = NULL;
+
+ _title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL);
+
+ Glib::RefPtr<const Gdk::Window> parentWindow = parent.get_window();
+ g_assert(parentWindow->gobj() != NULL);
+ _ownerHwnd = (HWND)gdk_win32_drawable_get_handle((GdkDrawable*)parentWindow->gobj());
+}
+
+FileDialogBaseWin32::~FileDialogBaseWin32()
+{
+ g_free(_title);
+}
+
+Inkscape::Extension::Extension *FileDialogBaseWin32::getSelectionType()
+{
+ return _extension;
+}
+
+Glib::ustring FileDialogBaseWin32::getCurrentDirectory()
+{
+ return _current_directory;
+}
+
+/*#########################################################################
+### F I L E O P E N
+#########################################################################*/
+
+bool FileOpenDialogImplWin32::_show_preview = true;
+
+/**
+ * Constructor. Not called directly. Use the factory.
+ */
+FileOpenDialogImplWin32::FileOpenDialogImplWin32(Gtk::Window &parent,
+ const Glib::ustring &dir,
+ FileDialogType fileTypes,
+ const gchar *title) :
+ FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.open")
+{
+ // Initalize to Autodetect
+ _extension = NULL;
+
+ // Set our dialog type (open, import, etc...)
+ dialogType = fileTypes;
+
+ _show_preview_button_bitmap = NULL;
+ _preview_wnd = NULL;
+ _file_dialog_wnd = NULL;
+ _base_window_proc = NULL;
+
+ _preview_file_size = 0;
+ _preview_bitmap = NULL;
+ _preview_file_icon = NULL;
+ _preview_document_width = 0;
+ _preview_document_height = 0;
+ _preview_image_width = 0;
+ _preview_image_height = 0;
+
+ createFilterMenu();
+}
+
+
+/**
+ * Destructor
+ */
+FileOpenDialogImplWin32::~FileOpenDialogImplWin32()
+{
+ if(_filter != NULL)
+ delete[] _filter;
+ if(_extension_map != NULL)
+ delete[] _extension_map;
+}
+
+void FileOpenDialogImplWin32::createFilterMenu()
+{
+ list<Filter> filter_list;
+
+ // Compose the filter string
+ Inkscape::Extension::DB::InputList extension_list;
+ Inkscape::Extension::db.get_input_list(extension_list);
+
+ ustring all_inkscape_files_filter, all_image_files_filter;
+ Filter all_files, all_inkscape_files, all_image_files;
+
+ const gchar *all_files_filter_name = _("All Files");
+ const gchar *all_inkscape_files_filter_name = ("All Inkscape Files");
+ const gchar *all_image_files_filter_name = _("All Image Files");
+
+ // Calculate the amount of memory required
+ int filter_count = 3; // 3 - one for All Files, All Images and All Inkscape Files
+ int filter_length = 1;
+
+ for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();
+ current_item != extension_list.end(); current_item++)
+ {
+ Filter filter;
+
+ Inkscape::Extension::Input *imod = *current_item;
+ if (imod->deactivated()) continue;
+
+ // Type
+ filter.name = g_utf8_to_utf16(imod->get_filetypename(),
+ -1, NULL, &filter.name_length, NULL);
+
+ // Extension
+ const gchar *file_extension_name = imod->get_extension();
+ filter.filter = g_utf8_to_utf16(file_extension_name,
+ -1, NULL, &filter.filter_length, NULL);
+
+ filter.mod = imod;
+ filter_list.push_back(filter);
+
+ filter_length += filter.name_length +
+ filter.filter_length + 3; // Add 3 for two \0s and a *
+
+ // Add to the "All Inkscape Files" Entry
+ if(all_inkscape_files_filter.length() > 0)
+ all_inkscape_files_filter += ";*";
+ all_inkscape_files_filter += file_extension_name;
+ if( strncmp("image", imod->get_mimetype(), 5) == 0)
+ {
+ // Add to the "All Image Files" Entry
+ if(all_image_files_filter.length() > 0)
+ all_image_files_filter += ";*";
+ all_image_files_filter += file_extension_name;
+ }
+
+ filter_count++;
+ }
+
+ int extension_index = 0;
+ _extension_map = new Inkscape::Extension::Extension*[filter_count];
+
+ // Filter Image Files
+ all_image_files.name = g_utf8_to_utf16(all_image_files_filter_name,
+ -1, NULL, &all_image_files.name_length, NULL);
+ all_image_files.filter = g_utf8_to_utf16(all_image_files_filter.data(),
+ -1, NULL, &all_image_files.filter_length, NULL);
+ filter_list.push_front(all_image_files);
+ _extension_map[extension_index++] = NULL;
+
+ // Filter Inkscape Files
+ all_inkscape_files.name = g_utf8_to_utf16(all_inkscape_files_filter_name,
+ -1, NULL, &all_inkscape_files.name_length, NULL);
+ all_inkscape_files.filter = g_utf8_to_utf16(all_inkscape_files_filter.data(),
+ -1, NULL, &all_inkscape_files.filter_length, NULL);
+ filter_list.push_front(all_inkscape_files);
+ _extension_map[extension_index++] = NULL;
+
+ // Filter All Files
+ all_files.name = g_utf8_to_utf16(all_files_filter_name,
+ -1, NULL, &all_files.name_length, NULL);
+ all_files.filter = NULL;
+ all_files.filter_length = 0;
+ filter_list.push_front(all_files);
+ _extension_map[extension_index++] = NULL;
+
+ filter_length += all_files.name_length + 3 +
+ all_inkscape_files.filter_length +
+ all_inkscape_files.name_length + 3 +
+ all_image_files.filter_length +
+ all_image_files.name_length + 3 + 1;
+ // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0
+
+
+ _filter = new wchar_t[filter_length];
+ wchar_t *filterptr = _filter;
+
+ for(list<Filter>::iterator filter_iterator = filter_list.begin();
+ filter_iterator != filter_list.end(); filter_iterator++)
+ {
+ const Filter &filter = *filter_iterator;
+
+ memcpy(filterptr, filter.name, filter.name_length * 2);
+ filterptr += filter.name_length;
+ g_free(filter.name);
+
+ *(filterptr++) = L'\0';
+ *(filterptr++) = L'*';
+
+ if(filter.filter != NULL)
+ {
+ memcpy(filterptr, filter.filter, filter.filter_length * 2);
+ filterptr += filter.filter_length;
+ g_free(filter.filter);
+ }
+
+ *(filterptr++) = L'\0';
+
+ // Associate this input extension with the file type name
+ _extension_map[extension_index++] = filter.mod;
+ }
+ *(filterptr++) = L'\0';
+
+ _filterIndex = 2;
+}
+
+void FileOpenDialogImplWin32::GetOpenFileName_thread()
+{
+ OPENFILENAMEEXW ofn;
+
+ g_assert(this != NULL);
+ //g_assert(_mutex != NULL);
+ g_assert(_main_loop != NULL);
+
+ WCHAR* current_directory_string = (WCHAR*)g_utf8_to_utf16(
+ _current_directory.data(), -1, NULL, NULL, NULL);
+
+ memset(&ofn, 0, sizeof(ofn));
+
+ // Copy the selected file name, converting from UTF-8 to UTF-16
+ memset(_path_string, 0, sizeof(_path_string));
+ gunichar2* utf16_path_string = g_utf8_to_utf16(
+ myFilename.data(), -1, NULL, NULL, NULL);
+ wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);
+ g_free(utf16_path_string);
+
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = _ownerHwnd;
+ ofn.lpstrFile = _path_string;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = current_directory_string;
+ ofn.lpstrTitle = _title;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_ENABLESIZING;
+ ofn.lpstrFilter = _filter;
+ ofn.nFilterIndex = _filterIndex;
+ ofn.lpfnHook = GetOpenFileName_hookproc;
+ ofn.lCustData = (LPARAM)this;
+
+ _result = GetOpenFileNameW(&ofn) != 0;
+
+ _filterIndex = ofn.nFilterIndex;
+ _extension = _extension_map[ofn.nFilterIndex];
+
+ myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ // Copy the selected file name, converting from UTF-16 to UTF-8
+ myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ // Tidy up
+ g_free(current_directory_string);
+
+ _mutex->lock();
+ _finished = true;
+ _mutex->unlock();
+ //g_main_loop_quit(_main_loop);
+
+
+}
+
+void FileOpenDialogImplWin32::register_preview_wnd_class()
+{
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+ const WNDCLASSA PreviewWndClass =
+ {
+ CS_HREDRAW | CS_VREDRAW,
+ preview_wnd_proc,
+ 0,
+ 0,
+ hInstance,
+ NULL,
+ LoadCursor(hInstance, IDC_ARROW),
+ (HBRUSH)(COLOR_BTNFACE + 1),
+ NULL,
+ PreviewWindowClassName
+ };
+
+ RegisterClassA(&PreviewWndClass);
+}
+
+UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(
+ HWND hdlg, UINT uiMsg, WPARAM, LPARAM lParam)
+{
+ FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
+ GetWindowLongPtr(hdlg, GWLP_USERDATA);
+
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hParentWnd = GetParent(hdlg);
+ HINSTANCE hInstance = GetModuleHandle(NULL);
+
+ // Make the window a bit wider
+ RECT rcRect;
+ GetWindowRect(hParentWnd, &rcRect);
+ MoveWindow(hParentWnd, rcRect.left, rcRect.top,
+ rcRect.right - rcRect.left + PreviewWidening,
+ rcRect.bottom - rcRect.top,
+ FALSE);
+
+ // Set the pointer to the object
+ OPENFILENAMEW *ofn = (OPENFILENAMEW*)lParam;
+ SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData);
+ SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData);
+ pImpl = (FileOpenDialogImplWin32*)ofn->lCustData;
+
+ // Subclass the parent
+ pImpl->_base_window_proc = (WNDPROC)GetWindowLongPtr(hParentWnd, GWL_WNDPROC);
+ SetWindowLongPtr(hParentWnd, GWL_WNDPROC, (LONG_PTR)file_dialog_subclass_proc);
+
+ // Add a button to the toolbar
+ pImpl->_toolbar_wnd = FindWindowEx(hParentWnd, NULL, "ToolbarWindow32", NULL);
+
+ pImpl->_show_preview_button_bitmap = LoadBitmap(
+ hInstance, MAKEINTRESOURCE(IDC_SHOW_PREVIEW));
+ TBADDBITMAP tbAddBitmap = {NULL, (UINT)pImpl->_show_preview_button_bitmap};
+ const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd,
+ TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap);
+
+ TBBUTTON tbButton;
+ memset(&tbButton, 0, sizeof(TBBUTTON));
+ tbButton.iBitmap = iBitmapIndex;
+ tbButton.idCommand = IDC_SHOW_PREVIEW;
+ tbButton.fsState = (pImpl->_show_preview ? TBSTATE_CHECKED : 0)
+ | TBSTATE_ENABLED;
+ tbButton.fsStyle = TBSTYLE_CHECK;
+ tbButton.iString = (INT_PTR)_("Show Preview");
+ SendMessage(pImpl->_toolbar_wnd, TB_ADDBUTTONS, 1, (LPARAM)&tbButton);
+
+ // Create preview pane
+ register_preview_wnd_class();
+
+ pImpl->_mutex->lock();
+
+ pImpl->_file_dialog_wnd = hParentWnd;
+
+ pImpl->_preview_wnd =
+ CreateWindow(PreviewWindowClassName, "",
+ WS_CHILD | WS_VISIBLE,
+ 0, 0, 100, 100, hParentWnd, NULL, hInstance, NULL);
+ SetWindowLongPtr(pImpl->_preview_wnd, GWLP_USERDATA, ofn->lCustData);
+
+ pImpl->_mutex->unlock();
+
+ pImpl->layout_dialog();
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+
+ OFNOTIFY *pOFNotify = reinterpret_cast<OFNOTIFY*>(lParam);
+ switch(pOFNotify->hdr.code)
+ {
+ case CDN_SELCHANGE:
+ {
+ if(pImpl != NULL)
+ {
+ // Get the file name
+ pImpl->_mutex->lock();
+
+ SendMessage(pOFNotify->hdr.hwndFrom, CDM_GETFILEPATH,
+ sizeof(pImpl->_path_string) / sizeof(wchar_t),
+ (LPARAM)pImpl->_path_string);
+
+ pImpl->_file_selected = true;
+
+ pImpl->_mutex->unlock();
+
+ //pImpl->file_selected();
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ pImpl->_mutex->lock();
+ pImpl->_preview_file_size = 0;
+
+ pImpl->_file_dialog_wnd = NULL;
+ DestroyWindow(pImpl->_preview_wnd);
+ pImpl->_preview_wnd = NULL;
+ DeleteObject(pImpl->_show_preview_button_bitmap);
+ pImpl->_show_preview_button_bitmap = NULL;
+ pImpl->_mutex->unlock();
+
+ break;
+ }
+
+ // Use default dialog behaviour
+ return 0;
+}
+
+LRESULT CALLBACK FileOpenDialogImplWin32::file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
+ GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ LRESULT lResult = CallWindowProc(pImpl->_base_window_proc, hwnd, uMsg, wParam, lParam);
+
+ switch(uMsg)
+ {
+ case WM_SHOWWINDOW:
+ if(wParam != 0)
+ pImpl->layout_dialog();
+ break;
+
+ case WM_SIZE:
+ pImpl->layout_dialog();
+ break;
+
+ case WM_COMMAND:
+ if(wParam == IDC_SHOW_PREVIEW)
+ {
+ const bool enable = SendMessage(pImpl->_toolbar_wnd,
+ TB_ISBUTTONCHECKED, IDC_SHOW_PREVIEW, 0) != 0;
+ pImpl->enable_preview(enable);
+ }
+ break;
+ }
+
+ return lResult;
+}
+
+LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ const int CaptionPadding = 4;
+ const int IconSize = 32;
+
+ FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)
+ GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ LRESULT lResult = 0;
+
+ switch(uMsg)
+ {
+ case WM_ERASEBKGND:
+ // Do nothing to erase the background
+ // - otherwise there'll be flicker
+ lResult = 1;
+ break;
+
+ case WM_PAINT:
+ {
+ // Get the client rect
+ RECT rcClient;
+ GetClientRect(hwnd, &rcClient);
+
+ // Prepare to paint
+ PAINTSTRUCT paint_struct;
+ HDC dc = BeginPaint(hwnd, &paint_struct);
+
+ HFONT hCaptionFont = (HFONT)SendMessage(GetParent(hwnd),
+ WM_GETFONT, 0, 0);
+ HFONT hOldFont = (HFONT)SelectObject(dc, hCaptionFont);
+ SetBkMode(dc, TRANSPARENT);
+
+ pImpl->_mutex->lock();
+
+ //FillRect(dc, &client_rect, (HBRUSH)(COLOR_HOTLIGHT+1));
+ if(pImpl->_path_string[0] == 0)
+ {
+ FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
+ DrawText(dc, _("No file selected"), -1, &rcClient,
+ DT_CENTER | DT_VCENTER | DT_NOPREFIX);
+ }
+ else if(pImpl->_preview_bitmap != NULL)
+ {
+ BITMAP bitmap;
+ GetObject(pImpl->_preview_bitmap, sizeof(bitmap), &bitmap);
+ const int destX = (rcClient.right - bitmap.bmWidth) / 2;
+
+ // Render the image
+ HDC hSrcDC = CreateCompatibleDC(dc);
+ HBITMAP hOldBitmap = (HBITMAP)SelectObject(hSrcDC, pImpl->_preview_bitmap);
+
+ BitBlt(dc, destX, 0, bitmap.bmWidth, bitmap.bmHeight,
+ hSrcDC, 0, 0, SRCCOPY);
+
+ SelectObject(hSrcDC, hOldBitmap);
+ DeleteDC(hSrcDC);
+
+ // Fill in the background area
+ HRGN hEraseRgn = CreateRectRgn(rcClient.left, rcClient.top,
+ rcClient.right, rcClient.bottom);
+ HRGN hImageRgn = CreateRectRgn(destX, 0,
+ destX + bitmap.bmWidth, bitmap.bmHeight);
+ CombineRgn(hEraseRgn, hEraseRgn, hImageRgn, RGN_DIFF);
+
+ FillRgn(dc, hEraseRgn, GetSysColorBrush(COLOR_3DFACE));
+
+ DeleteObject(hImageRgn);
+ DeleteObject(hEraseRgn);
+
+ // Draw the caption on
+ RECT rcCaptionRect = {rcClient.left,
+ rcClient.top + bitmap.bmHeight + CaptionPadding,
+ rcClient.right, rcClient.bottom};
+
+ WCHAR szCaption[_MAX_FNAME + 32];
+ const int iLength = pImpl->format_caption(
+ szCaption, sizeof(szCaption) / sizeof(WCHAR));
+
+ DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
+ DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);
+ }
+ else if(pImpl->_preview_file_icon != NULL)
+ {
+ FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
+
+ // Draw the files icon
+ const int destX = (rcClient.right - IconSize) / 2;
+ DrawIconEx(dc, destX, 0, pImpl->_preview_file_icon,
+ IconSize, IconSize, 0, NULL,
+ DI_NORMAL | DI_COMPAT);
+
+ // Draw the caption on
+ RECT rcCaptionRect = {rcClient.left,
+ rcClient.top + IconSize + CaptionPadding,
+ rcClient.right, rcClient.bottom};
+
+ WCHAR szFileName[_MAX_FNAME], szCaption[_MAX_FNAME + 32];
+ _wsplitpath(pImpl->_path_string, NULL, NULL, szFileName, NULL);
+
+ const int iLength = snwprintf(szCaption,
+ sizeof(szCaption), L"%s\n%d kB",
+ szFileName, pImpl->_preview_file_size);
+
+ DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
+ DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);
+ }
+ else
+ {
+ // Can't show anything!
+ FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));
+ }
+
+ pImpl->_mutex->unlock();
+
+ // Finish painting
+ SelectObject(dc, hOldFont);
+ EndPaint(hwnd, &paint_struct);
+ }
+
+ break;
+
+ case WM_DESTROY:
+ pImpl->free_preview();
+ break;
+
+ default:
+ lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);
+ break;
+ }
+
+ return lResult;
+}
+
+void FileOpenDialogImplWin32::enable_preview(bool enable)
+{
+ _show_preview = enable;
+
+ // Relayout the dialog
+ ShowWindow(_preview_wnd, enable ? SW_SHOW : SW_HIDE);
+ layout_dialog();
+
+ // Load or unload the preview
+ if(enable)
+ {
+ _mutex->lock();
+ _file_selected = true;
+ _mutex->unlock();
+ }
+ else free_preview();
+}
+
+void FileOpenDialogImplWin32::layout_dialog()
+{
+ union RECTPOINTS
+ {
+ RECT r;
+ POINT p[2];
+ };
+
+ const float MaxExtentScale = 2.0f / 3.0f;
+
+ RECT rcClient;
+ GetClientRect(_file_dialog_wnd, &rcClient);
+
+ // Re-layout the dialog
+ HWND hFileListWnd = GetDlgItem(_file_dialog_wnd, lst2);
+ HWND hFolderComboWnd = GetDlgItem(_file_dialog_wnd, cmb2);
+
+
+ RECT rcFolderComboRect;
+ RECTPOINTS rcFileList;
+ GetWindowRect(hFileListWnd, &rcFileList.r);
+ GetWindowRect(hFolderComboWnd, &rcFolderComboRect);
+ const int iPadding = rcFileList.r.top - rcFolderComboRect.bottom;
+ MapWindowPoints(NULL, _file_dialog_wnd, rcFileList.p, 2);
+
+ RECT rcPreview;
+ RECT rcBody = {rcFileList.r.left, rcFileList.r.top,
+ rcClient.right - iPadding, rcFileList.r.bottom};
+ rcFileList.r.right = rcBody.right;
+
+ if(_show_preview)
+ {
+ rcPreview.top = rcBody.top;
+ rcPreview.left = rcClient.right - (rcBody.bottom - rcBody.top);
+ const int iMaxExtent = (int)(MaxExtentScale * (float)(rcBody.left + rcBody.right)) + iPadding / 2;
+ if(rcPreview.left < iMaxExtent) rcPreview.left = iMaxExtent;
+ rcPreview.bottom = rcBody.bottom;
+ rcPreview.right = rcBody.right;
+
+ // Re-layout the preview box
+ _mutex->lock();
+
+ _preview_width = rcPreview.right - rcPreview.left;
+ _preview_height = rcPreview.bottom - rcPreview.top;
+
+ _mutex->unlock();
+
+ render_preview();
+
+ MoveWindow(_preview_wnd, rcPreview.left, rcPreview.top,
+ _preview_width, _preview_height, TRUE);
+
+ rcFileList.r.right = rcPreview.left - iPadding;
+ }
+
+ // Re-layout the file list box
+ MoveWindow(hFileListWnd, rcFileList.r.left, rcFileList.r.top,
+ rcFileList.r.right - rcFileList.r.left,
+ rcFileList.r.bottom - rcFileList.r.top, TRUE);
+
+ // Re-layout the toolbar
+ RECTPOINTS rcToolBar;
+ GetWindowRect(_toolbar_wnd, &rcToolBar.r);
+ MapWindowPoints(NULL, _file_dialog_wnd, rcToolBar.p, 2);
+ MoveWindow(_toolbar_wnd, rcToolBar.r.left, rcToolBar.r.top,
+ rcToolBar.r.right - rcToolBar.r.left, rcToolBar.r.bottom - rcToolBar.r.top, TRUE);
+}
+
+void FileOpenDialogImplWin32::file_selected()
+{
+ // Destroy any previous previews
+ free_preview();
+
+
+ // Determine if the file exists
+ DWORD attributes = GetFileAttributesW(_path_string);
+ if(attributes == 0xFFFFFFFF ||
+ attributes == FILE_ATTRIBUTE_DIRECTORY)
+ {
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+ return;
+ }
+
+ // Check the file exists and get the file size
+ HANDLE file_handle = CreateFileW(_path_string, GENERIC_READ,
+ FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(file_handle == INVALID_HANDLE_VALUE) return;
+ const DWORD file_size = GetFileSize(file_handle, NULL);
+ if (file_size == INVALID_FILE_SIZE) return;
+ _preview_file_size = file_size / 1024;
+ CloseHandle(file_handle);
+
+ if(_show_preview) load_preview();
+}
+
+void FileOpenDialogImplWin32::load_preview()
+{
+ // Destroy any previous previews
+ free_preview();
+
+ // Try to get the file icon
+ SHFILEINFOW fileInfo;
+ if(SUCCEEDED(SHGetFileInfoW(_path_string, 0, &fileInfo,
+ sizeof(fileInfo), SHGFI_ICON | SHGFI_LARGEICON)))
+ _preview_file_icon = fileInfo.hIcon;
+
+ // Will this file be too big?
+ if(_preview_file_size > MaxPreviewFileSize)
+ {
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+ return;
+ }
+
+ // Prepare to render a preview
+ const Glib::ustring svg = ".svg";
+ const Glib::ustring svgz = ".svgz";
+ const Glib::ustring path = utf16_to_ustring(_path_string);
+
+ bool success = false;
+
+ _preview_document_width = _preview_document_height = 0;
+
+ if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&
+ (hasSuffix(path, svg) || hasSuffix(path, svgz)))
+ success = set_svg_preview();
+ else if (isValidImageFile(path))
+ success = set_image_preview();
+ else {
+ // Show no preview
+ }
+
+ if(success) render_preview();
+
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+}
+
+void FileOpenDialogImplWin32::free_preview()
+{
+ _mutex->lock();
+ if(_preview_bitmap != NULL)
+ DeleteObject(_preview_bitmap);
+ _preview_bitmap = NULL;
+
+ if(_preview_file_icon != NULL)
+ DestroyIcon(_preview_file_icon);
+ _preview_file_icon = NULL;
+
+ _preview_bitmap_image.clear();
+ _mutex->unlock();
+}
+
+bool FileOpenDialogImplWin32::set_svg_preview()
+{
+ const int PreviewSize = 512;
+
+ gchar *utf8string = g_utf16_to_utf8((const gunichar2*)_path_string,
+ _MAX_PATH, NULL, NULL, NULL);
+ SPDocument *svgDoc = sp_document_new (utf8string, true);
+ g_free(utf8string);
+
+ // Check the document loaded properly
+ if(svgDoc == NULL) return false;
+ if(svgDoc->root == NULL)
+ {
+ sp_document_unref(svgDoc);
+ return false;
+ }
+
+ // Get the size of the document
+ const double svgWidth = sp_document_width(svgDoc);
+ const double svgHeight = sp_document_height(svgDoc);
+
+ // Find the minimum scale to fit the image inside the preview area
+ const double scaleFactorX = PreviewSize / svgWidth;
+ const double scaleFactorY = PreviewSize / svgHeight;
+ const double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;
+
+ // Now get the resized values
+ const double scaledSvgWidth = scaleFactor * svgWidth;
+ const double scaledSvgHeight = scaleFactor * svgHeight;
+
+ NR::Rect area(NR::Point(0, 0), NR::Point(scaledSvgWidth, scaledSvgHeight));
+ NRRectL areaL = {0, 0, scaledSvgWidth, scaledSvgHeight};
+ NRRectL bbox = {0, 0, scaledSvgWidth, scaledSvgHeight};
+
+ // write object bbox to area
+ NR::Maybe<NR::Rect> maybeArea(area);
+ sp_document_ensure_up_to_date (svgDoc);
+ sp_item_invoke_bbox((SPItem *) svgDoc->root, &maybeArea,
+ sp_item_i2r_affine((SPItem *)(svgDoc->root)), TRUE);
+
+ NRArena *const arena = NRArena::create();
+
+ unsigned const key = sp_item_display_key_new(1);
+
+ NRArenaItem *root = sp_item_invoke_show((SPItem*)(svgDoc->root),
+ arena, key, SP_ITEM_SHOW_DISPLAY);
+
+ NRGC gc(NULL);
+ nr_matrix_set_scale(&gc.transform, scaleFactor, scaleFactor);
+
+ nr_arena_item_invoke_update (root, NULL, &gc,
+ NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
+
+ // Prepare a GDI compatible NRPixBlock
+ NRPixBlock pixBlock;
+ pixBlock.size = NR_PIXBLOCK_SIZE_BIG;
+ pixBlock.mode = NR_PIXBLOCK_MODE_R8G8B8;
+ pixBlock.empty = 1;
+ pixBlock.visible_area.x0 = pixBlock.area.x0 = 0;
+ pixBlock.visible_area.y0 = pixBlock.area.y0 = 0;
+ pixBlock.visible_area.x1 = pixBlock.area.x1 = scaledSvgWidth;
+ pixBlock.visible_area.y1 = pixBlock.area.y1 = scaledSvgHeight;
+ pixBlock.rs = 4 * ((3 * (int)scaledSvgWidth + 3) / 4);
+ pixBlock.data.px = g_try_new (unsigned char, pixBlock.rs * scaledSvgHeight);
+
+ // Fail if the pixblock failed to allocate
+ if(pixBlock.data.px == NULL)
+ {
+ sp_document_unref(svgDoc);
+ return false;
+ }
+
+ memset(pixBlock.data.px, 0xFF, pixBlock.rs * scaledSvgHeight);
+
+ memcpy(&root->bbox, &areaL, sizeof(areaL));
+
+ // Render the image
+ nr_arena_item_invoke_render(NULL, root, &bbox, &pixBlock, /*0*/NR_ARENA_ITEM_RENDER_NO_CACHE);
+
+ // Tidy up
+ sp_document_unref(svgDoc);
+ sp_item_invoke_hide((SPItem*)(svgDoc->root), key);
+ nr_arena_item_unref(root);
+ nr_object_unref((NRObject *) arena);
+
+ // Create the GDK pixbuf
+ _mutex->lock();
+
+ _preview_bitmap_image = Gdk::Pixbuf::create_from_data(
+ pixBlock.data.px, Gdk::COLORSPACE_RGB, false, 8,
+ (int)scaledSvgWidth, (int)scaledSvgHeight, pixBlock.rs,
+ sigc::ptr_fun(destroy_svg_rendering));
+
+ _preview_document_width = scaledSvgWidth;
+ _preview_document_height = scaledSvgHeight;
+ _preview_image_width = svgWidth;
+ _preview_image_height = svgHeight;
+
+ _mutex->unlock();
+
+ return true;
+}
+
+void FileOpenDialogImplWin32::destroy_svg_rendering(const guint8 *buffer)
+{
+ g_assert(buffer != NULL);
+ g_free((void*)buffer);
+}
+
+bool FileOpenDialogImplWin32::set_image_preview()
+{
+ const Glib::ustring path = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ _mutex->lock();
+ _preview_bitmap_image = Gdk::Pixbuf::create_from_file(path);
+ if(!_preview_bitmap_image) return false;
+
+ _preview_image_width = _preview_bitmap_image->get_width();
+ _preview_document_width = _preview_image_width;
+ _preview_image_height = _preview_bitmap_image->get_height();
+ _preview_document_height = _preview_image_height;
+
+ _mutex->unlock();
+
+ return true;
+}
+
+void FileOpenDialogImplWin32::render_preview()
+{
+ double x, y;
+ const double blurRadius = 8;
+ const double halfBlurRadius = blurRadius / 2;
+ const int shaddowOffsetX = 0;
+ const int shaddowOffsetY = 2;
+ const int pagePadding = 5;
+ const double shaddowAlpha = 0.75;
+
+ // Is the preview showing?
+ if(!_show_preview)
+ return;
+
+ // Do we have anything to render?
+ _mutex->lock();
+
+ if(!_preview_bitmap_image)
+ {
+ _mutex->unlock();
+ return;
+ }
+
+ // Tidy up any previous bitmap renderings
+ if(_preview_bitmap != NULL)
+ DeleteObject(_preview_bitmap);
+ _preview_bitmap = NULL;
+
+ // Calculate the size of the caption
+ int captionHeight = 0;
+
+ if(_preview_wnd != NULL)
+ {
+ RECT rcCaptionRect;
+ WCHAR szCaption[_MAX_FNAME + 32];
+ const int iLength = format_caption(szCaption,
+ sizeof(szCaption) / sizeof(WCHAR));
+
+ HDC dc = GetDC(_preview_wnd);
+ DrawTextW(dc, szCaption, iLength, &rcCaptionRect,
+ DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_CALCRECT);
+ ReleaseDC(_preview_wnd, dc);
+
+ captionHeight = rcCaptionRect.bottom - rcCaptionRect.top;
+ }
+
+ // Find the minimum scale to fit the image inside the preview area
+ const double scaleFactorX =
+ ((double)_preview_width - pagePadding * 2 - blurRadius) / _preview_document_width;
+ const double scaleFactorY =
+ ((double)_preview_height - pagePadding * 2
+ - shaddowOffsetY - halfBlurRadius - captionHeight) / _preview_document_height;
+ double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;
+ scaleFactor = (scaleFactor > 1.0) ? 1.0 : scaleFactor;
+
+ // Now get the resized values
+ const double scaledSvgWidth = scaleFactor * _preview_document_width;
+ const double scaledSvgHeight = scaleFactor * _preview_document_height;
+
+ const int svgX = pagePadding + halfBlurRadius;
+ const int svgY = pagePadding;
+
+ const int frameX = svgX - pagePadding;
+ const int frameY = svgY - pagePadding;
+ const int frameWidth = scaledSvgWidth + pagePadding * 2;
+ const int frameHeight = scaledSvgHeight + pagePadding * 2;
+
+ const int totalWidth = (int)ceil(frameWidth + blurRadius);
+ const int totalHeight = (int)ceil(frameHeight + blurRadius);
+
+ // Prepare the drawing surface
+ HDC hDC = GetDC(_preview_wnd);
+ HDC hMemDC = CreateCompatibleDC(hDC);
+ _preview_bitmap = CreateCompatibleBitmap(hDC, totalWidth, totalHeight);
+ HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, _preview_bitmap);
+ Cairo::RefPtr<Win32Surface> surface = Win32Surface::create(hMemDC);
+ Cairo::RefPtr<Context> context = Context::create(surface);
+
+ // Paint the background to match the dialog colour
+ const COLORREF background = GetSysColor(COLOR_3DFACE);
+ context->set_source_rgb(
+ GetRValue(background) / 255.0,
+ GetGValue(background) / 255.0,
+ GetBValue(background) / 255.0);
+ context->paint();
+
+ //----- Draw the drop shaddow -----//
+
+ // Left Edge
+ x = frameX + shaddowOffsetX - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> leftEdgeFade = LinearGradient::create(
+ x, 0.0, x + blurRadius, 0.0);
+ leftEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
+ leftEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);
+ context->set_source(leftEdgeFade);
+ context->rectangle (x, frameY + shaddowOffsetY + halfBlurRadius,
+ blurRadius, frameHeight - blurRadius);
+ context->fill();
+
+ // Right Edge
+ x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> rightEdgeFade = LinearGradient::create(
+ x, 0.0, x + blurRadius, 0.0);
+ rightEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ rightEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(rightEdgeFade);
+ context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,
+ frameY + shaddowOffsetY + halfBlurRadius,
+ blurRadius, frameHeight - blurRadius);
+ context->fill();
+
+ // Top Edge
+ y = frameY + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> topEdgeFade = LinearGradient::create(
+ 0.0, y, 0.0, y + blurRadius);
+ topEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);
+ topEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);
+ context->set_source(topEdgeFade);
+ context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,
+ frameWidth - blurRadius, blurRadius);
+ context->fill();
+
+ // Bottom Edge
+ y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<LinearGradient> bottomEdgeFade = LinearGradient::create(
+ 0.0, y, 0.0, y + blurRadius);
+ bottomEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ bottomEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(bottomEdgeFade);
+ context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,
+ frameWidth - blurRadius, blurRadius);
+ context->fill();
+
+ // Top Left Corner
+ x = frameX + shaddowOffsetX - halfBlurRadius;
+ y = frameY + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> topLeftCornerFade = RadialGradient::create(
+ x + blurRadius, y + blurRadius, 0, x + blurRadius, y + blurRadius, blurRadius);
+ topLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ topLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(topLeftCornerFade);
+ context->rectangle (x, y, blurRadius, blurRadius);
+ context->fill();
+
+ // Top Right Corner
+ x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
+ y = frameY + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> topRightCornerFade = RadialGradient::create(
+ x, y + blurRadius, 0, x, y + blurRadius, blurRadius);
+ topRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ topRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(topRightCornerFade);
+ context->rectangle (x, y, blurRadius, blurRadius);
+ context->fill();
+
+ // Bottom Left Corner
+ x = frameX + shaddowOffsetX - halfBlurRadius;
+ y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> bottomLeftCornerFade = RadialGradient::create(
+ x + blurRadius, y, 0, x + blurRadius, y, blurRadius);
+ bottomLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ bottomLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(bottomLeftCornerFade);
+ context->rectangle (x, y, blurRadius, blurRadius);
+ context->fill();
+
+ // Bottom Right Corner
+ x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;
+ y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;
+ Cairo::RefPtr<RadialGradient> bottomRightCornerFade = RadialGradient::create(
+ x, y, 0, x, y, blurRadius);
+ bottomRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);
+ bottomRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);
+ context->set_source(bottomRightCornerFade);
+ context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,
+ frameY + frameHeight + shaddowOffsetY - halfBlurRadius,
+ blurRadius, blurRadius);
+ context->fill();
+
+ // Draw the frame
+ context->set_line_width(1);
+ context->rectangle (frameX, frameY, frameWidth, frameHeight);
+
+ context->set_source_rgb(1.0, 1.0, 1.0);
+ context->fill_preserve();
+ context->set_source_rgb(0.25, 0.25, 0.25);
+ context->stroke_preserve();
+
+ // Draw the image
+
+ if(_preview_bitmap_image) // Is the image a pixbuf?
+ {
+ // Set the transformation
+ const Matrix matrix = {
+ scaleFactor, 0,
+ 0, scaleFactor,
+ svgX, svgY };
+ context->set_matrix (matrix);
+
+ // Render the image
+ set_source_pixbuf (context, _preview_bitmap_image, 0, 0);
+ context->paint();
+
+ // Reset the transformation
+ context->set_identity_matrix();
+ }
+
+ // Draw the inner frame
+ context->set_source_rgb(0.75, 0.75, 0.75);
+ context->rectangle (svgX, svgY, scaledSvgWidth, scaledSvgHeight);
+ context->stroke();
+
+ _mutex->unlock();
+
+ // Finish drawing
+ surface->finish();
+ SelectObject(hMemDC, hOldBitmap) ;
+ DeleteDC(hMemDC);
+
+ // Refresh the preview pane
+ InvalidateRect(_preview_wnd, NULL, FALSE);
+}
+
+int FileOpenDialogImplWin32::format_caption(wchar_t *caption, int caption_size)
+{
+ wchar_t szFileName[_MAX_FNAME];
+ _wsplitpath(_path_string, NULL, NULL, szFileName, NULL);
+
+ return snwprintf(caption, caption_size,
+ L"%s\n%d kB\n%d \xD7 %d", szFileName, _preview_file_size,
+ (int)_preview_document_width, (int)_preview_document_height);
+}
+
+/**
+ * Show this dialog modally. Return true if user hits [OK]
+ */
+bool
+FileOpenDialogImplWin32::show()
+{
+ // We can only run one worker thread at a time
+ //if(_mutex != NULL) return false;
+
+ if(!Glib::thread_supported())
+ Glib::thread_init();
+
+ _result = false;
+ _finished = false;
+ _file_selected = false;
+ _mutex = new Glib::Mutex();
+ _main_loop = g_main_loop_new(g_main_context_default(), FALSE);
+
+ if(Glib::Thread::create(sigc::mem_fun(*this, &FileOpenDialogImplWin32::GetOpenFileName_thread), true))
+ {
+ while(1)
+ {
+ g_main_context_iteration(g_main_context_default(), FALSE);
+
+ if(_mutex->trylock())
+ {
+ // Read mutexed data
+ const bool finished = _finished;
+ const bool is_file_selected = _file_selected;
+ _file_selected = false;
+ _mutex->unlock();
+
+ if(finished) break;
+ if(is_file_selected) file_selected();
+ }
+
+ Sleep(10);
+ }
+ //g_main_loop_run(_main_loop);
+ }
+
+ // Tidy up
+ delete _mutex;
+ _mutex = NULL;
+
+ return _result;
+}
+
+/**
+ * To Get Multiple filenames selected at-once.
+ */
+std::vector<Glib::ustring>FileOpenDialogImplWin32::getFilenames()
+{
+ std::vector<Glib::ustring> result;
+ result.push_back(getFilename());
+ return result;
+}
+
+
+/*#########################################################################
+### F I L E S A V E
+#########################################################################*/
+
+/**
+ * Constructor
+ */
+FileSaveDialogImplWin32::FileSaveDialogImplWin32(Gtk::Window &parent,
+ const Glib::ustring &dir,
+ FileDialogType fileTypes,
+ const char *title,
+ const Glib::ustring &/*default_key*/) :
+ FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.save_as")
+{
+ _main_loop = NULL;
+
+ createFilterMenu();
+}
+
+FileSaveDialogImplWin32::~FileSaveDialogImplWin32()
+{
+}
+
+void FileSaveDialogImplWin32::createFilterMenu()
+{
+ list<Filter> filter_list;
+
+ knownExtensions.clear();
+
+ // Compose the filter string
+ Glib::ustring all_inkscape_files_filter, all_image_files_filter;
+ Inkscape::Extension::DB::OutputList extension_list;
+ Inkscape::Extension::db.get_output_list(extension_list);
+
+ int filter_count = 0;
+ int filter_length = 0;
+
+ for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();
+ current_item != extension_list.end(); current_item++)
+ {
+ Inkscape::Extension::Output *omod = *current_item;
+ if (omod->deactivated()) continue;
+
+ filter_count++;
+
+ Filter filter;
+
+ // Extension
+ const gchar *filter_extension = omod->get_extension();
+ filter.filter = g_utf8_to_utf16(
+ filter_extension, -1, NULL, &filter.filter_length, NULL);
+ knownExtensions.insert( Glib::ustring(filter_extension).casefold() );
+
+ // Type
+ filter.name = g_utf8_to_utf16(
+ omod->get_filetypename(), -1, NULL, &filter.name_length, NULL);
+
+ filter.mod = omod;
+
+ filter_length += filter.name_length +
+ filter.filter_length + 3; // Add 3 for two \0s and a *
+
+ filter_list.push_back(filter);
+ }
+
+ int extension_index = 0;
+ _extension_map = new Inkscape::Extension::Extension*[filter_count];
+
+ _filter = new wchar_t[filter_length];
+ wchar_t *filterptr = _filter;
+
+ for(list<Filter>::iterator filter_iterator = filter_list.begin();
+ filter_iterator != filter_list.end(); filter_iterator++)
+ {
+ const Filter &filter = *filter_iterator;
+
+ memcpy(filterptr, filter.name, filter.name_length * 2);
+ filterptr += filter.name_length;
+ g_free(filter.name);
+
+ *(filterptr++) = L'\0';
+ *(filterptr++) = L'*';
+
+ memcpy(filterptr, filter.filter, filter.filter_length * 2);
+ filterptr += filter.filter_length;
+ g_free(filter.filter);
+
+ *(filterptr++) = L'\0';
+
+ // Associate this input extension with the file type name
+ _extension_map[extension_index++] = filter.mod;
+ }
+ *(filterptr++) = 0;
+
+ _filterIndex = 0;
+}
+
+void FileSaveDialogImplWin32::GetSaveFileName_thread()
+{
+ OPENFILENAMEEXW ofn;
+
+ g_assert(this != NULL);
+ //g_assert(_mutex != NULL);
+ g_assert(_main_loop != NULL);
+
+ gunichar2* current_directory_string = g_utf8_to_utf16(
+ _current_directory.data(), -1, NULL, NULL, NULL);
+
+ // Copy the selected file name, converting from UTF-8 to UTF-16
+ memset(_path_string, 0, sizeof(_path_string));
+ gunichar2* utf16_path_string = g_utf8_to_utf16(
+ myFilename.data(), -1, NULL, NULL, NULL);
+ wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);
+ g_free(utf16_path_string);
+
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = _ownerHwnd;
+ ofn.lpstrFile = _path_string;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.nFilterIndex = _filterIndex;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = (wchar_t*)current_directory_string;
+ ofn.lpstrTitle = _title;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+ ofn.lpstrFilter = _filter;
+ ofn.nFilterIndex = _filterIndex;
+
+ _result = GetSaveFileNameW(&ofn) != 0;
+
+ _filterIndex = ofn.nFilterIndex;
+ _extension = _extension_map[ofn.nFilterIndex];
+
+ // Copy the selected file name, converting from UTF-16 to UTF-8
+ myFilename = utf16_to_ustring(_path_string, _MAX_PATH);
+
+ //_mutex->lock();
+ //_finished = true;
+ //_mutex->unlock();
+
+
+ // Tidy up
+ g_free(current_directory_string);
+
+ g_main_loop_quit(_main_loop);
+}
+
+/**
+ * Show this dialog modally. Return true if user hits [OK]
+ */
+bool
+FileSaveDialogImplWin32::show()
+{
+ // We can only run one worker thread at a time
+ //if(_mutex != NULL) return false;
+
+ if(!Glib::thread_supported())
+ Glib::thread_init();
+
+ _result = false;
+ //_finished = false;
+ //_mutex = new Glib::Mutex();
+ _main_loop = g_main_loop_new(g_main_context_default(), FALSE);
+
+ if(Glib::Thread::create(sigc::mem_fun(*this, &FileSaveDialogImplWin32::GetSaveFileName_thread), true))
+ {
+ /*while(1)
+ {
+ // While the dialog runs - keep the main UI alive
+ g_main_context_iteration(g_main_context_default(), FALSE);
+
+ if(_mutex->trylock())
+ {
+ if(_finished) break;
+ _mutex->unlock();
+ }
+
+ Sleep(10);
+ }*/
+ g_main_loop_run(_main_loop);
+ }
+ //delete _mutex;
+ //_mutex = NULL;
+
+ if(_result)
+ appendExtension(myFilename, (Inkscape::Extension::Output*)_extension);
+
+ return _result;
+}
+
+void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * /*key*/ )
+{
+ // If no pointer to extension is passed in, look up based on filename extension.
+
+}
+
+}
+}
+}
+
+#endif
+
+/*
+ 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 :
diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h
new file mode 100644
index 000000000..1b69c1993
--- /dev/null
+++ b/src/ui/dialog/filedialogimpl-win32.h
@@ -0,0 +1,348 @@
+/**
+ * Implementation of the file dialog interfaces defined in filedialog.h for Win32
+ *
+ * Authors:
+ * Joel Holdsworth
+ * The Inkscape Organization
+ *
+ * Copyright (C) 2004-2007 The Inkscape Organization
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef WIN32
+
+#include "gc-core.h"
+#include <windows.h>
+
+namespace Inkscape
+{
+namespace UI
+{
+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 of a MS Windows
+/// file dialog.
+class FileDialogBaseWin32
+{
+protected:
+ /// Abstract Constructor
+ /// @param parent The parent window for the dialog
+ /// @param dir The directory to begin browing from
+ /// @param title The title caption for the dialog in UTF-8
+ /// @param type The dialog type
+ /// @param preferenceBase The preferences key
+ FileDialogBaseWin32(Gtk::Window &parent, const Glib::ustring &dir,
+ const char *title, FileDialogType type,
+ gchar const *preferenceBase);
+
+ /// Destructor
+ ~FileDialogBaseWin32();
+
+public:
+
+ /// Gets the currently selected extension. Valid after an [OK]
+ /// @return Returns a pointer to the selected extension, or NULL
+ /// if the selected filter requires an automatic type detection
+ Inkscape::Extension::Extension* getSelectionType();
+
+ /// Get the path of the current directory
+ Glib::ustring getCurrentDirectory();
+
+protected:
+ /// The dialog type
+ FileDialogType dialogType;
+
+ /// This mutex is used to ensure that the worker thread
+ /// that calls GetOpenFileName cannot collide with the
+ /// main Inkscape thread
+ Glib::Mutex *_mutex;
+
+ /// This flag is set true when the GetOpenFileName call
+ /// has returned
+ bool _finished;
+
+ /// A pointer to the GTK main-loop context object. This
+ /// is used to keep the rest of the inkscape UI running
+ /// while the file dialog is displayed
+ GMainLoop *_main_loop;
+
+ /// The result of the call to GetOpenFileName. If true
+ /// the user clicked OK, if false the user clicked cancel
+ bool _result;
+
+ /// The parent window
+ Gtk::Window &parent;
+
+ /// The windows handle of the parent window
+ HWND _ownerHwnd;
+
+ /// The path of the directory that is currently being
+ /// browsed
+ Glib::ustring _current_directory;
+
+ /// The title of the dialog in UTF-16
+ wchar_t *_title;
+
+ /// The path of the currently selected file in UTF-16
+ wchar_t _path_string[_MAX_PATH];
+
+ /// The filter string for GetOpenFileName in UTF-16
+ wchar_t *_filter;
+
+ /// The index of the currently selected filter
+ int _filterIndex;
+
+ /// An array of the extensions associated with the
+ /// file types of each filter. So the Nth entry of
+ /// this array corresponds to the extension of the Nth
+ /// filter in the list. NULL if no specific extension is
+ /// specified/
+ Inkscape::Extension::Extension **_extension_map;
+
+ /// The currently selected extension. Valid after an [OK]
+ Inkscape::Extension::Extension *_extension;
+};
+
+
+/*#########################################################################
+### F I L E O P E N
+#########################################################################*/
+
+/// An Inkscape compatible wrapper around MS Windows GetOpenFileName API
+class FileOpenDialogImplWin32 : public FileOpenDialog, public FileDialogBaseWin32
+{
+public:
+ /// Constructor
+ /// @param parent The parent window for the dialog
+ /// @param dir The directory to begin browing from
+ /// @param title The title caption for the dialog in UTF-8
+ /// @param type The dialog type
+ FileOpenDialogImplWin32(Gtk::Window &parent,
+ const Glib::ustring &dir,
+ FileDialogType fileTypes,
+ const char *title);
+
+ /// Destructor
+ virtual ~FileOpenDialogImplWin32();
+
+ /// Shows the file dialog, and blocks until a file
+ /// has been selected.
+ /// @return Returns true if the the user selected a
+ /// file, or false if the user pressed cancel.
+ bool show();
+
+ /// Gets a list of the selected file names
+ /// @return Returns an STL vector filled with the
+ /// GTK names of the selected files
+ std::vector<Glib::ustring> getFilenames();
+
+ /// Get the path of the current directory
+ virtual Glib::ustring getCurrentDirectory()
+ { return FileDialogBaseWin32::getCurrentDirectory(); }
+
+ /// Gets the currently selected extension. Valid after an [OK]
+ /// @return Returns a pointer to the selected extension, or NULL
+ /// if the selected filter requires an automatic type detection
+ virtual Inkscape::Extension::Extension* getSelectionType()
+ { return FileDialogBaseWin32::getSelectionType(); }
+
+private:
+
+ /// Create a filter menu for this type of dialog
+ void createFilterMenu();
+
+ /// The handle of the preview pane window
+ HWND _preview_wnd;
+
+ /// The handle of the file dialog window
+ HWND _file_dialog_wnd;
+
+ /// A pointer to the standard window proc of the
+ /// unhooked file dialog
+ WNDPROC _base_window_proc;
+
+ /// The handle of the bitmap of the "show preview"
+ /// toggle button
+ HBITMAP _show_preview_button_bitmap;
+
+ /// The handle of the toolbar's window
+ HWND _toolbar_wnd;
+
+ /// This flag is set true when the preview should be
+ /// shown, or false when it should be hidden
+ static bool _show_preview;
+
+
+ /// The current width of the preview pane in pixels
+ int _preview_width;
+
+ /// The current height of the preview pane in pixels
+ int _preview_height;
+
+ /// The handle of the windows to display within the
+ /// preview pane, or NULL if no image should be displayed
+ HBITMAP _preview_bitmap;
+
+ /// The windows shell icon for the selected file
+ HICON _preview_file_icon;
+
+ /// The size of the preview file in kilobytes
+ unsigned long _preview_file_size;
+
+
+ /// The width of the document to be shown in the preview panel
+ double _preview_document_width;
+
+ /// The width of the document to be shown in the preview panel
+ double _preview_document_height;
+
+ /// The width of the rendered preview image in pixels
+ int _preview_image_width;
+
+ /// The height of the rendered preview image in pixels
+ int _preview_image_height;
+
+ /// A GDK Pixbuf of the rendered preview to be displayed
+ Glib::RefPtr<Gdk::Pixbuf> _preview_bitmap_image;
+
+ /// This flag is set true if a file has been selected
+ bool _file_selected;
+
+
+ /// The controller function for the thread which calls
+ /// GetOpenFileName
+ void GetOpenFileName_thread();
+
+ /// Registers the Windows Class of the preview panel window
+ static void register_preview_wnd_class();
+
+ /// A message proc which is called by the standard dialog
+ /// proc
+ static UINT_PTR CALLBACK GetOpenFileName_hookproc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);
+
+ /// A message proc which wraps the standard dialog proc,
+ /// but intercepts some calls
+ static LRESULT CALLBACK file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ /// The message proc for the preview panel window
+ static LRESULT CALLBACK preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ /// Lays out the controls in the file dialog given it's
+ /// current size
+ /// GetOpenFileName thread only.
+ void layout_dialog();
+
+ /// Enables or disables the file preview.
+ /// GetOpenFileName thread only.
+ void enable_preview(bool enable);
+
+ /// This function is called in the App thread when a file had
+ /// been selected
+ void file_selected();
+
+ /// Loads and renders the unshrunk preview image.
+ /// Main app thread only.
+ void load_preview();
+
+ /// Frees all the allocated objects associated with the file
+ /// currently being previewed
+ /// Main app thread only.
+ void free_preview();
+
+ /// Loads preview for an SVG or SVGZ file.
+ /// Main app thread only.
+ /// @return Returns true if the SVG loaded successfully
+ bool set_svg_preview();
+
+ /// A callback to allow this class to dispose of the
+ /// memory block of the rendered SVG bitmap
+ /// @buffer buffer The buffer to free
+ static void destroy_svg_rendering(const guint8 *buffer);
+
+ /// Loads the preview for a raster image
+ /// Main app thread only.
+ /// @return Returns true if the image loaded successfully
+ bool set_image_preview();
+
+ /// Renders the unshrunk preview image to a windows HTBITMAP
+ /// which can be painted in the preview pain.
+ /// Main app thread only.
+ void render_preview();
+
+ /// Formats the caption in UTF-16 for the preview image
+ /// @param caption The buffer to format the caption string into
+ /// @param caption_size The number of wchar_ts in the caption buffer
+ /// @return Returns the number of characters in caption string
+ int format_caption(wchar_t *caption, int caption_size);
+};
+
+
+/*#########################################################################
+### F I L E S A V E
+#########################################################################*/
+
+/// An Inkscape compatible wrapper around MS Windows GetSaveFileName API
+class FileSaveDialogImplWin32 : public FileSaveDialog, public FileDialogBaseWin32
+{
+
+public:
+ FileSaveDialogImplWin32(Gtk::Window &parent,
+ const Glib::ustring &dir,
+ FileDialogType fileTypes,
+ const char *title,
+ const Glib::ustring &default_key);
+
+ /// Destructor
+ virtual ~FileSaveDialogImplWin32();
+
+ /// Shows the file dialog, and blocks until a file
+ /// has been selected.
+ /// @return Returns true if the the user selected a
+ /// file, or false if the user pressed cancel.
+ bool show();
+
+ /// Get the path of the current directory
+ virtual Glib::ustring getCurrentDirectory()
+ { return FileDialogBaseWin32::getCurrentDirectory(); }
+
+ /// Gets the currently selected extension. Valid after an [OK]
+ /// @return Returns a pointer to the selected extension, or NULL
+ /// if the selected filter requires an automatic type detection
+ virtual Inkscape::Extension::Extension* getSelectionType()
+ { return FileDialogBaseWin32::getSelectionType(); }
+
+ virtual void setSelectionType( Inkscape::Extension::Extension *key );
+
+private:
+
+ /**
+ * Create a filter menu for this type of dialog
+ */
+ void createFilterMenu();
+
+ void GetSaveFileName_thread();
+};
+
+
+}
+}
+}
+
+#endif
+
+/*
+ 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 :