Code

Merged in Native File Dialogs for Windows Branch
authorjoelholdsworth <joelholdsworth@users.sourceforge.net>
Sat, 23 Feb 2008 12:56:59 +0000 (12:56 +0000)
committerjoelholdsworth <joelholdsworth@users.sourceforge.net>
Sat, 23 Feb 2008 12:56:59 +0000 (12:56 +0000)
src/dialogs/filedialog-win32.cpp [deleted file]
src/file.cpp
src/inkscape.rc
src/inkview.rc
src/ui/dialog/filedialog.cpp
src/ui/dialog/filedialog.h
src/ui/dialog/filedialogimpl-gtkmm.cpp
src/ui/dialog/filedialogimpl-gtkmm.h
src/ui/dialog/filedialogimpl-win32.cpp [new file with mode: 0644]
src/ui/dialog/filedialogimpl-win32.h [new file with mode: 0644]

diff --git a/src/dialogs/filedialog-win32.cpp b/src/dialogs/filedialog-win32.cpp
deleted file mode 100644 (file)
index ca9ce5f..0000000
+++ /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
-
-
-
-
index c3e7e7583998a89df4d358d6ed57ca219306c5d8..b41d61426f831c51ba496679f2f8a87b52320904 100644 (file)
@@ -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;
index 3e5b61548451bdfc51861a844034775ecf8bedfc..d48b68c431aa34da9ce9f13a192657832f13334e 100644 (file)
@@ -25,3 +25,6 @@ BEGIN
         VALUE "Translation", 1033, 437
     END
 END
+
+1000           BITMAP  "./show-preview.bmp"
+
index 245bdc68b740afbf43680c071af2045cf9b662fb..9f643eb4c910b3efcac151a1c851a96cdd841734 100644 (file)
@@ -25,3 +25,5 @@ BEGIN
         VALUE "Translation", 1033, 437\r
     END\r
 END\r
+\r
+1000           BITMAP  "./show-preview.bmp"\r
index c3ca49c992de5178430774de6971eb3a92665989..103b624858750712004b3a8ec20b8e9f0e28f80c 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "filedialog.h"
 #include "filedialogimpl-gtkmm.h"
+#include "filedialogimpl-win32.h"
 
 #include "gc-core.h"
 #include <dialogs/dialog-events.h>
@@ -25,6 +26,49 @@ namespace UI
 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);
index 75c6f008073c4517a4dd1c17fd88c6c6f4eb129c..a3d5c0ea9133a59f45017878abd459373d7b3fdc 100644 (file)
 
 #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,11 +51,17 @@ 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
