For any file name paths potentially save in relative (../../ etc...) style if specified by the preferences.
Affects:
. Waypoint images
. DEM file list
. Map directory cache
. GeoRef file image
A new level of 'Advanced' preferences tab has been created to store the controlling setting.
return realpath ( path, real );
}
+/**
+ * Permission granted to use this code after personal correspondance
+ * Slightly reworked for better cross platform use, glibisms, function rename and a compacter format
+ *
+ * FROM http://www.codeguru.com/cpp/misc/misc/fileanddirectorynaming/article.php/c263
+ */
+
+// GetRelativeFilename(), by Rob Fisher.
+// rfisher@iee.org
+// http://come.to/robfisher
+
+// defines
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+// The number of characters at the start of an absolute filename. e.g. in DOS,
+// absolute filenames start with "X:\" so this value should be 3, in UNIX they start
+// with "\" so this value should be 1.
+#ifdef WINDOWS
+#define ABSOLUTE_NAME_START 3
+#else
+#define ABSOLUTE_NAME_START 1
+#endif
+
+// Given the absolute current directory and an absolute file name, returns a relative file name.
+// For example, if the current directory is C:\foo\bar and the filename C:\foo\whee\text.txt is given,
+// GetRelativeFilename will return ..\whee\text.txt.
+
+const gchar *file_GetRelativeFilename ( gchar *currentDirectory, gchar *absoluteFilename )
+{
+ gint afMarker = 0, rfMarker = 0;
+ gint cdLen = 0, afLen = 0;
+ gint i = 0;
+ gint levels = 0;
+ static gchar relativeFilename[MAXPATHLEN+1];
+
+ cdLen = strlen(currentDirectory);
+ afLen = strlen(absoluteFilename);
+
+ // make sure the names are not too long or too short
+ if (cdLen > MAXPATHLEN || cdLen < ABSOLUTE_NAME_START+1 ||
+ afLen > MAXPATHLEN || afLen < ABSOLUTE_NAME_START+1) {
+ return NULL;
+ }
+
+ // Handle DOS names that are on different drives:
+ if (currentDirectory[0] != absoluteFilename[0]) {
+ // not on the same drive, so only absolute filename will do
+ strcpy(relativeFilename, absoluteFilename);
+ return relativeFilename;
+ }
+
+ // they are on the same drive, find out how much of the current directory
+ // is in the absolute filename
+ i = ABSOLUTE_NAME_START;
+ while (i < afLen && i < cdLen && currentDirectory[i] == absoluteFilename[i]) {
+ i++;
+ }
+
+ if (i == cdLen && (absoluteFilename[i] == G_DIR_SEPARATOR || absoluteFilename[i-1] == G_DIR_SEPARATOR)) {
+ // the whole current directory name is in the file name,
+ // so we just trim off the current directory name to get the
+ // current file name.
+ if (absoluteFilename[i] == G_DIR_SEPARATOR) {
+ // a directory name might have a trailing slash but a relative
+ // file name should not have a leading one...
+ i++;
+ }
+
+ strcpy(relativeFilename, &absoluteFilename[i]);
+ return relativeFilename;
+ }
+
+ // The file is not in a child directory of the current directory, so we
+ // need to step back the appropriate number of parent directories by
+ // using "..\"s. First find out how many levels deeper we are than the
+ // common directory
+ afMarker = i;
+ levels = 1;
+
+ // count the number of directory levels we have to go up to get to the
+ // common directory
+ while (i < cdLen) {
+ i++;
+ if (currentDirectory[i] == G_DIR_SEPARATOR) {
+ // make sure it's not a trailing slash
+ i++;
+ if (currentDirectory[i] != '\0') {
+ levels++;
+ }
+ }
+ }
+
+ // move the absolute filename marker back to the start of the directory name
+ // that it has stopped in.
+ while (afMarker > 0 && absoluteFilename[afMarker-1] != G_DIR_SEPARATOR) {
+ afMarker--;
+ }
+
+ // check that the result will not be too long
+ if (levels * 3 + afLen - afMarker > MAXPATHLEN) {
+ return NULL;
+ }
+
+ // add the appropriate number of "..\"s.
+ rfMarker = 0;
+ for (i = 0; i < levels; i++) {
+ relativeFilename[rfMarker++] = '.';
+ relativeFilename[rfMarker++] = '.';
+ relativeFilename[rfMarker++] = G_DIR_SEPARATOR;
+ }
+
+ // copy the rest of the filename into the result string
+ strcpy(&relativeFilename[rfMarker], &absoluteFilename[afMarker]);
+
+ return relativeFilename;
+}
+/* END http://www.codeguru.com/cpp/misc/misc/fileanddirectorynaming/article.php/c263 */
char *file_realpath ( const char *path, char *real );
+const gchar *file_GetRelativeFilename ( gchar *currentDirectory, gchar *absoluteFilename );
+
G_END_DECLS
#endif
static gchar * params_units_height[] = {"Metres", "Feet", NULL};
static VikLayerParamScale params_scales_lat[] = { {-90.0, 90.0, 0.05, 2} };
static VikLayerParamScale params_scales_long[] = { {-180.0, 180.0, 0.05, 2} };
-
+static gchar * params_vik_fileref[] = {N_("Absolute"), N_("Relative"), NULL};
+
static VikLayerParam prefs1[] = {
{ VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_NAMESPACE "degree_format", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Degree format:"), VIK_LAYER_WIDGET_COMBOBOX, params_degree_formats, NULL, NULL },
};
{ VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_IO_NAMESPACE "external_gpx_2", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("External GPX Program 2:"), VIK_LAYER_WIDGET_FILEENTRY, NULL, NULL, NULL },
};
+static VikLayerParam prefs_advanced[] = {
+ { VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_ADVANCED_NAMESPACE "save_file_reference_mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Save File Reference Mode:"), VIK_LAYER_WIDGET_COMBOBOX, params_vik_fileref, NULL,
+ N_("When saving a Viking .vik file, this determines how the directory paths of filenames are written."), NULL },
+};
+
/* End of Options static stuff */
void a_vik_preferences_init ()
// 'Advanced' Properties
a_preferences_register_group ( VIKING_PREFERENCES_ADVANCED_GROUP_KEY, _("Advanced") );
+
+ tmp.u = VIK_FILE_REF_FORMAT_ABSOLUTE;
+ a_preferences_register(&prefs_advanced[0], tmp, VIKING_PREFERENCES_ADVANCED_GROUP_KEY);
}
vik_degree_format_t a_vik_get_degree_format ( )
{
return a_preferences_get(VIKING_PREFERENCES_IO_NAMESPACE "external_gpx_2")->s;
}
+
+vik_file_ref_format_t a_vik_get_file_ref_format ( )
+{
+ vik_file_ref_format_t format;
+ format = a_preferences_get(VIKING_PREFERENCES_ADVANCED_NAMESPACE "save_file_reference_mode")->u;
+ return format;
+}
const gchar* a_vik_get_external_gpx_program_2 ( );
+/* File reference preferences - mainly in saving of a viking file */
+typedef enum {
+ VIK_FILE_REF_FORMAT_ABSOLUTE,
+ VIK_FILE_REF_FORMAT_RELATIVE,
+} vik_file_ref_format_t;
+
+vik_file_ref_format_t a_vik_get_file_ref_format ( );
+
/* Group for global preferences */
#define VIKING_PREFERENCES_GROUP_KEY "viking.globals"
#define VIKING_PREFERENCES_NAMESPACE "viking.globals."
}
if ( wp->image )
{
- gchar *tmp_image = slashdup(wp->image);
- fprintf ( f, " image=\"%s\"", tmp_image );
+ gchar *tmp_image = NULL;
+ gchar *cwd = NULL;
+ if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
+ cwd = g_get_current_dir();
+ if ( cwd )
+ tmp_image = g_strdup ( file_GetRelativeFilename ( cwd, wp->image ) );
+ }
+
+ // if cwd not available - use image filename as is
+ // this should be an absolute path as set in thumbnails
+ if ( !cwd )
+ tmp_image = slashdup(wp->image);
+
+ if ( tmp_image )
+ fprintf ( f, " image=\"%s\"", tmp_image );
+
+ g_free ( cwd );
g_free ( tmp_image );
}
if ( wp->symbol )
// Thus we can see/use what was done
}
+/**
+ * Process the list of DEM files and convert each one to a relative path
+ */
+static GList *dem_layer_convert_to_relative_filenaming ( GList *files )
+{
+ gchar *cwd = g_get_current_dir();
+ if ( !cwd )
+ return files;
+
+ GList *relfiles = NULL;
+
+ while ( files ) {
+ gchar *file = g_strdup ( file_GetRelativeFilename ( cwd, files->data ) );
+ relfiles = g_list_prepend ( relfiles, file );
+ files = files->next;
+ }
+
+ g_free ( cwd );
+
+ if ( relfiles ) {
+ // Replacing current list, so delete old values first.
+ GList *iter = files;
+ while ( iter ) {
+ g_free ( iter->data );
+ iter = iter->next;
+ }
+ g_list_free ( files );
+
+ return relfiles;
+ }
+
+ return files;
+}
+
gboolean dem_layer_set_param ( VikDEMLayer *vdl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
{
switch ( id )
VikLayerParamData rv;
switch ( id )
{
- case PARAM_FILES: rv.sl = vdl->files; break;
+ case PARAM_FILES:
+ rv.sl = vdl->files;
+ if ( is_file_operation )
+ // Save in relative format if necessary
+ if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE )
+ rv.sl = dem_layer_convert_to_relative_filenaming ( rv.sl );
+ break;
case PARAM_SOURCE: rv.u = vdl->source; break;
case PARAM_TYPE: rv.u = vdl->type; break;
case PARAM_COLOR: rv.c = vdl->color; break;
}
/* Try to add file full_path.
- * full_path will be copied.
+ * filename will be copied.
* returns FALSE if file does not exists, TRUE otherwise.
*/
-static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *full_path )
+static gboolean dem_layer_add_file ( VikDEMLayer *vdl, const gchar *filename )
{
- if ( g_file_test(full_path, G_FILE_TEST_EXISTS ) == TRUE ) {
+ if ( g_file_test(filename, G_FILE_TEST_EXISTS) == TRUE ) {
/* only load if file size is not 0 (not in progress) */
struct stat sb;
- stat (full_path, &sb);
+ stat ( filename, &sb );
if ( sb.st_size ) {
- gchar *duped_path = g_strdup(full_path);
+ gchar *duped_path = g_strdup(filename);
vdl->files = g_list_prepend ( vdl->files, duped_path );
a_dems_load ( duped_path );
g_debug("%s: %s", __FUNCTION__, duped_path);
VikLayerParamData rv;
switch ( id )
{
- case PARAM_IMAGE: rv.s = vgl->image ? vgl->image : ""; break;
+ case PARAM_IMAGE: {
+ gboolean set = FALSE;
+ if ( is_file_operation ) {
+ if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
+ gchar *cwd = g_get_current_dir();
+ if ( cwd ) {
+ rv.s = file_GetRelativeFilename ( cwd, vgl->image );
+ if ( !rv.s ) rv.s = "";
+ set = TRUE;
+ }
+ }
+ }
+ if ( !set )
+ rv.s = vgl->image ? vgl->image : "";
+ break;
+ }
case PARAM_CN: rv.d = vgl->corner.northing; break;
case PARAM_CE: rv.d = vgl->corner.easting; break;
case PARAM_MN: rv.d = vgl->mpp_northing; break;
switch ( id )
{
case PARAM_CACHE_DIR:
+ {
+ gboolean set = FALSE;
/* Only save a blank when the map cache location equals the default
On reading in, when it is blank then the default is reconstructed
Since the default changes dependent on the user and OS, it means the resultant file is more portable */
- if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 )
+ if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
rv.s = "";
- else
- rv.s = vml->cache_dir ? vml->cache_dir : "";
+ set = TRUE;
+ }
+ else if ( is_file_operation ) {
+ if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
+ gchar *cwd = g_get_current_dir();
+ if ( cwd ) {
+ rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
+ if ( !rv.s ) rv.s = "";
+ set = TRUE;
+ }
+ }
+ }
+ if ( !set )
+ rv.s = vml->cache_dir ? vml->cache_dir : "";
break;
+ }
case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
case PARAM_ALPHA: rv.u = vml->alpha; break;
case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;