PrefsObject

This forum is for general developer support questions.
User avatar
jaokim
Beta Tester
Beta Tester
Posts: 90
Joined: Sat Jun 18, 2011 12:41 am

Re: PrefsObject

Post by jaokim »

I don't have much application library knowledge, so I don't know which six types there are. But, if I'm allowed to elaborate, I'm thinking one might want to support more types in the future. Therefore I think that an attribute would be better suited... Although, on the other hand, we'd get a less "typed" and uncontrolled structure.
My thought was that one would perhaps want, as an application programmer, to store application specific "blobs", with some sort of XML CDATA thingie, especially wen porting software. I'm imagining that the ported program has its own binary format, which we then could save using minimal Amiga application specific code, but still take advantage of Amiga specific functionality.

Like I said, I don't have any deep insight in exactly what application library supports for the prefs objects, so I might be proposing unsuitable stuff.

But either way, I'd prefer a format where the data type is an attribute, and not a static tag.
User avatar
trixie
Posts: 409
Joined: Thu Jun 30, 2011 2:54 pm
Location: Czech Republic

Re: PrefsObject

Post by trixie »

@jaokim
I don't have much application library knowledge, so I don't know which six types there are.
See here:
http://wiki.amigaos.net/wiki/PrefsObjects#Object_Types
The Rear Window blog

AmigaOne X5000 @ 2GHz / 4GB RAM / Radeon RX 560 / ESI Juli@ / AmigaOS 4.1 Final Edition
SAM440ep-flex @ 667MHz / 1GB RAM / Radeon 9250 / AmigaOS 4.1 Final Edition
User avatar
mritter0
Posts: 214
Joined: Mon Aug 25, 2014 9:41 pm
Location: Bettendorf, IA, USA

Re: PrefsObject

Post by mritter0 »

I haven't heard back from my PM to Trixie on getting some example code. Does anyone have an example to get me started?
Workbench Explorer - A better way to browse drawers
User avatar
javierdlr
Beta Tester
Beta Tester
Posts: 389
Joined: Sun Jun 19, 2011 10:13 pm
Location: Donostia (GUIPUZCOA) - Spain
Contact:

Re: PrefsObject

Post by javierdlr »

Not sure if its what you want, but I use an XML file to store Mixer.docky prefs (SoundVolume and Mute), here it's a snnipet:

XML looks like this:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE pobjects PUBLIC "-//Amiga Inc.//DTD POBJECTS 1.0//EN" "http://www.amiga.com/DTDs/PrefsObjects-1.0.dtd">
<pobjects version="1.0">
<dict>
	<key>Volume-Mute</key>
	<array>
		<integer>100</integer>
		<bool>FALSE</bool>
		<integer>100</integer>
		<bool>FALSE</bool>
		<integer>100</integer>
		<bool>FALSE</bool>
		<integer>100</integer>
		<bool>FALSE</bool>
	</array>
</dict>
</pobjects>
And source for reading such xml:

Code: Select all