@@ -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);
 
 
index a1773d39a317c36775d91815e5fe0141a5e62cf5..1405e11aa0700c4f62f116c6ab210ee0acbabff4 100644 (file)
@@ -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)
index e5058d0c207f6f2def2584381753bd7ff2b26c94..5bac9aa5b088ff5dc3342618b1b1edf10a04a370 100644 (file)
@@ -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 (file)
index 0000000..6330186
--- /dev/null
@@ -0,0 +1,1461 @@
+/**\r
+ * Implementation of the file dialog interfaces defined in filedialog.h for Win32\r
+ *\r
+ * Authors:\r
+ *   Joel Holdsworth\r
+ *   The Inkscape Organization\r
+ *\r
+ * Copyright (C) 2004-2007 The Inkscape Organization\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
\r
+#ifdef HAVE_CONFIG_H\r
+# include <config.h>\r
+#endif\r
+\r
+#ifdef WIN32\r
\r
+//General includes\r
+#include <list>\r
+#include <unistd.h>\r
+#include <sys/stat.h>\r
+#include <errno.h>\r
+#include <set>\r
+#include <gdk/gdkwin32.h>\r
+#include <glib/gstdio.h>\r
+#include <glibmm/i18n.h>\r
+#include <gtkmm/window.h>\r
+\r
+//Inkscape includes\r
+#include "inkscape.h"\r
+#include "prefs-utils.h"\r
+#include <dialogs/dialog-events.h>\r
+#include <extension/input.h>\r
+#include <extension/output.h>\r
+#include <extension/db.h>\r
+\r
+#include <libnr/nr-pixops.h>\r
+#include <libnr/nr-translate-scale-ops.h>\r
+#include <display/nr-arena-item.h>\r
+#include <display/nr-arena.h>\r
+#include "sp-item.h"\r
+#include "canvas-arena.h"\r
+\r
+#include "filedialog.h"\r
+#include "filedialogimpl-win32.h"\r
+\r
+#include <zlib.h>\r
+#include <cairomm/win32_surface.h>\r
+#include <cairomm/context.h>\r
+\r
+using namespace std;\r
+using namespace Glib;\r
+using namespace Cairo;\r
+using namespace Gdk::Cairo;\r
+\r
+namespace Inkscape\r
+{\r
+namespace UI\r
+{\r
+namespace Dialog\r
+{\r
+\r
+const int PreviewWidening = 150;\r
+const char PreviewWindowClassName[] = "PreviewWnd";\r
+const unsigned long MaxPreviewFileSize = 1344; // kB\r
+\r
+#define IDC_SHOW_PREVIEW    1000\r
+\r
+// Windows 2000 version of OPENFILENAMEW\r
+struct OPENFILENAMEEXW : public OPENFILENAMEW { \r
+  void *        pvReserved;\r
+  DWORD         dwReserved;\r
+  DWORD         FlagsEx;\r
+};\r
+\r
+struct Filter\r
+{\r
+    gunichar2* name;\r
+    glong name_length;\r
+    gunichar2* filter;\r
+    glong filter_length;\r
+    Inkscape::Extension::Extension* mod;\r
+};\r
+\r
+ustring utf16_to_ustring(const wchar_t *utf16string, int utf16length = -1)\r
+{\r
+    gchar *utf8string = g_utf16_to_utf8((const gunichar2*)utf16string,\r
+        utf16length, NULL, NULL, NULL);\r
+    ustring result(utf8string);\r
+    g_free(utf8string);\r
+    \r
+    return result;\r
+}\r
+\r
+/*#########################################################################\r
+### F I L E     D I A L O G    B A S E    C L A S S\r
+#########################################################################*/\r
+\r
+FileDialogBaseWin32::FileDialogBaseWin32(Gtk::Window &parent, \r
+        const Glib::ustring &dir, const gchar *title,\r
+        FileDialogType type, gchar const* /*preferenceBase*/) :\r
+        dialogType(type),\r
+        parent(parent),\r
+        _current_directory(dir)\r
+{\r
+    //_mutex = NULL;\r
+    _main_loop = NULL;\r
+    \r
+    _title = (wchar_t*)g_utf8_to_utf16(title, -1, NULL, NULL, NULL);\r
+    \r
+    Glib::RefPtr<const Gdk::Window> parentWindow = parent.get_window();\r
+    g_assert(parentWindow->gobj() != NULL);\r
+    _ownerHwnd = (HWND)gdk_win32_drawable_get_handle((GdkDrawable*)parentWindow->gobj());\r
+}\r
+\r
+FileDialogBaseWin32::~FileDialogBaseWin32()\r
+{\r
+    g_free(_title);\r
+}\r
+\r
+Inkscape::Extension::Extension *FileDialogBaseWin32::getSelectionType()\r
+{\r
+    return _extension;\r
+}\r
+\r
+Glib::ustring FileDialogBaseWin32::getCurrentDirectory()\r
+{\r
+    return _current_directory;\r
+}\r
+\r
+/*#########################################################################\r
+### F I L E    O P E N\r
+#########################################################################*/\r
+\r
+bool FileOpenDialogImplWin32::_show_preview = true;\r
+\r
+/**\r
+ * Constructor.  Not called directly.  Use the factory.\r
+ */\r
+FileOpenDialogImplWin32::FileOpenDialogImplWin32(Gtk::Window &parent,  \r
+                                       const Glib::ustring &dir,\r
+                                       FileDialogType fileTypes,\r
+                                       const gchar *title) :\r
+    FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.open")\r
+{\r
+    // Initalize to Autodetect\r
+    _extension = NULL;\r
+\r
+    // Set our dialog type (open, import, etc...)\r
+    dialogType = fileTypes;\r
+    \r
+    _show_preview_button_bitmap = NULL;\r
+    _preview_wnd = NULL;\r
+    _file_dialog_wnd = NULL;\r
+    _base_window_proc = NULL;\r
+    \r
+    _preview_file_size = 0;\r
+    _preview_bitmap = NULL;\r
+    _preview_file_icon = NULL;\r
+    _preview_document_width = 0;\r
+    _preview_document_height = 0;\r
+    _preview_image_width = 0;\r
+    _preview_image_height = 0;\r
+    \r
+    createFilterMenu();\r
+}\r
+\r
+\r
+/**\r
+ * Destructor\r
+ */\r
+FileOpenDialogImplWin32::~FileOpenDialogImplWin32()\r
+{\r
+    if(_filter != NULL)\r
+        delete[] _filter;\r
+    if(_extension_map != NULL)\r
+        delete[] _extension_map;\r
+}\r
+\r
+void FileOpenDialogImplWin32::createFilterMenu()\r
+{\r
+    list<Filter> filter_list;\r
+\r
+    // Compose the filter string\r
+    Inkscape::Extension::DB::InputList extension_list;\r
+    Inkscape::Extension::db.get_input_list(extension_list);\r
+    \r
+    ustring all_inkscape_files_filter, all_image_files_filter;\r
+    Filter all_files, all_inkscape_files, all_image_files;\r
+\r
+    const gchar *all_files_filter_name = _("All Files");\r
+    const gchar *all_inkscape_files_filter_name = ("All Inkscape Files");\r
+    const gchar *all_image_files_filter_name = _("All Image Files");\r
+        \r
+    // Calculate the amount of memory required\r
+    int filter_count = 3;       // 3 - one for All Files, All Images and All Inkscape Files\r
+    int filter_length = 1;\r
+        \r
+    for (Inkscape::Extension::DB::InputList::iterator current_item = extension_list.begin();\r
+         current_item != extension_list.end(); current_item++)\r
+    {\r
+        Filter filter;\r
+    \r
+        Inkscape::Extension::Input *imod = *current_item;\r
+        if (imod->deactivated()) continue;\r
+                \r
+        // Type\r
+        filter.name = g_utf8_to_utf16(imod->get_filetypename(),\r
+            -1, NULL, &filter.name_length, NULL);\r
+        \r
+        // Extension\r
+        const gchar *file_extension_name = imod->get_extension();\r
+        filter.filter = g_utf8_to_utf16(file_extension_name,\r
+            -1, NULL, &filter.filter_length, NULL);\r
+        \r
+        filter.mod = imod;\r
+        filter_list.push_back(filter);\r
+        \r
+        filter_length += filter.name_length +\r
+            filter.filter_length + 3;   // Add 3 for two \0s and a *\r
+            \r
+        // Add to the "All Inkscape Files" Entry\r
+        if(all_inkscape_files_filter.length() > 0)\r
+            all_inkscape_files_filter += ";*";\r
+        all_inkscape_files_filter += file_extension_name;\r
+        if( strncmp("image", imod->get_mimetype(), 5) == 0)\r
+        {\r
+            // Add to the "All Image Files" Entry\r
+            if(all_image_files_filter.length() > 0)\r
+                all_image_files_filter += ";*";\r
+            all_image_files_filter += file_extension_name;\r
+        }\r
+        \r
+        filter_count++;\r
+    }\r
+    \r
+    int extension_index = 0;\r
+    _extension_map = new Inkscape::Extension::Extension*[filter_count];\r
+    \r
+    // Filter Image Files\r
+    all_image_files.name = g_utf8_to_utf16(all_image_files_filter_name,\r
+        -1, NULL, &all_image_files.name_length, NULL);\r
+    all_image_files.filter = g_utf8_to_utf16(all_image_files_filter.data(),\r
+            -1, NULL, &all_image_files.filter_length, NULL);\r
+    filter_list.push_front(all_image_files);\r
+    _extension_map[extension_index++] = NULL;\r
+    \r
+    // Filter Inkscape Files\r
+    all_inkscape_files.name = g_utf8_to_utf16(all_inkscape_files_filter_name,\r
+        -1, NULL, &all_inkscape_files.name_length, NULL);\r
+    all_inkscape_files.filter = g_utf8_to_utf16(all_inkscape_files_filter.data(),\r
+            -1, NULL, &all_inkscape_files.filter_length, NULL);\r
+    filter_list.push_front(all_inkscape_files);\r
+    _extension_map[extension_index++] = NULL;\r
+    \r
+    // Filter All Files\r
+    all_files.name = g_utf8_to_utf16(all_files_filter_name,\r
+        -1, NULL, &all_files.name_length, NULL);\r
+    all_files.filter = NULL;\r
+    all_files.filter_length = 0;\r
+    filter_list.push_front(all_files);\r
+    _extension_map[extension_index++] = NULL;\r
+    \r
+    filter_length += all_files.name_length + 3 +\r
+                    all_inkscape_files.filter_length + \r
+                    all_inkscape_files.name_length + 3 +\r
+                    all_image_files.filter_length +\r
+                    all_image_files.name_length + 3 + 1;\r
+     // Add 3 for 2*2 \0s and a *, and 1 for a trailing \0\r
+      \r
+    \r
+    _filter = new wchar_t[filter_length];\r
+    wchar_t *filterptr = _filter;\r
+    \r
+    for(list<Filter>::iterator filter_iterator = filter_list.begin();\r
+        filter_iterator != filter_list.end(); filter_iterator++)\r
+    {\r
+        const Filter &filter = *filter_iterator;\r
+        \r
+        memcpy(filterptr, filter.name, filter.name_length * 2);\r
+        filterptr += filter.name_length;\r
+        g_free(filter.name);\r
+        \r
+        *(filterptr++) = L'\0';\r
+        *(filterptr++) = L'*';\r
+        \r
+        if(filter.filter != NULL)\r
+        {\r
+            memcpy(filterptr, filter.filter, filter.filter_length * 2);\r
+            filterptr += filter.filter_length;  \r
+            g_free(filter.filter);\r
+        }\r
+    \r
+        *(filterptr++) = L'\0';\r
+        \r
+        // Associate this input extension with the file type name\r
+        _extension_map[extension_index++] = filter.mod;\r
+    }\r
+    *(filterptr++) = L'\0';\r
+    \r
+    _filterIndex = 2;\r
+}\r
+\r
+void FileOpenDialogImplWin32::GetOpenFileName_thread()\r
+{\r
+    OPENFILENAMEEXW ofn;\r
+\r
+    g_assert(this != NULL);\r
+    //g_assert(_mutex != NULL);\r
+    g_assert(_main_loop != NULL);    \r
+        \r
+    WCHAR* current_directory_string = (WCHAR*)g_utf8_to_utf16(\r
+        _current_directory.data(), -1, NULL, NULL, NULL);\r
+        \r
+    memset(&ofn, 0, sizeof(ofn));\r
+    \r
+    // Copy the selected file name, converting from UTF-8 to UTF-16\r
+    memset(_path_string, 0, sizeof(_path_string));\r
+    gunichar2* utf16_path_string = g_utf8_to_utf16(\r
+        myFilename.data(), -1, NULL, NULL, NULL);\r
+    wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);\r
+    g_free(utf16_path_string);\r
+    \r
+    ofn.lStructSize = sizeof(ofn);\r
+    ofn.hwndOwner = _ownerHwnd;\r
+    ofn.lpstrFile = _path_string;\r
+    ofn.nMaxFile = _MAX_PATH;\r
+    ofn.lpstrFileTitle = NULL;\r
+    ofn.nMaxFileTitle = 0;\r
+    ofn.lpstrInitialDir = current_directory_string;\r
+    ofn.lpstrTitle = _title;\r
+    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_HIDEREADONLY | OFN_ENABLESIZING;\r
+    ofn.lpstrFilter = _filter;\r
+    ofn.nFilterIndex = _filterIndex;\r
+    ofn.lpfnHook = GetOpenFileName_hookproc;\r
+    ofn.lCustData = (LPARAM)this;\r
+    \r
+    _result = GetOpenFileNameW(&ofn) != 0;\r
+    \r
+    _filterIndex = ofn.nFilterIndex;\r
+    _extension = _extension_map[ofn.nFilterIndex];\r
+\r
+    myFilename = utf16_to_ustring(_path_string, _MAX_PATH);\r
+    \r
+    // Copy the selected file name, converting from UTF-16 to UTF-8\r
+    myFilename = utf16_to_ustring(_path_string, _MAX_PATH);\r
+    \r
+    // Tidy up\r
+    g_free(current_directory_string);\r
+    \r
+    _mutex->lock();\r
+    _finished = true;\r
+    _mutex->unlock();\r
+    //g_main_loop_quit(_main_loop);\r
+    \r
+\r
+}\r
+\r
+void FileOpenDialogImplWin32::register_preview_wnd_class()\r
+{\r
+    HINSTANCE hInstance = GetModuleHandle(NULL);\r
+    const WNDCLASSA PreviewWndClass = \r
+    {\r
+        CS_HREDRAW | CS_VREDRAW,\r
+        preview_wnd_proc,\r
+        0,\r
+        0,\r
+        hInstance,\r
+        NULL,\r
+        LoadCursor(hInstance, IDC_ARROW),\r
+        (HBRUSH)(COLOR_BTNFACE + 1),\r
+        NULL,\r
+        PreviewWindowClassName\r
+    };\r
+\r
+    RegisterClassA(&PreviewWndClass);\r
+}\r
+\r
+UINT_PTR CALLBACK FileOpenDialogImplWin32::GetOpenFileName_hookproc(\r
+    HWND hdlg, UINT uiMsg, WPARAM, LPARAM lParam)\r
+{\r
+    FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)\r
+        GetWindowLongPtr(hdlg, GWLP_USERDATA);\r
+        \r
+    switch(uiMsg)\r
+    {\r
+    case WM_INITDIALOG:\r
+        {\r
+            HWND hParentWnd = GetParent(hdlg);\r
+            HINSTANCE hInstance = GetModuleHandle(NULL);\r
+            \r
+            // Make the window a bit wider\r
+            RECT rcRect;\r
+            GetWindowRect(hParentWnd, &rcRect);\r
+            MoveWindow(hParentWnd, rcRect.left, rcRect.top,\r
+                rcRect.right - rcRect.left + PreviewWidening,\r
+                rcRect.bottom - rcRect.top,\r
+                FALSE);\r
+            \r
+            // Set the pointer to the object\r
+            OPENFILENAMEW *ofn = (OPENFILENAMEW*)lParam;\r
+            SetWindowLongPtr(hdlg, GWLP_USERDATA, ofn->lCustData);\r
+            SetWindowLongPtr(hParentWnd, GWLP_USERDATA, ofn->lCustData);\r
+            pImpl = (FileOpenDialogImplWin32*)ofn->lCustData;\r
+            \r
+            // Subclass the parent\r
+            pImpl->_base_window_proc = (WNDPROC)GetWindowLongPtr(hParentWnd, GWL_WNDPROC);\r
+            SetWindowLongPtr(hParentWnd, GWL_WNDPROC, (LONG_PTR)file_dialog_subclass_proc);\r
+        \r
+            // Add a button to the toolbar\r
+            pImpl->_toolbar_wnd = FindWindowEx(hParentWnd, NULL, "ToolbarWindow32", NULL);\r
+\r
+            pImpl->_show_preview_button_bitmap = LoadBitmap(\r
+                hInstance, MAKEINTRESOURCE(IDC_SHOW_PREVIEW));\r
+            TBADDBITMAP tbAddBitmap = {NULL, (UINT)pImpl->_show_preview_button_bitmap};            \r
+            const int iBitmapIndex = SendMessage(pImpl->_toolbar_wnd,\r
+                TB_ADDBITMAP, 1, (LPARAM)&tbAddBitmap);\r
+    \r
+            TBBUTTON tbButton;\r
+            memset(&tbButton, 0, sizeof(TBBUTTON));\r
+            tbButton.iBitmap = iBitmapIndex;\r
+            tbButton.idCommand = IDC_SHOW_PREVIEW;\r
+            tbButton.fsState = (pImpl->_show_preview ? TBSTATE_CHECKED : 0)\r
+                | TBSTATE_ENABLED;\r
+            tbButton.fsStyle = TBSTYLE_CHECK;\r
+            tbButton.iString = (INT_PTR)_("Show Preview");\r
+            SendMessage(pImpl->_toolbar_wnd, TB_ADDBUTTONS, 1, (LPARAM)&tbButton); \r
+            \r
+            // Create preview pane\r
+            register_preview_wnd_class();\r
+\r
+            pImpl->_mutex->lock();\r
+            \r
+                pImpl->_file_dialog_wnd = hParentWnd;\r
+                \r
+                pImpl->_preview_wnd = \r
+                    CreateWindow(PreviewWindowClassName, "",\r
+                        WS_CHILD | WS_VISIBLE,\r
+                        0, 0, 100, 100, hParentWnd, NULL, hInstance, NULL);\r
+                SetWindowLongPtr(pImpl->_preview_wnd, GWLP_USERDATA, ofn->lCustData);\r
+                    \r
+            pImpl->_mutex->unlock();\r
+                \r
+            pImpl->layout_dialog();\r
+        }\r
+        break;\r
+    \r
+    case WM_NOTIFY:\r
+        {\r
+        \r
+        OFNOTIFY *pOFNotify = reinterpret_cast<OFNOTIFY*>(lParam);\r
+        switch(pOFNotify->hdr.code)\r
+        {\r
+        case CDN_SELCHANGE:\r
+            {\r
+                if(pImpl != NULL)\r
+                {\r
+                    // Get the file name\r
+                    pImpl->_mutex->lock();\r
+                    \r
+                    SendMessage(pOFNotify->hdr.hwndFrom, CDM_GETFILEPATH,\r
+                        sizeof(pImpl->_path_string) / sizeof(wchar_t),\r
+                        (LPARAM)pImpl->_path_string);\r
+                    \r
+                    pImpl->_file_selected = true;\r
+                    \r
+                    pImpl->_mutex->unlock();\r
+                        \r
+                    //pImpl->file_selected();\r
+                }\r
+            }\r
+            break;\r
+        }\r
+        }\r
+        break;\r
+        \r
+    case WM_CLOSE:\r
+        pImpl->_mutex->lock();\r
+        pImpl->_preview_file_size = 0;\r
+    \r
+        pImpl->_file_dialog_wnd = NULL;\r
+        DestroyWindow(pImpl->_preview_wnd);\r
+        pImpl->_preview_wnd = NULL;\r
+        DeleteObject(pImpl->_show_preview_button_bitmap);\r
+        pImpl->_show_preview_button_bitmap = NULL;\r
+        pImpl->_mutex->unlock();\r
+\r
+        break;\r
+    }\r
+        \r
+    // Use default dialog behaviour\r
+    return 0;\r
+}\r
+\r
+LRESULT CALLBACK FileOpenDialogImplWin32::file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+    FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)\r
+        GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
+\r
+    LRESULT lResult = CallWindowProc(pImpl->_base_window_proc, hwnd, uMsg, wParam, lParam);\r
+        \r
+    switch(uMsg)\r
+    {\r
+    case WM_SHOWWINDOW:\r
+        if(wParam != 0)\r
+            pImpl->layout_dialog();\r
+        break;\r
+        \r
+    case WM_SIZE:\r
+        pImpl->layout_dialog();\r
+        break;\r
+        \r
+    case WM_COMMAND:\r
+        if(wParam == IDC_SHOW_PREVIEW)\r
+        {\r
+            const bool enable = SendMessage(pImpl->_toolbar_wnd,\r
+                TB_ISBUTTONCHECKED, IDC_SHOW_PREVIEW, 0) != 0;\r
+            pImpl->enable_preview(enable);\r
+        }\r
+        break;\r
+    }\r
+    \r
+    return lResult;\r
+}\r
+\r
+LRESULT CALLBACK FileOpenDialogImplWin32::preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+    const int CaptionPadding = 4;\r
+    const int IconSize = 32;\r
+    \r
+    FileOpenDialogImplWin32 *pImpl = (FileOpenDialogImplWin32*)\r
+        GetWindowLongPtr(hwnd, GWLP_USERDATA);\r
+\r
+    LRESULT lResult = 0;\r
+    \r
+    switch(uMsg)\r
+    {\r
+    case WM_ERASEBKGND:\r
+        // Do nothing to erase the background\r
+        //  - otherwise there'll be flicker\r
+        lResult = 1;\r
+        break;\r
+    \r
+    case WM_PAINT:\r
+        {\r
+            // Get the client rect\r
+            RECT rcClient;\r
+            GetClientRect(hwnd, &rcClient);\r
+            \r
+            // Prepare to paint\r
+            PAINTSTRUCT paint_struct;\r
+            HDC dc = BeginPaint(hwnd, &paint_struct);\r
+            \r
+            HFONT hCaptionFont = (HFONT)SendMessage(GetParent(hwnd),\r
+                    WM_GETFONT, 0, 0);\r
+            HFONT hOldFont = (HFONT)SelectObject(dc, hCaptionFont);\r
+            SetBkMode(dc, TRANSPARENT);\r
+            \r
+            pImpl->_mutex->lock();\r
+            \r
+            //FillRect(dc, &client_rect, (HBRUSH)(COLOR_HOTLIGHT+1));\r
+            if(pImpl->_path_string[0] == 0)\r
+            {\r
+                FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));\r
+                DrawText(dc, _("No file selected"), -1, &rcClient,\r
+                    DT_CENTER | DT_VCENTER | DT_NOPREFIX);\r
+            }\r
+            else if(pImpl->_preview_bitmap != NULL)\r
+            {\r
+                BITMAP bitmap;\r
+                GetObject(pImpl->_preview_bitmap, sizeof(bitmap), &bitmap);\r
+                const int destX = (rcClient.right - bitmap.bmWidth) / 2;\r
+                            \r
+                // Render the image\r
+                HDC hSrcDC = CreateCompatibleDC(dc);\r
+                HBITMAP hOldBitmap = (HBITMAP)SelectObject(hSrcDC, pImpl->_preview_bitmap);\r
+            \r
+                BitBlt(dc, destX, 0, bitmap.bmWidth, bitmap.bmHeight,\r
+                    hSrcDC, 0, 0, SRCCOPY);\r
+                    \r
+                SelectObject(hSrcDC, hOldBitmap);\r
+                DeleteDC(hSrcDC);\r
+                \r
+                // Fill in the background area\r
+                HRGN hEraseRgn = CreateRectRgn(rcClient.left, rcClient.top,\r
+                    rcClient.right, rcClient.bottom);\r
+                HRGN hImageRgn = CreateRectRgn(destX, 0,\r
+                    destX + bitmap.bmWidth, bitmap.bmHeight);\r
+                CombineRgn(hEraseRgn, hEraseRgn, hImageRgn, RGN_DIFF);\r
+                \r
+                FillRgn(dc, hEraseRgn, GetSysColorBrush(COLOR_3DFACE));\r
+                                \r
+                DeleteObject(hImageRgn);\r
+                DeleteObject(hEraseRgn);\r
+                \r
+                // Draw the caption on\r
+                RECT rcCaptionRect = {rcClient.left,\r
+                    rcClient.top + bitmap.bmHeight + CaptionPadding,\r
+                    rcClient.right, rcClient.bottom};\r
+                    \r
+                WCHAR szCaption[_MAX_FNAME + 32];                \r
+                const int iLength = pImpl->format_caption(\r
+                    szCaption, sizeof(szCaption) / sizeof(WCHAR));\r
+        \r
+                DrawTextW(dc, szCaption, iLength, &rcCaptionRect,\r
+                    DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);\r
+            }\r
+            else if(pImpl->_preview_file_icon != NULL)\r
+            {\r
+                FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));\r
+                \r
+                // Draw the files icon\r
+                const int destX = (rcClient.right - IconSize) / 2;\r
+                DrawIconEx(dc, destX, 0, pImpl->_preview_file_icon,\r
+                    IconSize, IconSize, 0, NULL,\r
+                    DI_NORMAL | DI_COMPAT);\r
+                    \r
+                // Draw the caption on\r
+                RECT rcCaptionRect = {rcClient.left,\r
+                    rcClient.top + IconSize + CaptionPadding,\r
+                    rcClient.right, rcClient.bottom};\r
+                    \r
+                WCHAR szFileName[_MAX_FNAME], szCaption[_MAX_FNAME + 32];\r
+                _wsplitpath(pImpl->_path_string, NULL, NULL, szFileName, NULL);\r
+                \r
+                const int iLength = snwprintf(szCaption,\r
+                    sizeof(szCaption), L"%s\n%d kB",\r
+                    szFileName, pImpl->_preview_file_size);\r
+                \r
+                DrawTextW(dc, szCaption, iLength, &rcCaptionRect,\r
+                    DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS);\r
+            }\r
+            else\r
+            {\r
+                // Can't show anything!\r
+                FillRect(dc, &rcClient, (HBRUSH)(COLOR_3DFACE + 1));\r
+            }\r
+            \r
+            pImpl->_mutex->unlock();\r
+            \r
+            // Finish painting\r
+            SelectObject(dc, hOldFont);\r
+            EndPaint(hwnd, &paint_struct);\r
+        }\r
+        \r
+        break;\r
+        \r
+    case WM_DESTROY:\r
+        pImpl->free_preview();\r
+        break;\r
+        \r
+    default:\r
+        lResult = DefWindowProc(hwnd, uMsg, wParam, lParam);\r
+        break;\r
+    }\r
+\r
+    return lResult;\r
+}\r
+\r
+void FileOpenDialogImplWin32::enable_preview(bool enable)\r
+{\r
+    _show_preview = enable;\r
+\r
+    // Relayout the dialog\r
+    ShowWindow(_preview_wnd, enable ? SW_SHOW : SW_HIDE);\r
+    layout_dialog();\r
+    \r
+    // Load or unload the preview\r
+    if(enable)\r
+    {\r
+        _mutex->lock();\r
+        _file_selected = true;\r
+        _mutex->unlock();\r
+    }\r
+    else free_preview();\r
+}\r
+\r
+void FileOpenDialogImplWin32::layout_dialog()\r
+{\r
+    union RECTPOINTS\r
+    {\r
+        RECT r;\r
+        POINT p[2];\r
+    };    \r
+    \r
+    const float MaxExtentScale = 2.0f / 3.0f;\r
+    \r
+    RECT rcClient;\r
+    GetClientRect(_file_dialog_wnd, &rcClient);\r
+\r
+    // Re-layout the dialog\r
+    HWND hFileListWnd = GetDlgItem(_file_dialog_wnd, lst2);\r
+    HWND hFolderComboWnd = GetDlgItem(_file_dialog_wnd, cmb2);\r
+    \r
+    \r
+    RECT rcFolderComboRect;\r
+    RECTPOINTS rcFileList;\r
+    GetWindowRect(hFileListWnd, &rcFileList.r);\r
+    GetWindowRect(hFolderComboWnd, &rcFolderComboRect);\r
+    const int iPadding = rcFileList.r.top - rcFolderComboRect.bottom;\r
+    MapWindowPoints(NULL, _file_dialog_wnd, rcFileList.p, 2);\r
+        \r
+    RECT rcPreview;\r
+    RECT rcBody = {rcFileList.r.left, rcFileList.r.top,\r
+        rcClient.right - iPadding, rcFileList.r.bottom};\r
+    rcFileList.r.right = rcBody.right;\r
+    \r
+    if(_show_preview)\r
+    {\r
+        rcPreview.top = rcBody.top;\r
+        rcPreview.left = rcClient.right - (rcBody.bottom - rcBody.top);\r
+        const int iMaxExtent = (int)(MaxExtentScale * (float)(rcBody.left + rcBody.right)) + iPadding / 2;\r
+        if(rcPreview.left < iMaxExtent) rcPreview.left = iMaxExtent;\r
+        rcPreview.bottom = rcBody.bottom;\r
+        rcPreview.right = rcBody.right;\r
+        \r
+        // Re-layout the preview box\r
+        _mutex->lock();\r
+\r
+            _preview_width = rcPreview.right - rcPreview.left;\r
+            _preview_height = rcPreview.bottom - rcPreview.top;\r
+\r
+        _mutex->unlock();\r
+        \r
+        render_preview();\r
+        \r
+        MoveWindow(_preview_wnd, rcPreview.left, rcPreview.top,\r
+            _preview_width, _preview_height, TRUE);\r
+            \r
+        rcFileList.r.right = rcPreview.left - iPadding;\r
+    }\r
+    \r
+    // Re-layout the file list box\r
+    MoveWindow(hFileListWnd, rcFileList.r.left, rcFileList.r.top,\r
+        rcFileList.r.right - rcFileList.r.left,\r
+        rcFileList.r.bottom - rcFileList.r.top, TRUE);\r
+        \r
+    // Re-layout the toolbar\r
+    RECTPOINTS rcToolBar;\r
+    GetWindowRect(_toolbar_wnd, &rcToolBar.r);\r
+    MapWindowPoints(NULL, _file_dialog_wnd, rcToolBar.p, 2);\r
+    MoveWindow(_toolbar_wnd, rcToolBar.r.left, rcToolBar.r.top, \r
+        rcToolBar.r.right - rcToolBar.r.left, rcToolBar.r.bottom - rcToolBar.r.top, TRUE); \r
+}\r
+\r
+void FileOpenDialogImplWin32::file_selected()\r
+{\r
+    // Destroy any previous previews\r
+    free_preview();\r
+    \r
+\r
+    // Determine if the file exists\r
+    DWORD attributes = GetFileAttributesW(_path_string);\r
+    if(attributes == 0xFFFFFFFF ||\r
+        attributes == FILE_ATTRIBUTE_DIRECTORY)\r
+    {\r
+        InvalidateRect(_preview_wnd, NULL, FALSE);\r
+        return;\r
+    }\r
+\r
+    // Check the file exists and get the file size\r
+    HANDLE file_handle = CreateFileW(_path_string, GENERIC_READ,\r
+        FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+    if(file_handle == INVALID_HANDLE_VALUE) return;    \r
+    const DWORD file_size = GetFileSize(file_handle, NULL);\r
+    if (file_size == INVALID_FILE_SIZE) return;\r
+    _preview_file_size = file_size / 1024;\r
+    CloseHandle(file_handle);\r
+        \r
+    if(_show_preview) load_preview();    \r
+}\r
+    \r
+void FileOpenDialogImplWin32::load_preview()\r
+{\r
+    // Destroy any previous previews\r
+    free_preview();\r
+    \r
+    // Try to get the file icon\r
+    SHFILEINFOW fileInfo;\r
+    if(SUCCEEDED(SHGetFileInfoW(_path_string, 0, &fileInfo,\r
+        sizeof(fileInfo), SHGFI_ICON | SHGFI_LARGEICON)))\r
+        _preview_file_icon = fileInfo.hIcon;\r
+        \r
+    // Will this file be too big?\r
+    if(_preview_file_size > MaxPreviewFileSize)\r
+    {\r
+        InvalidateRect(_preview_wnd, NULL, FALSE);\r
+        return;\r
+    }\r
+\r
+    // Prepare to render a preview\r
+    const Glib::ustring svg = ".svg";\r
+    const Glib::ustring svgz = ".svgz";\r
+    const Glib::ustring path = utf16_to_ustring(_path_string);\r
+    \r
+    bool success = false;\r
+    \r
+    _preview_document_width = _preview_document_height = 0;\r
+    \r
+    if ((dialogType == SVG_TYPES || dialogType == IMPORT_TYPES) &&\r
+            (hasSuffix(path, svg) || hasSuffix(path, svgz)))\r
+        success = set_svg_preview();\r
+    else if (isValidImageFile(path))\r
+        success = set_image_preview();\r
+    else {\r
+        // Show no preview\r
+    }\r
+    \r
+    if(success) render_preview();\r
+    \r
+    InvalidateRect(_preview_wnd, NULL, FALSE);\r
+}\r
+\r
+void FileOpenDialogImplWin32::free_preview()\r
+{\r
+    _mutex->lock();\r
+    if(_preview_bitmap != NULL)\r
+        DeleteObject(_preview_bitmap);\r
+    _preview_bitmap = NULL;\r
+    \r
+    if(_preview_file_icon != NULL)\r
+        DestroyIcon(_preview_file_icon);\r
+    _preview_file_icon = NULL;\r
+    \r
+    _preview_bitmap_image.clear();\r
+    _mutex->unlock();\r
+}\r
+\r
+bool FileOpenDialogImplWin32::set_svg_preview()\r
+{\r
+    const int PreviewSize = 512;\r
+\r
+    gchar *utf8string = g_utf16_to_utf8((const gunichar2*)_path_string,\r
+        _MAX_PATH, NULL, NULL, NULL);\r
+    SPDocument *svgDoc = sp_document_new (utf8string, true);\r
+    g_free(utf8string);\r
+        \r
+    // Check the document loaded properly        \r
+    if(svgDoc == NULL) return false;\r
+    if(svgDoc->root == NULL)\r
+    {\r
+        sp_document_unref(svgDoc);\r
+        return false;\r
+    }\r
+    \r
+    // Get the size of the document\r
+    const double svgWidth = sp_document_width(svgDoc);\r
+    const double svgHeight = sp_document_height(svgDoc);\r
+    \r
+    // Find the minimum scale to fit the image inside the preview area\r
+    const double scaleFactorX =    PreviewSize / svgWidth;\r
+    const double scaleFactorY =    PreviewSize / svgHeight;\r
+    const double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;\r
+    \r
+    // Now get the resized values\r
+    const double scaledSvgWidth  = scaleFactor * svgWidth;\r
+    const double scaledSvgHeight = scaleFactor * svgHeight;\r
+    \r
+    NR::Rect area(NR::Point(0, 0), NR::Point(scaledSvgWidth, scaledSvgHeight));\r
+    NRRectL areaL = {0, 0, scaledSvgWidth, scaledSvgHeight};\r
+    NRRectL bbox = {0, 0, scaledSvgWidth, scaledSvgHeight};\r
+        \r
+    // write object bbox to area\r
+    NR::Maybe<NR::Rect> maybeArea(area);\r
+    sp_document_ensure_up_to_date (svgDoc);\r
+    sp_item_invoke_bbox((SPItem *) svgDoc->root, &maybeArea,\r
+        sp_item_i2r_affine((SPItem *)(svgDoc->root)), TRUE);\r
+    \r
+    NRArena *const arena = NRArena::create();\r
+        \r
+    unsigned const key = sp_item_display_key_new(1);\r
+    \r
+    NRArenaItem *root = sp_item_invoke_show((SPItem*)(svgDoc->root),\r
+        arena, key, SP_ITEM_SHOW_DISPLAY);\r
+    \r
+    NRGC gc(NULL);\r
+    nr_matrix_set_scale(&gc.transform, scaleFactor, scaleFactor);\r
+    \r
+    nr_arena_item_invoke_update (root, NULL, &gc,\r
+        NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);\r
+    \r
+    // Prepare a GDI compatible NRPixBlock\r
+    NRPixBlock pixBlock;\r
+    pixBlock.size = NR_PIXBLOCK_SIZE_BIG;\r
+    pixBlock.mode = NR_PIXBLOCK_MODE_R8G8B8;\r
+    pixBlock.empty = 1;\r
+    pixBlock.visible_area.x0 = pixBlock.area.x0 = 0;\r
+    pixBlock.visible_area.y0 = pixBlock.area.y0 = 0;\r
+    pixBlock.visible_area.x1 = pixBlock.area.x1 = scaledSvgWidth;\r
+    pixBlock.visible_area.y1 = pixBlock.area.y1 = scaledSvgHeight;\r
+    pixBlock.rs = 4 * ((3 * (int)scaledSvgWidth + 3) / 4);\r
+    pixBlock.data.px = g_try_new (unsigned char, pixBlock.rs * scaledSvgHeight);\r
+    \r
+    // Fail if the pixblock failed to allocate\r
+    if(pixBlock.data.px == NULL)\r
+    {\r
+        sp_document_unref(svgDoc);\r
+        return false;\r
+    }\r
+    \r
+    memset(pixBlock.data.px, 0xFF, pixBlock.rs * scaledSvgHeight);\r
+    \r
+    memcpy(&root->bbox, &areaL, sizeof(areaL));\r
+            \r
+    // Render the image\r
+    nr_arena_item_invoke_render(NULL, root, &bbox, &pixBlock, /*0*/NR_ARENA_ITEM_RENDER_NO_CACHE);\r
+    \r
+    // Tidy up\r
+    sp_document_unref(svgDoc);\r
+    sp_item_invoke_hide((SPItem*)(svgDoc->root), key);\r
+    nr_arena_item_unref(root);\r
+    nr_object_unref((NRObject *) arena);\r
+    \r
+    // Create the GDK pixbuf\r
+    _mutex->lock();\r
+    \r
+    _preview_bitmap_image = Gdk::Pixbuf::create_from_data(\r
+        pixBlock.data.px, Gdk::COLORSPACE_RGB, false, 8,\r
+        (int)scaledSvgWidth, (int)scaledSvgHeight, pixBlock.rs,\r
+        sigc::ptr_fun(destroy_svg_rendering));\r
+\r
+    _preview_document_width = scaledSvgWidth;\r
+    _preview_document_height = scaledSvgHeight;\r
+    _preview_image_width = svgWidth;\r
+    _preview_image_height = svgHeight;\r
+        \r
+    _mutex->unlock();\r
+        \r
+    return true;\r
+}\r
+\r
+void FileOpenDialogImplWin32::destroy_svg_rendering(const guint8 *buffer)\r
+{\r
+    g_assert(buffer != NULL);\r
+    g_free((void*)buffer);\r
+}\r
+    \r
+bool FileOpenDialogImplWin32::set_image_preview()\r
+{\r
+    const Glib::ustring path = utf16_to_ustring(_path_string, _MAX_PATH);\r
+    \r
+    _mutex->lock();\r
+    _preview_bitmap_image = Gdk::Pixbuf::create_from_file(path);\r
+    if(!_preview_bitmap_image) return false;\r
+    \r
+    _preview_image_width = _preview_bitmap_image->get_width();\r
+    _preview_document_width = _preview_image_width;\r
+    _preview_image_height = _preview_bitmap_image->get_height();\r
+    _preview_document_height = _preview_image_height;\r
+    \r
+    _mutex->unlock();\r
+\r
+    return true;\r
+}\r
+\r
+void FileOpenDialogImplWin32::render_preview()\r
+{\r
+    double x, y;\r
+    const double blurRadius = 8;\r
+    const double halfBlurRadius = blurRadius / 2;\r
+    const int shaddowOffsetX = 0;\r
+    const int shaddowOffsetY = 2;\r
+    const int pagePadding = 5;\r
+    const double shaddowAlpha = 0.75;\r
+    \r
+    // Is the preview showing?\r
+    if(!_show_preview)\r
+        return;\r
+    \r
+    // Do we have anything to render?\r
+    _mutex->lock();\r
+    \r
+    if(!_preview_bitmap_image)\r
+    {\r
+        _mutex->unlock();\r
+        return;\r
+    }\r
+        \r
+    // Tidy up any previous bitmap renderings\r
+    if(_preview_bitmap != NULL)\r
+        DeleteObject(_preview_bitmap);\r
+    _preview_bitmap = NULL;\r
+    \r
+    // Calculate the size of the caption\r
+    int captionHeight = 0;\r
+\r
+    if(_preview_wnd != NULL)\r
+    {\r
+        RECT rcCaptionRect;\r
+        WCHAR szCaption[_MAX_FNAME + 32];                \r
+        const int iLength = format_caption(szCaption,\r
+            sizeof(szCaption) / sizeof(WCHAR));\r
+    \r
+        HDC dc = GetDC(_preview_wnd);\r
+        DrawTextW(dc, szCaption, iLength, &rcCaptionRect,\r
+            DT_CENTER | DT_TOP | DT_NOPREFIX | DT_PATH_ELLIPSIS | DT_CALCRECT);\r
+        ReleaseDC(_preview_wnd, dc);\r
+    \r
+        captionHeight = rcCaptionRect.bottom - rcCaptionRect.top;\r
+    }\r
+    \r
+    // Find the minimum scale to fit the image inside the preview area\r
+    const double scaleFactorX =\r
+        ((double)_preview_width - pagePadding * 2 - blurRadius)  / _preview_document_width;\r
+    const double scaleFactorY =\r
+        ((double)_preview_height - pagePadding * 2\r
+        - shaddowOffsetY - halfBlurRadius - captionHeight) / _preview_document_height;\r
+    double scaleFactor = (scaleFactorX > scaleFactorY) ? scaleFactorY : scaleFactorX;\r
+    scaleFactor = (scaleFactor > 1.0) ? 1.0 : scaleFactor;    \r
+    \r
+    // Now get the resized values\r
+    const double scaledSvgWidth  = scaleFactor * _preview_document_width;\r
+    const double scaledSvgHeight = scaleFactor * _preview_document_height;\r
+    \r
+    const int svgX = pagePadding + halfBlurRadius;\r
+    const int svgY = pagePadding;\r
+    \r
+    const int frameX = svgX - pagePadding;\r
+    const int frameY = svgY - pagePadding;\r
+    const int frameWidth = scaledSvgWidth + pagePadding * 2;\r
+    const int frameHeight = scaledSvgHeight + pagePadding * 2;\r
+    \r
+    const int totalWidth = (int)ceil(frameWidth + blurRadius);\r
+    const int totalHeight = (int)ceil(frameHeight + blurRadius);\r
+    \r
+    // Prepare the drawing surface\r
+    HDC hDC = GetDC(_preview_wnd);\r
+    HDC hMemDC = CreateCompatibleDC(hDC);\r
+    _preview_bitmap = CreateCompatibleBitmap(hDC, totalWidth, totalHeight);\r
+    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, _preview_bitmap);\r
+    Cairo::RefPtr<Win32Surface> surface = Win32Surface::create(hMemDC);\r
+    Cairo::RefPtr<Context> context = Context::create(surface);\r
+\r
+    // Paint the background to match the dialog colour\r
+    const COLORREF background = GetSysColor(COLOR_3DFACE);  \r
+    context->set_source_rgb(\r
+        GetRValue(background) / 255.0,\r
+        GetGValue(background) / 255.0,\r
+        GetBValue(background) / 255.0);\r
+    context->paint();\r
+     \r
+    //----- Draw the drop shaddow -----//\r
+    \r
+    // Left Edge\r
+    x = frameX + shaddowOffsetX - halfBlurRadius;\r
+    Cairo::RefPtr<LinearGradient> leftEdgeFade = LinearGradient::create(\r
+        x, 0.0, x + blurRadius, 0.0);\r
+    leftEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);\r
+    leftEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);\r
+    context->set_source(leftEdgeFade);\r
+    context->rectangle (x, frameY + shaddowOffsetY + halfBlurRadius,\r
+        blurRadius, frameHeight - blurRadius);\r
+    context->fill();\r
+    \r
+    // Right Edge\r
+    x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;\r
+    Cairo::RefPtr<LinearGradient> rightEdgeFade = LinearGradient::create(\r
+        x, 0.0,    x + blurRadius, 0.0);\r
+    rightEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
+    rightEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
+    context->set_source(rightEdgeFade);\r
+    context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,\r
+        frameY + shaddowOffsetY + halfBlurRadius,\r
+        blurRadius, frameHeight - blurRadius);\r
+    context->fill();\r
+        \r
+    // Top Edge\r
+    y = frameY + shaddowOffsetY - halfBlurRadius;\r
+    Cairo::RefPtr<LinearGradient> topEdgeFade = LinearGradient::create(\r
+        0.0, y, 0.0, y + blurRadius);\r
+    topEdgeFade->add_color_stop_rgba (0, 0, 0, 0, 0);\r
+    topEdgeFade->add_color_stop_rgba (1, 0, 0, 0, shaddowAlpha);\r
+    context->set_source(topEdgeFade);\r
+    context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,\r
+        frameWidth - blurRadius, blurRadius);\r
+    context->fill();\r
+    \r
+    // Bottom Edge\r
+    y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;\r
+    Cairo::RefPtr<LinearGradient> bottomEdgeFade = LinearGradient::create(\r
+        0.0, y,    0.0, y + blurRadius);\r
+    bottomEdgeFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
+    bottomEdgeFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
+    context->set_source(bottomEdgeFade);\r
+    context->rectangle (frameX + shaddowOffsetX + halfBlurRadius, y,\r
+        frameWidth - blurRadius, blurRadius);\r
+    context->fill();\r
+    \r
+    // Top Left Corner\r
+    x = frameX + shaddowOffsetX - halfBlurRadius;\r
+    y = frameY + shaddowOffsetY - halfBlurRadius;\r
+    Cairo::RefPtr<RadialGradient> topLeftCornerFade = RadialGradient::create(\r
+        x + blurRadius, y + blurRadius, 0, x + blurRadius, y + blurRadius, blurRadius);\r
+    topLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
+    topLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
+    context->set_source(topLeftCornerFade);\r
+    context->rectangle (x, y, blurRadius, blurRadius);\r
+    context->fill();\r
+    \r
+    // Top Right Corner\r
+    x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;\r
+    y = frameY + shaddowOffsetY - halfBlurRadius;\r
+    Cairo::RefPtr<RadialGradient> topRightCornerFade = RadialGradient::create(\r
+        x, y + blurRadius, 0, x, y + blurRadius, blurRadius);\r
+    topRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
+    topRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
+    context->set_source(topRightCornerFade);\r
+    context->rectangle (x, y, blurRadius, blurRadius);\r
+    context->fill();\r
+    \r
+    // Bottom Left Corner\r
+    x = frameX + shaddowOffsetX - halfBlurRadius;\r
+    y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;\r
+    Cairo::RefPtr<RadialGradient> bottomLeftCornerFade = RadialGradient::create(\r
+        x + blurRadius, y, 0, x + blurRadius, y, blurRadius);\r
+    bottomLeftCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
+    bottomLeftCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
+    context->set_source(bottomLeftCornerFade);\r
+    context->rectangle (x, y, blurRadius, blurRadius);\r
+    context->fill();\r
+    \r
+    // Bottom Right Corner\r
+    x = frameX + frameWidth + shaddowOffsetX - halfBlurRadius;\r
+    y = frameY + frameHeight + shaddowOffsetY - halfBlurRadius;\r
+    Cairo::RefPtr<RadialGradient> bottomRightCornerFade = RadialGradient::create(\r
+        x, y, 0, x, y, blurRadius);\r
+    bottomRightCornerFade->add_color_stop_rgba (0, 0, 0, 0, shaddowAlpha);\r
+    bottomRightCornerFade->add_color_stop_rgba (1, 0, 0, 0, 0);\r
+    context->set_source(bottomRightCornerFade);\r
+    context->rectangle (frameX + frameWidth + shaddowOffsetX - halfBlurRadius,\r
+        frameY + frameHeight + shaddowOffsetY - halfBlurRadius,\r
+        blurRadius, blurRadius);\r
+    context->fill();\r
+    \r
+    // Draw the frame\r
+    context->set_line_width(1);\r
+    context->rectangle (frameX, frameY,    frameWidth, frameHeight);\r
+    \r
+    context->set_source_rgb(1.0, 1.0, 1.0);\r
+    context->fill_preserve();\r
+    context->set_source_rgb(0.25, 0.25, 0.25);\r
+    context->stroke_preserve();\r
+    \r
+    // Draw the image\r
+    \r
+    if(_preview_bitmap_image)    // Is the image a pixbuf?\r
+    {\r
+        // Set the transformation\r
+        const Matrix matrix = {\r
+            scaleFactor, 0,\r
+            0, scaleFactor,\r
+            svgX, svgY };\r
+        context->set_matrix (matrix);\r
+    \r
+        // Render the image\r
+        set_source_pixbuf (context, _preview_bitmap_image, 0, 0);\r
+        context->paint();\r
+        \r
+        // Reset the transformation\r
+        context->set_identity_matrix();\r
+    }\r
+    \r
+    // Draw the inner frame\r
+    context->set_source_rgb(0.75, 0.75, 0.75);\r
+    context->rectangle (svgX, svgY,    scaledSvgWidth, scaledSvgHeight);\r
+    context->stroke();\r
+    \r
+    _mutex->unlock();\r
+\r
+    // Finish drawing\r
+    surface->finish();\r
+    SelectObject(hMemDC, hOldBitmap) ;\r
+    DeleteDC(hMemDC);\r
+    \r
+    // Refresh the preview pane\r
+    InvalidateRect(_preview_wnd, NULL, FALSE);\r
+}\r
+\r
+int FileOpenDialogImplWin32::format_caption(wchar_t *caption, int caption_size)\r
+{\r
+    wchar_t szFileName[_MAX_FNAME];\r
+    _wsplitpath(_path_string, NULL, NULL, szFileName, NULL);\r
+                \r
+    return snwprintf(caption, caption_size,\r
+        L"%s\n%d kB\n%d \xD7 %d", szFileName, _preview_file_size,\r
+        (int)_preview_document_width, (int)_preview_document_height);\r
+}\r
+\r
+/**\r
+ * Show this dialog modally.  Return true if user hits [OK]\r
+ */\r
+bool\r
+FileOpenDialogImplWin32::show()\r
+{\r
+    // We can only run one worker thread at a time\r
+    //if(_mutex != NULL) return false;\r
+    \r
+    if(!Glib::thread_supported())\r
+        Glib::thread_init();\r
+    \r
+    _result = false;\r
+    _finished = false;\r
+    _file_selected = false;\r
+    _mutex = new Glib::Mutex();\r
+    _main_loop = g_main_loop_new(g_main_context_default(), FALSE);\r
+    \r
+    if(Glib::Thread::create(sigc::mem_fun(*this, &FileOpenDialogImplWin32::GetOpenFileName_thread), true))\r
+    {\r
+        while(1)\r
+        {\r
+            g_main_context_iteration(g_main_context_default(), FALSE);\r
+            \r
+            if(_mutex->trylock())\r
+            {\r
+                // Read mutexed data\r
+                const bool finished = _finished;\r
+                const bool is_file_selected = _file_selected;\r
+                _file_selected = false;\r
+                _mutex->unlock();\r
+                \r
+                if(finished) break;\r
+                if(is_file_selected) file_selected();\r
+            }\r
+            \r
+            Sleep(10);\r
+        }\r
+        //g_main_loop_run(_main_loop);\r
+    }\r
+    \r
+    // Tidy up    \r
+    delete _mutex;\r
+    _mutex = NULL;\r
+        \r
+    return _result;\r
+}\r
+\r
+/**\r
+ * To Get Multiple filenames selected at-once.\r
+ */\r
+std::vector<Glib::ustring>FileOpenDialogImplWin32::getFilenames()\r
+{\r
+    std::vector<Glib::ustring> result;\r
+    result.push_back(getFilename());\r
+    return result;\r
+}\r
+\r
+\r
+/*#########################################################################\r
+### F I L E    S A V E\r
+#########################################################################*/\r
+\r
+/**\r
+ * Constructor\r
+ */\r
+FileSaveDialogImplWin32::FileSaveDialogImplWin32(Gtk::Window &parent, \r
+            const Glib::ustring &dir,\r
+            FileDialogType fileTypes,\r
+            const char *title,\r
+            const Glib::ustring &/*default_key*/) :\r
+    FileDialogBaseWin32(parent, dir, title, fileTypes, "dialogs.save_as")\r
+{\r
+    _main_loop = NULL;\r
+\r
+    createFilterMenu();\r
+}\r
+\r
+FileSaveDialogImplWin32::~FileSaveDialogImplWin32()\r
+{\r
+}\r
+\r
+void FileSaveDialogImplWin32::createFilterMenu()\r
+{\r
+    list<Filter> filter_list;\r
+\r
+    knownExtensions.clear();\r
+\r
+    // Compose the filter string\r
+    Glib::ustring all_inkscape_files_filter, all_image_files_filter;\r
+    Inkscape::Extension::DB::OutputList extension_list;\r
+    Inkscape::Extension::db.get_output_list(extension_list);\r
+\r
+    int filter_count = 0;\r
+    int filter_length = 0;\r
+            \r
+    for (Inkscape::Extension::DB::OutputList::iterator current_item = extension_list.begin();\r
+         current_item != extension_list.end(); current_item++)\r
+    {\r
+        Inkscape::Extension::Output *omod = *current_item;\r
+        if (omod->deactivated()) continue;\r
+        \r
+        filter_count++;\r
+        \r
+        Filter filter;\r
+        \r
+        // Extension\r
+        const gchar *filter_extension = omod->get_extension();      \r
+        filter.filter = g_utf8_to_utf16(\r
+            filter_extension, -1, NULL, &filter.filter_length, NULL);    \r
+        knownExtensions.insert( Glib::ustring(filter_extension).casefold() );\r
+        \r
+        // Type\r
+        filter.name = g_utf8_to_utf16(\r
+            omod->get_filetypename(), -1, NULL, &filter.name_length, NULL);\r
+            \r
+        filter.mod = omod;\r
+                        \r
+        filter_length += filter.name_length +\r
+            filter.filter_length + 3;   // Add 3 for two \0s and a *\r
+            \r
+        filter_list.push_back(filter);\r
+    }\r
+     \r
+    int extension_index = 0;\r
+    _extension_map = new Inkscape::Extension::Extension*[filter_count];\r
+    \r
+    _filter = new wchar_t[filter_length];\r
+    wchar_t *filterptr = _filter;\r
+    \r
+    for(list<Filter>::iterator filter_iterator = filter_list.begin();\r
+        filter_iterator != filter_list.end(); filter_iterator++)\r
+    {\r
+        const Filter &filter = *filter_iterator;\r
+    \r
+        memcpy(filterptr, filter.name, filter.name_length * 2);\r
+        filterptr += filter.name_length;\r
+        g_free(filter.name);\r
+    \r
+        *(filterptr++) = L'\0';\r
+        *(filterptr++) = L'*';\r
+\r
+        memcpy(filterptr, filter.filter, filter.filter_length * 2);\r
+        filterptr += filter.filter_length;\r
+        g_free(filter.filter);\r
+    \r
+        *(filterptr++) = L'\0';\r
+        \r
+        // Associate this input extension with the file type name\r
+        _extension_map[extension_index++] = filter.mod;\r
+    }\r
+    *(filterptr++) = 0;\r
+    \r
+    _filterIndex = 0;\r
+}\r
+\r
+void FileSaveDialogImplWin32::GetSaveFileName_thread()\r
+{\r
+    OPENFILENAMEEXW ofn;\r
+    \r
+    g_assert(this != NULL);\r
+    //g_assert(_mutex != NULL);\r
+    g_assert(_main_loop != NULL);    \r
+\r
+    gunichar2* current_directory_string = g_utf8_to_utf16(\r
+        _current_directory.data(), -1, NULL, NULL, NULL);\r
+    \r
+    // Copy the selected file name, converting from UTF-8 to UTF-16\r
+    memset(_path_string, 0, sizeof(_path_string));\r
+    gunichar2* utf16_path_string = g_utf8_to_utf16(\r
+        myFilename.data(), -1, NULL, NULL, NULL);\r
+    wcsncpy(_path_string, (wchar_t*)utf16_path_string, _MAX_PATH);\r
+    g_free(utf16_path_string);\r
+    \r
+    ZeroMemory(&ofn, sizeof(ofn));\r
+    ofn.lStructSize = sizeof(ofn);\r
+    ofn.hwndOwner = _ownerHwnd;\r
+    ofn.lpstrFile = _path_string;\r
+    ofn.nMaxFile = _MAX_PATH;\r
+    ofn.nFilterIndex = _filterIndex;\r
+    ofn.lpstrFileTitle = NULL;\r
+    ofn.nMaxFileTitle = 0;\r
+    ofn.lpstrInitialDir = (wchar_t*)current_directory_string;\r
+    ofn.lpstrTitle = _title;\r
+    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;\r
+    ofn.lpstrFilter = _filter;\r
+    ofn.nFilterIndex = _filterIndex;\r
+    \r
+    _result = GetSaveFileNameW(&ofn) != 0;\r
+    \r
+    _filterIndex = ofn.nFilterIndex;\r
+    _extension = _extension_map[ofn.nFilterIndex];\r
+    \r
+    // Copy the selected file name, converting from UTF-16 to UTF-8\r
+    myFilename = utf16_to_ustring(_path_string, _MAX_PATH);\r
+        \r
+    //_mutex->lock();\r
+    //_finished = true;\r
+    //_mutex->unlock();\r
+    \r
+    \r
+    // Tidy up\r
+    g_free(current_directory_string);\r
+    \r
+    g_main_loop_quit(_main_loop);\r
+}\r
+\r
+/**\r
+ * Show this dialog modally.  Return true if user hits [OK]\r
+ */\r
+bool\r
+FileSaveDialogImplWin32::show()\r
+{\r
+    // We can only run one worker thread at a time\r
+    //if(_mutex != NULL) return false;\r
+\r
+    if(!Glib::thread_supported())\r
+        Glib::thread_init();\r
+        \r
+    _result = false;\r
+    //_finished = false;\r
+    //_mutex = new Glib::Mutex();\r
+    _main_loop = g_main_loop_new(g_main_context_default(), FALSE);\r
+    \r
+    if(Glib::Thread::create(sigc::mem_fun(*this, &FileSaveDialogImplWin32::GetSaveFileName_thread), true))\r
+    {\r
+        /*while(1)\r
+        {\r
+            // While the dialog runs - keep the main UI alive\r
+            g_main_context_iteration(g_main_context_default(), FALSE);\r
+            \r
+            if(_mutex->trylock())\r
+            {\r
+                if(_finished) break;\r
+                _mutex->unlock();\r
+            }\r
+            \r
+            Sleep(10);\r
+        }*/\r
+        g_main_loop_run(_main_loop);\r
+    }\r
+    //delete _mutex;\r
+    //_mutex = NULL;\r
+        \r
+    if(_result)\r
+        appendExtension(myFilename, (Inkscape::Extension::Output*)_extension);\r
+        \r
+    return _result;   \r
+}\r
+\r
+void FileSaveDialogImplWin32::setSelectionType( Inkscape::Extension::Extension * /*key*/ )\r
+{\r
+    // If no pointer to extension is passed in, look up based on filename extension.\r
+    \r
+}\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
diff --git a/src/ui/dialog/filedialogimpl-win32.h b/src/ui/dialog/filedialogimpl-win32.h
new file mode 100644 (file)
index 0000000..1b69c19
--- /dev/null
@@ -0,0 +1,348 @@
+/**\r
+ * Implementation of the file dialog interfaces defined in filedialog.h for Win32\r
+ *\r
+ * Authors:\r
+ *   Joel Holdsworth\r
+ *   The Inkscape Organization\r
+ *\r
+ * Copyright (C) 2004-2007 The Inkscape Organization\r
+ *\r
+ * Released under GNU GPL, read the file 'COPYING' for more information\r
+ */\r
\r
+#ifdef WIN32\r
+\r
+#include "gc-core.h"\r
+#include <windows.h>\r
+\r
+namespace Inkscape\r
+{\r
+namespace UI\r
+{\r
+namespace Dialog\r
+{\r
+\r
+/*#########################################################################\r
+### F I L E     D I A L O G    B A S E    C L A S S\r
+#########################################################################*/\r
+\r
+/// This class is the base implementation of a MS Windows\r
+/// file dialog.\r
+class FileDialogBaseWin32\r
+{\r
+protected:\r
+    /// Abstract Constructor\r
+    /// @param parent The parent window for the dialog\r
+    /// @param dir The directory to begin browing from\r
+    /// @param title The title caption for the dialog in UTF-8\r
+    /// @param type The dialog type\r
+    /// @param preferenceBase The preferences key\r
+    FileDialogBaseWin32(Gtk::Window &parent, const Glib::ustring &dir,\r
+        const char *title, FileDialogType type,\r
+        gchar const *preferenceBase);\r
+\r
+    /// Destructor\r
+    ~FileDialogBaseWin32();\r
+    \r
+public:\r
+\r
+    /// Gets the currently selected extension. Valid after an [OK]\r
+    /// @return Returns a pointer to the selected extension, or NULL\r
+    /// if the selected filter requires an automatic type detection\r
+    Inkscape::Extension::Extension* getSelectionType();\r
+    \r
+    /// Get the path of the current directory\r
+    Glib::ustring getCurrentDirectory();\r
\r
+protected:\r
+    /// The dialog type\r
+    FileDialogType dialogType;\r
+    \r
+    /// This mutex is used to ensure that the worker thread\r
+    /// that calls GetOpenFileName cannot collide with the\r
+    /// main Inkscape thread\r
+    Glib::Mutex *_mutex;\r
+    \r
+    /// This flag is set true when the GetOpenFileName call\r
+    /// has returned\r
+    bool _finished;\r
+    \r
+    /// A pointer to the GTK main-loop context object. This\r
+    /// is used to keep the rest of the inkscape UI running\r
+    /// while the file dialog is displayed\r
+    GMainLoop *_main_loop;\r
+    \r
+    /// The result of the call to GetOpenFileName. If true\r
+    /// the user clicked OK, if false the user clicked cancel\r
+    bool _result;\r
+    \r
+    /// The parent window\r
+    Gtk::Window &parent;\r
+    \r
+    /// The windows handle of the parent window\r
+    HWND _ownerHwnd;\r
+    \r
+    /// The path of the directory that is currently being\r
+    /// browsed\r
+    Glib::ustring _current_directory;\r
+    \r
+    /// The title of the dialog in UTF-16\r
+    wchar_t *_title;\r
+    \r
+    /// The path of the currently selected file in UTF-16\r
+    wchar_t _path_string[_MAX_PATH];\r
+    \r
+    /// The filter string for GetOpenFileName in UTF-16\r
+    wchar_t *_filter;\r
+    \r
+    /// The index of the currently selected filter\r
+    int _filterIndex;\r
+    \r
+    /// An array of the extensions associated with the\r
+    /// file types of each filter. So the Nth entry of\r
+    /// this array corresponds to the extension of the Nth\r
+    /// filter in the list. NULL if no specific extension is\r
+    /// specified/\r
+    Inkscape::Extension::Extension **_extension_map;\r
+\r
+    /// The currently selected extension. Valid after an [OK]\r
+    Inkscape::Extension::Extension *_extension;\r
+};\r
+\r
+\r
+/*#########################################################################\r
+### F I L E    O P E N\r
+#########################################################################*/\r
+\r
+/// An Inkscape compatible wrapper around MS Windows GetOpenFileName API\r
+class FileOpenDialogImplWin32 : public FileOpenDialog, public FileDialogBaseWin32\r
+{\r
+public:\r
+    /// Constructor\r
+    /// @param parent The parent window for the dialog\r
+    /// @param dir The directory to begin browing from\r
+    /// @param title The title caption for the dialog in UTF-8\r
+    /// @param type The dialog type\r
+    FileOpenDialogImplWin32(Gtk::Window &parent, \r
+                       const Glib::ustring &dir,\r
+                       FileDialogType fileTypes,\r
+                       const char *title);\r
+\r
+    /// Destructor\r
+    virtual ~FileOpenDialogImplWin32();\r
+\r
+    /// Shows the file dialog, and blocks until a file\r
+    /// has been selected.\r
+    /// @return Returns true if the the user selected a\r
+    /// file, or false if the user pressed cancel.\r
+    bool show();\r
+\r
+    /// Gets a list of the selected file names\r
+    /// @return Returns an STL vector filled with the\r
+    /// GTK names of the selected files\r
+    std::vector<Glib::ustring> getFilenames();\r
+    \r
+    /// Get the path of the current directory\r
+    virtual Glib::ustring getCurrentDirectory()\r
+        { return FileDialogBaseWin32::getCurrentDirectory(); }\r
+\r
+    /// Gets the currently selected extension. Valid after an [OK]\r
+    /// @return Returns a pointer to the selected extension, or NULL\r
+    /// if the selected filter requires an automatic type detection\r
+    virtual Inkscape::Extension::Extension* getSelectionType()\r
+        { return FileDialogBaseWin32::getSelectionType(); }\r
+\r
+private:\r
+\r
+    /// Create a filter menu for this type of dialog\r
+    void createFilterMenu();\r
+    \r
+    /// The handle of the preview pane window\r
+    HWND _preview_wnd;\r
+    \r
+    /// The handle of the file dialog window\r
+    HWND _file_dialog_wnd;\r
+    \r
+    /// A pointer to the standard window proc of the\r
+    /// unhooked file dialog\r
+    WNDPROC _base_window_proc;\r
+    \r
+    /// The handle of the bitmap of the "show preview"\r
+    /// toggle button\r
+    HBITMAP _show_preview_button_bitmap;\r
+    \r
+    /// The handle of the toolbar's window\r
+    HWND _toolbar_wnd;\r
+    \r
+    /// This flag is set true when the preview should be\r
+    /// shown, or false when it should be hidden\r
+    static bool _show_preview;\r
+    \r
+    \r
+    /// The current width of the preview pane in pixels\r
+    int _preview_width;\r
+    \r
+    /// The current height of the preview pane in pixels\r
+    int _preview_height;\r
+    \r
+    /// The handle of the windows to display within the\r
+    /// preview pane, or NULL if no image should be displayed\r
+    HBITMAP _preview_bitmap;\r
+    \r
+    /// The windows shell icon for the selected file\r
+    HICON _preview_file_icon;\r
+    \r
+    /// The size of the preview file in kilobytes\r
+    unsigned long _preview_file_size;\r
+\r
+    \r
+    /// The width of the document to be shown in the preview panel\r
+    double _preview_document_width;\r
+    \r
+    /// The width of the document to be shown in the preview panel\r
+    double _preview_document_height;\r
+    \r
+    /// The width of the rendered preview image in pixels\r
+    int _preview_image_width;\r
+    \r
+    /// The height of the rendered preview image in pixels\r
+    int _preview_image_height;\r
+\r
+    /// A GDK Pixbuf of the rendered preview to be displayed\r
+    Glib::RefPtr<Gdk::Pixbuf> _preview_bitmap_image;\r
+    \r
+    /// This flag is set true if a file has been selected\r
+    bool _file_selected;\r
+    \r
+    \r
+    /// The controller function for the thread which calls\r
+    /// GetOpenFileName\r
+    void GetOpenFileName_thread();\r
+    \r
+    /// Registers the Windows Class of the preview panel window\r
+    static void register_preview_wnd_class();\r
+    \r
+    /// A message proc which is called by the standard dialog\r
+    /// proc\r
+    static UINT_PTR CALLBACK GetOpenFileName_hookproc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);\r
+    \r
+    /// A message proc which wraps the standard dialog proc,\r
+    /// but intercepts some calls\r
+    static LRESULT CALLBACK file_dialog_subclass_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+    \r
+    /// The message proc for the preview panel window\r
+    static LRESULT CALLBACK preview_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
+    \r
+    /// Lays out the controls in the file dialog given it's\r
+    /// current size\r
+    /// GetOpenFileName thread only.\r
+    void layout_dialog();\r
+    \r
+    /// Enables or disables the file preview.\r
+    /// GetOpenFileName thread only.\r
+    void enable_preview(bool enable);\r
+    \r
+    /// This function is called in the App thread when a file had\r
+    /// been selected\r
+    void file_selected();\r
+    \r
+    /// Loads and renders the unshrunk preview image.\r
+    /// Main app thread only.\r
+    void load_preview();\r
+    \r
+    /// Frees all the allocated objects associated with the file\r
+    /// currently being previewed\r
+    /// Main app thread only.\r
+    void free_preview();\r
+    \r
+    /// Loads preview for an SVG or SVGZ file.\r
+    /// Main app thread only.\r
+    /// @return Returns true if the SVG loaded successfully\r
+    bool set_svg_preview();\r
+    \r
+    /// A callback to allow this class to dispose of the\r
+    /// memory block of the rendered SVG bitmap\r
+    /// @buffer buffer The buffer to free\r
+    static void destroy_svg_rendering(const guint8 *buffer);\r
+    \r
+    /// Loads the preview for a raster image\r
+    /// Main app thread only.\r
+    /// @return Returns true if the image loaded successfully\r
+    bool set_image_preview();\r
+    \r
+    /// Renders the unshrunk preview image to a windows HTBITMAP\r
+    /// which can be painted in the preview pain.\r
+    /// Main app thread only.\r
+    void render_preview();\r
+    \r
+    /// Formats the caption in UTF-16 for the preview image\r
+    /// @param caption The buffer to format the caption string into\r
+    /// @param caption_size The number of wchar_ts in the caption buffer \r
+    /// @return Returns the number of characters in caption string\r
+    int format_caption(wchar_t *caption, int caption_size);\r
+};\r
+\r
+\r
+/*#########################################################################\r
+### F I L E    S A V E\r
+#########################################################################*/\r
+\r
+/// An Inkscape compatible wrapper around MS Windows GetSaveFileName API\r
+class FileSaveDialogImplWin32 : public FileSaveDialog, public FileDialogBaseWin32\r
+{\r
+\r
+public:\r
+    FileSaveDialogImplWin32(Gtk::Window &parent, \r
+                       const Glib::ustring &dir,\r
+                       FileDialogType fileTypes,\r
+                       const char *title,\r
+                       const Glib::ustring &default_key);\r
+\r
+    /// Destructor\r
+    virtual ~FileSaveDialogImplWin32();\r
+\r
+    /// Shows the file dialog, and blocks until a file\r
+    /// has been selected.\r
+    /// @return Returns true if the the user selected a\r
+    /// file, or false if the user pressed cancel.\r
+    bool show();\r
+    \r
+    /// Get the path of the current directory\r
+    virtual Glib::ustring getCurrentDirectory()\r
+        { return FileDialogBaseWin32::getCurrentDirectory(); }\r
+\r
+    /// Gets the currently selected extension. Valid after an [OK]\r
+    /// @return Returns a pointer to the selected extension, or NULL\r
+    /// if the selected filter requires an automatic type detection\r
+    virtual Inkscape::Extension::Extension* getSelectionType()\r
+        { return FileDialogBaseWin32::getSelectionType(); }\r
+\r
+    virtual void setSelectionType( Inkscape::Extension::Extension *key );\r
+    \r
+private:\r
+\r
+    /**\r
+     *  Create a filter menu for this type of dialog\r
+     */\r
+    void createFilterMenu();\r
+\r
+    void GetSaveFileName_thread();\r
+};\r
+\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif\r
+\r
+/*\r
+  Local Variables:\r
+  mode:c++\r
+  c-file-style:"stroustrup"\r
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
+  indent-tabs-mode:nil\r
+  fill-column:99\r
+  End:\r
+*/\r
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r