Hint added.
[AROS.git] / workbench / prefs / locale / page_language.c
blob883b516ab0bdd2d5c2678d5c075f4fef0b33c7da
1 /*
2 Copyright © 2003-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
8 #include <proto/alib.h>
9 #include <proto/codesets.h>
10 #include <proto/intuition.h>
11 #include <proto/utility.h>
12 #include <proto/muimaster.h>
14 #include <zune/customclasses.h>
15 #include <zune/prefseditor.h>
17 #include "locale.h"
18 #include "prefs.h"
19 #include "misc.h"
20 #include "registertab.h"
21 #include "page_language.h"
22 #include "languagelist.h"
24 /*** Instance Data **********************************************************/
26 struct Language_DATA
28 int nr_languages;
29 int nr_preferred;
31 Object *child;
32 Object *available;
33 Object *preferred;
34 Object *charset;
35 Object *cslist;
36 Object *cslistview;
37 Object *popup;
38 Object *clear;
39 Object *prefs;
41 char **strings_available;
42 char **strings_preferred;
43 STRPTR *strings_charsets;
45 char *langpreferred[10]; /* result array for MUIA_Language_Preferred */
48 struct MUI_CustomClass *Language_CLASS;
50 static struct Hook hook_available;
51 static struct Hook hook_preferred;
52 static struct Hook hook_clear;
54 /*** Helpers *****************************************************************/
56 STATIC VOID init_language_lists(struct Language_DATA *data)
59 struct LanguageEntry *entry;
60 LONG i = 0, p = 0, a = 0;
62 data->nr_languages = 0;
63 ForeachNode(&language_list, entry)
65 data->nr_languages++;
67 D(bug("[LocalePrefs-LanguageClass]: nr of languages: %d\n",data->nr_languages));
69 data->strings_available = AllocVec(sizeof(char *) * (data->nr_languages+1), MEMF_CLEAR);
70 data->strings_preferred = AllocVec(sizeof(char *) * (data->nr_languages+1), MEMF_CLEAR);
72 ForeachNode(&language_list, entry)
74 D(bug("[LocalePrefs-LanguageClass] language '%s' ('%s')\n", entry->lve.node.ln_Name, entry->lve.realname));
75 BOOL preferred = FALSE;
77 /* max 10 preferred langs, see prefs/locale.h */
78 for (i = 0; (i < 10) && (localeprefs.lp_PreferredLanguages[i][0]); i++)
80 if (Stricmp(localeprefs.lp_PreferredLanguages[i], entry->lve.realname) == 0)
82 D(bug("[LocalePrefs-LanguageClass] %s is preferred\n", entry->lve.realname));
83 preferred = TRUE;
84 break;
88 if(preferred)
89 data->strings_preferred[p++] = entry->lve.node.ln_Name;
90 else
91 data->strings_available[a++] = entry->lve.node.ln_Name;
95 data->strings_available[a] = NULL;
96 data->strings_preferred[p] = NULL;
99 /*** Hooks ******************************************************************
101 * hook_func_available
102 * handles double clicks on the available languages
104 * hook_func_preferred
105 * handles double clicks on the preferred languages
107 * hook_func_clear
108 * handles clearing of preferred languages
110 ****************************************************************************/
112 STATIC VOID func_move_to_selected(char* selstr, struct Language_DATA *data)
114 struct LanguageEntry *entry = NULL;
115 unsigned int i = 0;
116 char *test;
118 D(bug("[LocalePrefs-LanguageClass] func_move_to_selected('%s')\n", selstr));
120 if(selstr) {
121 ForeachNode(&language_list, entry)
123 if (Stricmp(selstr, entry->lve.realname) == 0)
125 DoMethod(data->preferred,
126 MUIM_List_InsertSingle, entry->lve.node.ln_Name,
127 MUIV_List_Insert_Bottom);
128 break;
133 /* we could use
134 * DoMethod(data->available,MUIM_List_Remove, MUIV_List_Remove_Active);
135 * of course, but I also want to be able to use that for
136 * the Set method.
139 if (entry)
141 GET(data->available, MUIA_List_Entries, &i);
142 while(i)
144 i--;
145 DoMethod(data->available, MUIM_List_GetEntry, i, &test);
146 if (Stricmp(entry->lve.node.ln_Name, test) == 0)
148 DoMethod(data->available, MUIM_List_Remove, i);
149 i = 0;
155 AROS_UFH2
157 void, hook_func_available,
158 AROS_UFHA(struct Hook *, hook, A0),
159 AROS_UFHA(APTR, obj, A2)
162 AROS_USERFUNC_INIT
164 struct Language_DATA *data = hook->h_Data;
165 struct LanguageEntry *entry;
167 char *selstr;
169 D(bug("[LocalePrefs-LanguageClass] hook_func_available\n"));
171 DoMethod(obj,MUIM_List_GetEntry,
172 MUIV_List_GetEntry_Active, &selstr);
174 ForeachNode(&language_list, entry)
176 if (Stricmp(selstr, entry->lve.node.ln_Name) == 0)
178 func_move_to_selected(entry->lve.realname, data);
179 break;
183 AROS_USERFUNC_EXIT
186 AROS_UFH2
188 void, hook_func_preferred,
189 AROS_UFHA(struct Hook *, hook, A0),
190 AROS_UFHA(APTR, obj, A2)
193 AROS_USERFUNC_INIT
195 struct Language_DATA *data= hook->h_Data;
196 char *selstr;
197 struct LanguageEntry *entry;
199 D(bug("[LocalePrefs-LanguageClass] hook_func_preferred\n"));
201 DoMethod(obj,MUIM_List_GetEntry,
202 MUIV_List_GetEntry_Active, &selstr);
204 if(selstr)
206 D(bug("move: %s\n",selstr));
208 ForeachNode(&language_list, entry)
210 if (Stricmp(selstr, entry->lve.node.ln_Name) == 0)
212 DoMethod(data->available,
213 MUIM_List_InsertSingle, entry->lve.node.ln_Name,
214 MUIV_List_Insert_Sorted);
217 DoMethod(obj, MUIM_List_Remove, MUIV_List_Remove_Active);
220 AROS_USERFUNC_EXIT
223 STATIC VOID func_clear(struct Language_DATA *data)
225 struct LanguageEntry *entry;
227 D(bug("[LocalePrefs-LanguageClass] func_clear\n"));
229 /* clear it */
230 DoMethod(data->preferred, MUIM_List_Clear);
232 /* add all old preferred languages again */
233 set(data->available, MUIA_List_Quiet, TRUE);
234 DoMethod(data->available, MUIM_List_Clear);
236 ForeachNode(&language_list, entry)
238 DoMethod(data->available,
239 MUIM_List_InsertSingle, entry->lve.node.ln_Name,
240 MUIV_List_Insert_Sorted);
243 set(data->available, MUIA_List_Quiet, FALSE);
246 AROS_UFH2(
247 void, hook_func_clear,
248 AROS_UFHA(struct Hook *, hook, A0),
249 AROS_UFHA(APTR *, obj, A2)
252 AROS_USERFUNC_INIT
254 struct Language_DATA *data = hook->h_Data;
256 func_clear(data);
257 SET(data->prefs, MUIA_PrefsEditor_Changed, TRUE);
259 AROS_USERFUNC_EXIT
262 AROS_UFH3
264 void, charset_popup_to_string,
265 AROS_UFHA(struct Hook*, hook, A0),
266 AROS_UFHA(Object *, list, A2),
267 AROS_UFHA(Object *, string, A1)
270 AROS_USERFUNC_INIT
272 STRPTR listentry;
273 STRPTR oldentry;
275 GetAttr(MUIA_Text_Contents, string, (IPTR *)&oldentry);
276 DoMethod(list, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, (IPTR)&listentry);
277 if (Stricmp(listentry, oldentry))
279 SetAttrs(string, MUIA_Text_Contents, listentry, TAG_DONE);
280 SetAttrs(hook->h_Data, MUIA_PrefsEditor_Changed, TRUE, TAG_DONE);
283 AROS_USERFUNC_EXIT
286 AROS_UFH3
288 ULONG, charset_string_to_popup,
289 AROS_UFHA(struct Hook*, hook, A0),
290 AROS_UFHA(Object *, list, A2),
291 AROS_UFHA(Object *, str, A1)
294 AROS_USERFUNC_INIT
296 STRPTR strtext, listentry;
297 LONG index;
299 GetAttr(MUIA_Text_Contents, str, (IPTR *)&strtext);
301 for(index = 0; ; index++)
303 DoMethod(list, MUIM_List_GetEntry, index, (IPTR)&listentry);
305 if (!listentry)
307 SET(list, MUIA_List_Active, MUIV_List_Active_Off);
308 break;
311 if (Stricmp(strtext, listentry) == 0)
313 SET(list, MUIA_List_Active, index);
314 break;
318 return TRUE;
320 AROS_USERFUNC_EXIT
323 static struct Hook charset_popup_to_string_hook =
325 {NULL, NULL},
326 (HOOKFUNC)AROS_ASMSYMNAME(charset_popup_to_string),
327 NULL,
328 NULL
331 static struct Hook charset_string_to_popup_hook =
333 {NULL, NULL},
334 (HOOKFUNC)AROS_ASMSYMNAME(charset_string_to_popup),
335 NULL,
336 NULL
339 /*** Methods ****************************************************************
343 static void free_strings(struct Language_DATA *data)
345 if (data->strings_charsets)
347 CodesetsFreeA(data->strings_charsets, NULL);
348 data->strings_charsets = NULL;
350 if(data->strings_available)
352 FreeVec(data->strings_available);
353 data->strings_available = NULL;
356 if(data->strings_preferred)
358 FreeVec(data->strings_preferred);
359 data->strings_preferred = NULL;
364 static Object *handle_New_error(Object *obj, struct IClass *cl, char *error)
366 struct Language_DATA *data;
368 ShowMessage(error);
369 D(bug("[LocalePrefs-LanguageClass] %s\n"));
371 if(!obj)
372 return NULL;
374 data = INST_DATA(cl, obj);
376 if(data->clear)
378 DisposeObject(data->clear);
379 data->clear=NULL;
382 if(data->available)
384 DisposeObject(data->available);
385 data->available=NULL;
388 if(data->preferred)
390 DisposeObject(data->preferred);
391 data->preferred = NULL;
394 if(data->child)
396 DisposeObject(data->child);
397 data->child = NULL;
400 if (data->charset) {
401 DisposeObject(data->charset);
402 data->charset = NULL;
405 if (data->cslist) {
406 DisposeObject(data->cslist);
407 data->cslist = NULL;
410 if (data->cslistview) {
411 DisposeObject(data->cslistview);
412 data->cslist = NULL;
415 if (data->popup) {
416 DisposeObject(data->popup);
417 data->popup = NULL;
420 free_strings(data);
422 CoerceMethod(cl, obj, OM_DISPOSE);
423 return NULL;
426 Object *Language__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
428 struct Language_DATA *data;
429 struct TagItem *tstate, *tag;
430 struct Object *avail_list, *pref_list;
432 D(bug("[LocalePrefs-LanguageClass] Language Class New\n"));
435 * we create self first and then create the child,
436 * so we have self->data available already
439 obj = (Object *) DoSuperNewTags
441 cl, obj, NULL,
442 TAG_DONE
445 if (obj == NULL)
447 return handle_New_error(obj, cl, "ERROR: Unable to create object!\n");
450 data = INST_DATA(cl, obj);
452 tstate=((struct opSet *)msg)->ops_AttrList;
453 while ((tag = (struct TagItem *) NextTagItem((APTR) &tstate)))
455 switch (tag->ti_Tag)
457 case MUIA_UserData:
458 data->prefs = (Object *) tag->ti_Data;
459 break;
463 if(!data->prefs)
464 return handle_New_error(obj, cl, "ERROR: MA_PrefsObject not supplied!\n");
466 init_language_lists(data);
467 data->strings_charsets = CodesetsSupportedA(NULL);
469 data->clear = MUI_MakeObject(MUIO_Button, __(MSG_GAD_CLEAR_LANGUAGES));
471 data->available = ListviewObject, MUIA_Listview_List,
472 avail_list = NewObject(Languagelist_CLASS->mcc_Class, 0,
473 InputListFrame,
474 MUIA_Draggable, TRUE,
475 MUIA_List_SourceArray, data->strings_available,
476 TAG_DONE),
477 End;
479 data->preferred = ListviewObject, MUIA_Listview_List,
480 pref_list = NewObject(Languagelist_CLASS->mcc_Class, 0,
481 InputListFrame,
482 MUIA_Draggable, TRUE,
483 MUIA_List_SourceArray, data->strings_preferred,
484 TAG_DONE),
485 End;
487 set(pref_list, MUIA_UserData, avail_list);
488 set(avail_list, MUIA_UserData, pref_list);
490 data->charset = TextObject,
491 TextFrame,
492 MUIA_Background, MUII_TextBack,
493 End;
495 data->cslist = ListObject,
496 MUIA_Frame, MUIV_Frame_InputList,
497 MUIA_Background, MUII_ListBack,
498 MUIA_List_AutoVisible, TRUE,
499 MUIA_List_SourceArray, data->strings_charsets,
500 End;
502 data->cslistview = ListviewObject,
503 MUIA_Listview_List, data->cslist,
504 End;
506 charset_popup_to_string_hook.h_Data = data->prefs;
508 data->popup = PopobjectObject,
509 MUIA_Popobject_Object, data->cslistview,
510 MUIA_Popobject_StrObjHook, &charset_string_to_popup_hook,
511 MUIA_Popobject_ObjStrHook, &charset_popup_to_string_hook,
512 MUIA_Popstring_Button, PopButton(MUII_PopUp),
513 MUIA_Popstring_String, data->charset,
514 End;
516 if(!data->clear || !data->available || !data->preferred || !data->charset || !data->cslist ||
517 !data->cslistview || !data->popup)
518 return handle_New_error(obj,cl,"ERROR: MakeObject failed\n");
520 DoMethod(data->cslist, MUIM_List_Sort);
521 DoMethod(data->cslist, MUIM_List_InsertSingle, _(MSG_NOT_SPECIFIED), MUIV_List_Insert_Top);
523 data->child = VGroup,
524 Child, HGroup,
525 Child, VGroup, /* Available Languages */
526 Child, CLabel1(_(MSG_GAD_AVAIL_LANGUAGES)),
527 Child, data->available,
528 End,
529 Child, VGroup, /* Preferred Languages */
530 Child, CLabel1(_(MSG_GAD_PREF_LANGUAGES)),
531 Child, data->preferred,
532 End,
533 End,
534 Child, data->clear,
535 Child, HGroup,
536 Child, CLabel1(_(MSG_CHARACTER_SET)),
537 Child, data->popup,
538 End,
539 End;
541 if(!data->child)
542 return handle_New_error(obj, cl, "ERROR: create child failed\n");
544 /* add to self */
545 DoMethod(obj, OM_ADDMEMBER, data->child);
547 /* setup hooks */
548 DoMethod(data->cslistview, MUIM_Notify, MUIA_Listview_DoubleClick, TRUE, data->popup, 2, MUIM_Popstring_Close, TRUE);
550 /* move hooks */
551 hook_available.h_Entry = (HOOKFUNC) hook_func_available;
552 hook_available.h_Data = data ;
553 DoMethod
555 data->available, MUIM_Notify, MUIA_Listview_DoubleClick, MUIV_EveryTime, data->available,
556 2, MUIM_CallHook, (IPTR) &hook_available
559 hook_preferred.h_Entry = (HOOKFUNC) hook_func_preferred;
560 hook_preferred.h_Data = data ;
561 DoMethod
563 data->preferred, MUIM_Notify, MUIA_Listview_DoubleClick, MUIV_EveryTime, data->preferred,
564 2, MUIM_CallHook, (IPTR) &hook_preferred
567 /* clear hook */
568 hook_clear.h_Entry = (HOOKFUNC) hook_func_clear;
569 hook_clear.h_Data = data ;
570 DoMethod
572 data->clear, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, data->preferred,
573 2, MUIM_CallHook, (IPTR) &hook_clear
576 /* changed hooks */
577 DoMethod
579 pref_list, MUIM_Notify, MUIA_List_Entries, MUIV_EveryTime,
580 (IPTR) data->prefs, 3, MUIM_Set, MUIA_PrefsEditor_Changed, TRUE
583 return obj;
586 /*** Get ******************************************************************/
588 static IPTR Language__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
590 struct Language_DATA *data = INST_DATA(cl, obj);
591 IPTR rc;
592 IPTR i;
594 switch (msg->opg_AttrID)
596 case MUIA_Language_Preferred: /* return array of preferred language strings */
597 memset(data->langpreferred, 0, sizeof(data->langpreferred));
598 for (i = 0; i < 10; i++)
600 struct LanguageEntry *entry;
601 char *langNative = NULL;
603 DoMethod(data->preferred, MUIM_List_GetEntry, i, &langNative);
604 D(bug("[LocalePrefs-LanguageClass] Get: MUIA_Language_Preferred %02d = '%s'\n", i, langNative));
605 ForeachNode(&language_list, entry)
607 if(Stricmp(langNative, entry->lve.node.ln_Name) == 0)
609 data->langpreferred[i] = entry->lve.realname;
610 D(bug("[LocalePrefs-LanguageClass] Get: BaseName = '%s'\n", data->langpreferred[i]));
611 break;
615 rc = (IPTR) data->langpreferred;
616 break;
617 case MUIA_Language_Characterset:
618 GetAttr(MUIA_List_Active, data->cslist, (IPTR *)&i);
619 D(bug("[LocalePrefs-LanguageClass] Get: MUIA_Language_Characterset = %d\n", i));
620 if ((i == 0) || (i == MUIV_List_Active_Off))
621 *msg->opg_Storage = 0;
622 else
623 GetAttr(MUIA_Text_Contents, data->charset, msg->opg_Storage);
624 return TRUE;
625 default:
626 return DoSuperMethodA(cl, obj, (Msg)msg);
629 *msg->opg_Storage = rc;
630 return TRUE;
633 /*** Set ******************************************************************/
634 static IPTR Language__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
636 struct Language_DATA *data = INST_DATA(cl, obj);
637 struct TagItem *tstate, *tag;
638 ULONG update;
639 ULONG i;
641 tstate = msg->ops_AttrList;
642 update = FALSE;
644 while ((tag = (struct TagItem *) NextTagItem((APTR) &tstate)))
646 switch (tag->ti_Tag)
648 case MUIA_Language_Preferred:
649 /* clear preferred */
650 func_clear(data);
651 for (i = 0; i < 10; i++)
653 if(localeprefs.lp_PreferredLanguages[i][0] != '\0')
655 D(bug("[LocalePrefs-LanguageClass] OM_SET: MUIA_Language_Preferred %d = '%s'\n", i, localeprefs.lp_PreferredLanguages[i]));
656 func_move_to_selected(localeprefs.lp_PreferredLanguages[i], data);
660 update = TRUE;
661 break;
662 case MUIA_Language_Characterset:
664 char *charset = (char *)tag->ti_Data;
666 D(bug("[LocalePrefs-LanguageClass] OM_SET: MUIA_Language_Characterset = '%s'\n", i, charset));
668 if (!charset || !*charset)
669 DoMethod(data->cslist, MUIM_List_GetEntry, 0, (IPTR *)&charset);
670 SetAttrs(data->charset, MUIA_Text_Contents, charset, TAG_DONE);
672 break;
674 default:
675 return DoSuperMethodA(cl, obj, (Msg)msg);
679 if(update)
681 MUI_Redraw(obj, MADF_DRAWOBJECT);
684 return TRUE;
687 static IPTR Language__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
689 struct Language_DATA *data = INST_DATA(cl, obj);
691 D(bug("[LocalePrefs-LanguageClass] OM_DISPOSE()\n"));
693 free_strings(data);
695 return DoSuperMethodA(cl, obj, msg);
698 /*** Setup ******************************************************************/
699 ZUNE_CUSTOMCLASS_4
701 Language, NULL, MUIC_Group, NULL,
702 OM_NEW, struct opSet *,
703 OM_SET, struct opSet *,
704 OM_GET, struct opGet *,
705 OM_DISPOSE, Msg