/** \file dprmfile.c * Param File Management */ /* XTrkCad - Model Railroad CAD * Copyright (C) 2005 Dave Bullis * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <assert.h> #include <stdint.h> #include <string.h> #include <time.h> #include "custom.h" #include "fileio.h" #include "i18n.h" #include "messages.h" #include "param.h" #include "paths.h" #include "track.h" typedef struct { char * name; char * contents; int deleted; int deletedShadow; int valid; } paramFileInfo_t; typedef paramFileInfo_t * paramFileInfo_p; static dynArr_t paramFileInfo_da; #define paramFileInfo(N) DYNARR_N( paramFileInfo_t, paramFileInfo_da, N ) EXPORT int curParamFileIndex = PARAM_DEMO; static char curParamDir[STR_LONG_SIZE]; static struct wFilSel_t * paramFile_fs; EXPORT wBool_t IsParamValid( int fileInx ) { if (fileInx == PARAM_DEMO) return (curDemo>=0); else if (fileInx == PARAM_CUSTOM) return TRUE; else if (fileInx == PARAM_LAYOUT) return TRUE; else if (fileInx >= 0 && fileInx < paramFileInfo_da.cnt) return (!paramFileInfo(fileInx).deleted) && paramFileInfo(fileInx).valid; else return FALSE; } EXPORT char * GetParamFileName( int fileInx ) { return paramFileInfo(fileInx).contents; } static BOOL_T UpdateParamFiles( void ) { char fileName[STR_LONG_SIZE], *fileNameP; char * contents; const char * cp; FILE * updateF; FILE * paramF; long updateTime; long lastTime; MakeFullpath(&fileNameP, libDir, "xtrkcad.upd", NULL); updateF = fopen( fileNameP, "r" ); free(fileNameP); if ( updateF == NULL ) return FALSE; if ( fgets( message, sizeof message, updateF ) == NULL ) { NoticeMessage( "short file: xtrkcad.upd", _("Ok"), NULL ); return FALSE; } wPrefGetInteger( "file", "updatetime", &lastTime, 0 ); updateTime = atol( message ); if ( lastTime >= updateTime ) return FALSE; while ( ( fgets( fileName, STR_LONG_SIZE, updateF ) ) != NULL ) { Stripcr( fileName ); InfoMessage( _("Updating %s"), fileName ); MakeFullpath(&fileNameP, libDir, "params", fileName, NULL); paramF = fopen( fileNameP, "r" ); if ( paramF == NULL ) { NoticeMessage( MSG_PRMFIL_OPEN_NEW, _("Ok"), NULL, fileNameP ); free(fileNameP); continue; } contents = NULL; while ( ( fgets(message, sizeof message, paramF) ) != NULL ) { if (strncmp( message, "CONTENTS", 8 ) == 0) { Stripcr( message ); contents = message+9; break; } } fclose( paramF ); if (contents == NULL) { NoticeMessage( MSG_PRMFIL_NO_CONTENTS, _("Ok"), NULL, fileNameP ); free(fileNameP); continue; } cp = wPrefGetString( "Parameter File Map", contents ); wPrefSetString( "Parameter File Map", contents, fileNameP ); if (cp!=NULL && *cp!='\0') { /* been there, done that */ free(fileNameP); continue; } DYNARR_APPEND( paramFileInfo_t, paramFileInfo_da, 10 ); curParamFileIndex = paramFileInfo_da.cnt-1; paramFileInfo(curParamFileIndex).name = MyStrdup( fileNameP ); curContents = curSubContents = NULL; paramFileInfo(curParamFileIndex).deleted = FALSE; paramFileInfo(curParamFileIndex).valid = TRUE; paramFileInfo(curParamFileIndex).deletedShadow = paramFileInfo(curParamFileIndex).deleted = !ReadParams( 0, NULL, fileNameP ); paramFileInfo(curParamFileIndex).contents = curContents; free(fileNameP); } wPrefSetInteger( "file", "updatetime", updateTime ); return TRUE; } EXPORT void ReadParamFiles( void ) { int fileNo; const char *fileName; const char * contents; BOOL_T updated = FALSE; updated = UpdateParamFiles(); for ( fileNo=1; ; fileNo++ ) { sprintf( message, "File%d", fileNo ); contents = wPrefGetString( "Parameter File Names", message ); if (contents==NULL || *contents=='\0') break; InfoMessage( "Parameters for %s", contents ); fileName = wPrefGetString( "Parameter File Map", contents ); if (fileName==NULL || *fileName=='\0') { NoticeMessage( MSG_PRMFIL_NO_MAP, _("Ok"), NULL, contents ); continue; } DYNARR_APPEND( paramFileInfo_t, paramFileInfo_da, 10 ); curParamFileIndex = paramFileInfo_da.cnt-1; paramFileInfo(curParamFileIndex).name = MyStrdup( fileName ); curContents = NULL; paramFileInfo(curParamFileIndex).deleted = FALSE; paramFileInfo(curParamFileIndex).valid = TRUE; paramFileInfo(curParamFileIndex).deletedShadow = paramFileInfo(curParamFileIndex).deleted = !ReadParams( 0, NULL, fileName ); if (curContents == NULL) curContents = curSubContents = MyStrdup(contents); paramFileInfo(curParamFileIndex).contents = curContents; } curParamFileIndex = PARAM_CUSTOM; if (updated) { RememberParamFiles(); } } EXPORT void RememberParamFiles( void ) { int fileInx; int fileNo; char * contents, *cp; for (fileInx=0, fileNo=1; fileInx<paramFileInfo_da.cnt; fileInx++ ) { if (paramFileInfo(fileInx).valid && !paramFileInfo(fileInx).deleted) { sprintf( message, "File%d", fileNo++ ); contents = paramFileInfo(fileInx).contents; for ( cp=contents; *cp; cp++ ) { if ( *cp == '=' || *cp == '\'' || *cp == '"' || *cp == ':' || *cp == '.' ) *cp = ' '; } wPrefSetString( "Parameter File Names", message, contents ); wPrefSetString("Parameter File Map", contents, paramFileInfo(fileInx).name); } } sprintf( message, "File%d", fileNo++ ); wPrefSetString( "Parameter File Names", message, "" ); } /**************************************************************************** * * Param File Dialog * */ static wWin_p paramFileW; static long paramFileSel = 0; static wIcon_p mtbox_bm; static wIcon_p chkbox_bm; static void ParamFileAction( void * ); static void ParamFileBrowse( void * ); static void ParamFileSelectAll( void * ); static paramListData_t paramFileListData = { 10, 370 }; static char * paramFileLabels[] = { N_("Show File Names"), NULL }; static paramData_t paramFilePLs[] = { #define I_PRMFILLIST (0) #define paramFileL ((wList_p)paramFilePLs[I_PRMFILLIST].control) { PD_LIST, NULL, "inx", 0, ¶mFileListData, NULL, BL_DUP|BL_SETSTAY|BL_MANY }, #define I_PRMFILTOGGLE (1) { PD_TOGGLE, ¶mFileSel, "mode", 0, paramFileLabels, NULL, BC_HORZ|BC_NOBORDER }, { PD_BUTTON, (void *)ParamFileSelectAll, "selectall", PDO_DLGCMDBUTTON, NULL, N_("Select all") }, #define I_PRMFILACTION (3) #define paramFileActionB ((wButton_p)paramFilePLs[I_PRMFILACTION].control) { PD_BUTTON, (void*)ParamFileAction, "action", PDO_DLGCMDBUTTON, NULL, N_("Unload"), 0L, FALSE }, { PD_BUTTON, (void*)ParamFileBrowse, "browse", 0, NULL, N_("Browse ...") } }; static paramGroup_t paramFilePG = { "prmfile", 0, paramFilePLs, sizeof paramFilePLs/sizeof paramFilePLs[0] }; static void ParamFileLoadList( void ) { int fileInx; wIndex_t listInx; wControlShow( (wControl_p)paramFileL, FALSE ); listInx = wListGetIndex(paramFileL); wListClear( paramFileL ); for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ ) { if (paramFileInfo(fileInx).valid) { strcpy( message, ((!paramFileSel) && paramFileInfo(fileInx).contents)? paramFileInfo(fileInx).contents: paramFileInfo(fileInx).name ); wListAddValue( paramFileL, message, (paramFileInfo(fileInx).deleted)?mtbox_bm:chkbox_bm, (void*)(intptr_t)fileInx ); } } wListSetIndex( paramFileL, listInx ); wControlShow( (wControl_p)paramFileL, TRUE ); } /** * Load the selected parameter files. This is a callback executed when the file selection dialog * is closed. * Steps: * - the parameters are read from file * - check is performed to see whether the content is already present, if yes the previously * loaded content is invalidated * - loaded parameter file is added to list of parameter files * - if a parameter file dialog exists the list is updated. It is either rewritten in * in case of an invalidated file or the new file is appended * - the settings are updated * These steps are repeated for every file in list * * \param files IN the number of filenames in the fileName array * \param fileName IN an array of fully qualified filenames * \param data IN ignored * \return TRUE on success, FALSE on error */ EXPORT int LoadParamFile( int files, char ** fileName, void * data ) { wIndex_t inx; int i = 0; wBool_t redrawList = FALSE; assert( fileName != NULL ); assert( files > 0); for( i=0; i < files; i++ ) { curContents = curSubContents = NULL; curParamFileIndex = paramFileInfo_da.cnt; if ( !ReadParams( 0, NULL, fileName[ i ] ) ) return FALSE; assert( curContents != NULL ); // in case the contents is already presented, make invalid for ( inx=0; inx<paramFileInfo_da.cnt; inx++ ) { if ( paramFileInfo(inx).valid && strcmp( paramFileInfo(inx).contents, curContents ) == 0 ) { paramFileInfo(inx).valid = FALSE; redrawList = TRUE; break; } } DYNARR_APPEND( paramFileInfo_t, paramFileInfo_da, 10 ); paramFileInfo(curParamFileIndex).name = MyStrdup( fileName[ i ] ); paramFileInfo(curParamFileIndex).valid = TRUE; paramFileInfo(curParamFileIndex).deletedShadow = paramFileInfo(curParamFileIndex).deleted = FALSE; paramFileInfo(curParamFileIndex).contents = curContents; if ( paramFilePG.win ) { if ( redrawList ) { ParamFileLoadList(); } else { strcpy( message, ((!paramFileSel) && paramFileInfo(curParamFileIndex).contents)? paramFileInfo(curParamFileIndex).contents: paramFileInfo(curParamFileIndex).name ); wListAddValue( paramFileL, message, chkbox_bm, (void*)(intptr_t)curParamFileIndex ); wListSetIndex( paramFileL, wListGetCount(paramFileL)-1 ); } } wPrefSetString( "Parameter File Map", curContents, paramFileInfo(curParamFileIndex).name ); } curParamFileIndex = PARAM_CUSTOM; DoChangeNotification( CHANGE_PARAMS ); return TRUE; } static void ParamFileBrowse( void * junk ) { wFilSelect( paramFile_fs, curParamDir ); return; } /** * Update the action button. If at least one selected file is unloaded, the action button * is set to 'Reload'. If all selected files are loaded, the button will be set to 'Unload'. * * \param varname1 IN this is a variable * \return */ static void UpdateParamFileButton( wIndex_t fileInx ) { wIndex_t selcnt = wListGetSelectedCount( paramFileL ); wIndex_t inx, cnt; // set the default wButtonSetLabel( paramFileActionB, _("Unload")); paramFilePLs[ I_PRMFILACTION ].context = FALSE; //nothing selected -> leave if( selcnt <= 0 ) return; // get the number of items in list cnt = wListGetCount( paramFileL ); // walk through the whole list box for ( inx=0; inx<cnt; inx++ ) { if ( wListGetItemSelected( (wList_p)paramFileL, inx )) { // if item is selected, get status fileInx = (intptr_t)wListGetItemContext( paramFileL, inx ); if (fileInx < 0 || fileInx >= paramFileInfo_da.cnt) return; if( paramFileInfo(fileInx).deleted ) { // if selected file was unloaded, set button to reload and finish loop wButtonSetLabel( paramFileActionB, _("Reload")); paramFilePLs[ I_PRMFILACTION ].context = (void *)TRUE; break; } } } } /** * Unload selected files. * * \param action IN FALSE = unload, TRUE = reload parameter files * \return */ static void ParamFileAction( void * action ) { wIndex_t selcnt = wListGetSelectedCount( paramFileL ); wIndex_t inx, cnt; wIndex_t fileInx; unsigned newDeletedState; if( action ) newDeletedState = FALSE; else newDeletedState = TRUE; //nothing selected -> leave if( selcnt <= 0 ) return; // get the number of items in list cnt = wListGetCount( paramFileL ); // walk through the whole list box for ( inx=0; inx<cnt; inx++ ) { if ( wListGetItemSelected( (wList_p)paramFileL, inx ) ) { fileInx = (intptr_t)wListGetItemContext( paramFileL, inx ); // set the desired state paramFileInfo(fileInx).deleted = newDeletedState; strcpy( message, ((!paramFileSel) && paramFileInfo(fileInx).contents)? paramFileInfo(fileInx).contents: paramFileInfo(fileInx).name ); wListSetValues( paramFileL, inx, message, (paramFileInfo(fileInx).deleted)?mtbox_bm:chkbox_bm, (void*)(intptr_t)fileInx ); } } DoChangeNotification( CHANGE_PARAMS ); UpdateParamFileButton( fileInx ); } /** * Select all files in the list and set action button * * \param junk IN ignored * \return */ static void ParamFileSelectAll( void *junk ) { wListSelectAll( paramFileL ); UpdateParamFileButton( 0 ); } static void ParamFileOk( void * junk ) { wIndex_t fileInx; for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ ) paramFileInfo(fileInx).deletedShadow = paramFileInfo(fileInx).deleted; wHide( paramFileW ); } static void ParamFileCancel( wWin_p junk ) { wIndex_t fileInx; for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ ) paramFileInfo(fileInx).deleted = paramFileInfo(fileInx).deletedShadow; wHide( paramFileW ); DoChangeNotification( CHANGE_PARAMS ); } static void ParamFilesChange( long changes ) { #ifdef LATER int fileInx; wIndex_t listInx; if ((changes&CHANGE_PARAMS) == 0 || paramFileW == NULL || !wWinIsVisible(paramFileW) ) return; wControlShow( (wControl_p)paramFileL, FALSE ); listInx = wListGetIndex(paramFileL); wListClear( paramFileL ); for ( fileInx = 0; fileInx < paramFileInfo_da.cnt; fileInx++ ) { if (paramFileInfo(fileInx).valid) { strcpy( message, ((!paramFileSel) && paramFileInfo(fileInx).contents)? paramFileInfo(fileInx).contents: paramFileInfo(fileInx).name ); wListAddValue( paramFileL, message, (paramFileInfo(fileInx).deleted)?mtbox_bm:chkbox_bm, (void*)fileInx ); } } wListSetIndex( paramFileL, listInx ); wControlShow( (wControl_p)paramFileL, TRUE ); #endif } static void ParamFileDlgUpdate( paramGroup_p pg, int inx, void * valueP ) { switch (inx) { case I_PRMFILLIST: UpdateParamFileButton( (wIndex_t)(long)wListGetItemContext(paramFileL,wListGetIndex(paramFileL)) ); break; case I_PRMFILTOGGLE: ParamFileLoadList(); break; } } #include "bitmaps/mtbox.xbm" #include "bitmaps/chkbox.xbm" static void DoParamFiles( void * junk ) { wIndex_t listInx; void * data; if (paramFileW == NULL) { const char * dir; dir = wPrefGetString( "file", "paramdir" ); if (dir != NULL) strcpy( curParamDir, dir ); else { // in case there is no preference setting, use the installation's param directory as default char *str; MakeFullpath(&str, libDir, PARAM_SUBDIR, NULL); strcpy( curParamDir, str ); free(str); } mtbox_bm = wIconCreateBitMap( mtbox_width, mtbox_height, mtbox_bits, drawColorBlack ); chkbox_bm = wIconCreateBitMap( chkbox_width, chkbox_height, chkbox_bits, drawColorBlack ); paramFileW = ParamCreateDialog( ¶mFilePG, MakeWindowTitle(_("Parameter Files")), _("Ok"), ParamFileOk, ParamFileCancel, TRUE, NULL, 0, ParamFileDlgUpdate ); paramFile_fs = wFilSelCreate( mainW, FS_LOAD, FS_MULTIPLEFILES, _("Load Parameters"), _("Parameter files|*.xtp"), LoadParamFile, NULL ); ParamFileLoadList(); } ParamLoadControls( ¶mFilePG ); ParamGroupRecord( ¶mFilePG ); if ((listInx = wListGetValues( paramFileL, NULL, 0, NULL, &data ))>=0) UpdateParamFileButton( (wIndex_t)(long)data ); ParamFileLoadList(); wShow( paramFileW ); } EXPORT addButtonCallBack_t ParamFilesInit( void ) { BOOL_T initted = FALSE; if (!initted) { ParamRegister( ¶mFilePG ); RegisterChangeNotification( ParamFilesChange ); initted = TRUE; } return &DoParamFiles; }