extern uint32 sliderVal[SC_MAX];
extern BOOL buttonMute[SC_MAX];
...
void ReadXMLcfg(char *filename, struct DockyData *dd)
{
 PrefsObject *dict;
 uint32 err = 0;

 dict = IPrefsObjects->PrefsDictionary(NULL, NULL, ALPO_Alloc,0, TAG_DONE);

 err = IPrefsObjects->ReadPrefs(dict, READPREFS_FileName,(ULONG)filename, TAG_DONE);
 if(err!=0 && err!=ALPOEF_FILEERROR)
  DoMessage("Warning: Can't read/load XML settings.", REQIMAGE_WARNING, dd);
 else
 {
  PrefsObject *soundcard = IPrefsObjects->DictGetObjectForKey(dict, "Volume-Mute");
  if(soundcard)
  {
   int32 count;
   struct ALPOObjIndex oi;

   IPrefsObjects->PrefsArray(soundcard, NULL, ALPOARR_GetCount,&count, TAG_DONE);
   for(oi.index = 0; oi.index < count; oi.index++)
   {
    IPrefsObjects->PrefsArray(soundcard, NULL, ALPOARR_GetObjAtIndex,&oi, TAG_DONE);
    if(oi.obj)
    {
     int32 vol;
     BOOL mut;
//IDOS->Printf("[XML]object %2ld: ",oi.index);
     IPrefsObjects->PrefsNumber(oi.obj, &err, ALPONUM_GetLong,&vol, TAG_DONE);
     if(!err)
      sliderVal[oi.index>>1] = vol;

     oi.index++;
     IPrefsObjects->PrefsArray(soundcard, NULL, ALPOARR_GetObjAtIndex,&oi, TAG_DONE);
     IPrefsObjects->PrefsNumber(oi.obj, &err, ALPONUM_GetBool,&mut, TAG_DONE);
     if(!err)
      buttonMute[oi.index>>1] = mut;
//IDOS->Printf("[R:%ld]sliderVal=%ld buttonMute=%ld\n",oi.index>>1,sliderVal[oi.index>>1],buttonMute[oi.index>>1]);
    }
   }
  } // END soundcard
 }
 IPrefsObjects->PrefsDictionary(dict, NULL, ALPO_Release,0, TAG_DONE);
}
(full sources are Mixer archive(openamiga, os4depot)
User avatar
trixie
Posts: 409
Joined: Thu Jun 30, 2011 2:54 pm
Location: Czech Republic

Re: PrefsObject

Post by trixie »

@mritter0
mritter0 wrote:I haven't heard back from my PM to Trixie on getting some example code. Does anyone have an example to get me started?
Sorry I forgot to check my PM. Was the current example in the wiki not enough? The easiest way is really to register your app with REGAPP_LoadPrefs, TRUE, get the prefs dictionary object via GetApplicationAttrs(), and then manipulate the settings via the respective getter functions - DictGetBoolForKey(), DictGetIntegerForKey() etc. Values are set using DictSetObjectForKey(). Saving to the XML file is done through WritePrefs().

What Javier is suggesting is an alternative: you allocate your own prefs dictionary through PrefsDictionary() and then ReadPrefs() into it. The rest is pretty much the same.

I'm still working on improving the wiki page but it takes time, unfortunately :(

EDIT: This is what I use in WordNet to load/save settings:

Code: Select all

int load_settings(uint32 appID)
{
 PrefsObject *prefsObj = NULL;

 // Obtain the prefs dictionary.
 IApplication->GetApplicationAttrs(appID, APPATTR_MainPrefsDict, &prefsObj, TAG_DONE);

 if ( prefsObj )
  {
   // Load prefs (or use defaults).
   settings.width      = IPrefsObjects->DictGetIntegerForKey(prefsObj, PREFSKEY_WINWIDTH, WINWIDTH_DEFAULT);
   settings.height     = IPrefsObjects->DictGetIntegerForKey(prefsObj, PREFSKEY_WINHEIGHT, WINHEIGHT_DEFAULT);
   settings.histlen    = IPrefsObjects->DictGetIntegerForKey(prefsObj, PREFSKEY_HISTLEN, HISTLEN_DEFAULT);
   settings.lingmode   = IPrefsObjects->DictGetBoolForKey(prefsObj, PREFSKEY_LINGMODE, LINGMODE_DEFAULT);
   settings.fulldesc   = IPrefsObjects->DictGetBoolForKey(prefsObj, PREFSKEY_FULLDESC, FULLDESC_DEFAULT);
   settings.unfold     = IPrefsObjects->DictGetBoolForKey(prefsObj, PREFSKEY_UNFOLD, UNFOLD_DEFAULT);
   settings.dclick     = IPrefsObjects->DictGetBoolForKey(prefsObj, PREFSKEY_DCLICK, DCLICK_DEFAULT);
   settings.showfreq   = IPrefsObjects->DictGetBoolForKey(prefsObj, PREFSKEY_SHOWFREQ, SHOWFREQ_DEFAULT);
   settings.escquit    = IPrefsObjects->DictGetBoolForKey(prefsObj, PREFSKEY_ESCQUIT, ESCQUIT_DEFAULT);
   settings.helptips   = IPrefsObjects->DictGetBoolForKey(prefsObj, PREFSKEY_HELPTIPS, HELPTIPS_DEFAULT);

   return RETURN_OK;
  }

 else return RETURN_FAIL;
}



int save_settings(uint32 appID)
{
 PrefsObject *prefsObj    = NULL;
 int          retValue    = RETURN_FAIL;

 // Obtain the prefs dictionary.
 IApplication->GetApplicationAttrs(appID, APPATTR_MainPrefsDict, &prefsObj, TAG_DONE);

 if ( prefsObj )
  {
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetLong, settings.width,
         TAG_DONE), PREFSKEY_WINWIDTH);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetLong, settings.height,
         TAG_DONE), PREFSKEY_WINHEIGHT);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetLong, settings.histlen,
         TAG_DONE), PREFSKEY_HISTLEN);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetBool, settings.lingmode,
         TAG_DONE), PREFSKEY_LINGMODE);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetBool, settings.fulldesc,
         TAG_DONE), PREFSKEY_FULLDESC);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetBool, settings.unfold,
         TAG_DONE), PREFSKEY_UNFOLD);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetBool, settings.dclick,
         TAG_DONE), PREFSKEY_DCLICK);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetBool, settings.showfreq,
         TAG_DONE), PREFSKEY_SHOWFREQ);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetBool, settings.escquit,
         TAG_DONE), PREFSKEY_ESCQUIT);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsNumber(NULL, NULL,
         ALPONUM_AllocSetBool, settings.helptips,
         TAG_DONE), PREFSKEY_HELPTIPS);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsString(NULL, NULL,
         ALPOSTR_AllocSetString, settings.homepage,
         TAG_DONE), PREFSKEY_HOMEPAGE);
   IPrefsObjects->DictSetObjectForKey(prefsObj, IPrefsObjects->PrefsString(NULL, NULL,
         ALPOSTR_AllocSetString, settings.docfile,
         TAG_DONE), PREFSKEY_DOCFILE);

      // Write preferences.
   if ( IPrefsObjects->WritePrefs(prefsObj,
         WRITEPREFS_AppID, appID,
         WRITEPREFS_WriteENVARC, TRUE,
         TAG_DONE) == 0 ) retValue = RETURN_OK;
  }

 return retValue;
}
The Rear Window blog

AmigaOne X5000 @ 2GHz / 4GB RAM / Radeon RX 560 / ESI Juli@ / AmigaOS 4.1 Final Edition
SAM440ep-flex @ 667MHz / 1GB RAM / Radeon 9250 / AmigaOS 4.1 Final Edition
User avatar
mritter0
Posts: 214
Joined: Mon Aug 25, 2014 9:41 pm
Location: Bettendorf, IA, USA

Re: PrefsObject

Post by mritter0 »

Thanks guys. The loading code on the wiki doesn't do me any good if I can't save my prefs first. ;)

I would still like to see a fully loaded example that saves/loads a complicated prefs file. As in, Screen settings grouped, Window settings grouped, etc. Not just a straight list of items.

This will get me started.
Workbench Explorer - A better way to browse drawers
User avatar
mritter0
Posts: 214
Joined: Mon Aug 25, 2014 9:41 pm
Location: Bettendorf, IA, USA

Re: PrefsObject

Post by mritter0 »

Now I am going to get nit-picky:

To be consistent across applications, what is the prefs filename extension? Xxxx.prefs or Xxxxx.xml

I already see a mix of the two. I like .xml. Pick one, Style Guide maintainer. :P
Workbench Explorer - A better way to browse drawers
User avatar
broadblues
AmigaOS Core Developer
AmigaOS Core Developer
Posts: 600
Joined: Sat Jun 18, 2011 2:40 am
Location: Portsmouth, UK
Contact:

Re: PrefsObject

Post by broadblues »

#?.prefs ofcourse you don't call older prefs formats in IFF #?.iff

But it doesn't matter really.
User avatar
trixie
Posts: 409
Joined: Thu Jun 30, 2011 2:54 pm
Location: Czech Republic

Re: PrefsObject

Post by trixie »

@mritter0
mritter0 wrote:To be consistent across applications, what is the prefs filename extension? Xxxx.prefs or Xxxxx.xml
The Application Library uses .xml by default.
I would still like to see a fully loaded example that saves/loads a complicated prefs file. As in, Screen settings grouped, Window settings grouped, etc. Not just a straight list of items. This will get me started.
This is why it's important to specify what exactly you are after. If you say things like "to get me started", it appears that you need to learn the basics. So you've got what you've got: examples describing the basics :-) Anyway, I'll try to dig out something more complex for you.
The Rear Window blog

AmigaOne X5000 @ 2GHz / 4GB RAM / Radeon RX 560 / ESI Juli@ / AmigaOS 4.1 Final Edition
SAM440ep-flex @ 667MHz / 1GB RAM / Radeon 9250 / AmigaOS 4.1 Final Edition
User avatar
mritter0
Posts: 214
Joined: Mon Aug 25, 2014 9:41 pm
Location: Bettendorf, IA, USA

Re: PrefsObject

Post by mritter0 »

I am leaning more towards what BroadBlues suggested. But what salass00 suggested is just as good. But I would like to see some other tags added:

Code: Select all

<pobjects version="2.0">
<dict>
	<Application>MyProgram</Application>
	<Version>1.0</Version>
	<!-- some other tags -->

	<!-- this is more compact -->	
	<integer key="WindowX">79</integer>
	<integer key="WindowY">33</integer>
	<integer key="WindowWidth">1066</integer>
	<integer key="WindowHeight">631</integer>
	<string key="SomeText">Text message</string>
	<bool key="Verify">TRUE</bool>
	
	
	<!-- Be able to add comment lines and blank lines -->	
	<item key="Window">
		<array>
			<item key="WindowX">
				<integer>79</integer>
			</item>
			<item key="WindowY">
				<integer>33</integer>
			</item>
			<item key="WindowWidth">
				<integer>1066</integer>
			</item>
			<item key="WindowHeight">
				<integer>631</integer>
			</item>
		</array>
	</item>
</dict>
</pobjects>
Name and version, comment lines, and blank lines to group better and for easier reading.

For an array, you loop through the count of items. Not good. Should "search" by name like do for individual items. That way if items are added/removed with new version of program it won't affect anything. Then can also be added/removed in any order/place. At least that is what the Mixer code shows.

Then can do this:

Code: Select all

PrefsObject *MainDict, *WindowArray;

Name=IPrefsObjects->DictGetIntegerForKey(MainDict,"Application","");
Version=IPrefsObjects->DictGetIntegerForKey(MainDict,"Version","");

WindowArray=IPrefsObjects->DictGetIntegerForKey(MainDict,"Window",NULL);  // find the Window array
if (WindowArray)
{
    Prefs->WindowX=IPrefsObjects->DictGetIntegerForKey(WindowArray,"WindowX",10);
}
else
{
    // fill in default values
}
.....
Prefs->Verify=IPrefsObjects->DictGetIntegerForKey(MainDict,"Verify",TRUE);
.....
Workbench Explorer - A better way to browse drawers
Post Reply