• Main Page
  • Classes
  • Files

contentLister/src/control.c

Go to the documentation of this file.
00001 /*
00002  * This file is part of contentLister.
00003  *
00004  * contentLister is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation, either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * contentLister is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 
00026 /*
00027  * contentLister - A GTK based content lister (read only) application on
00028  * the eReader platform 
00029  * Copyright (C) 2005-2008 iRex Technologies B.V. 
00030  * All rights reserved.
00031  */
00032 
00033 // config.h is generated based on the directives placed in the
00034 // configure.ac 
00035 // file and user input supplied to the configure script
00036 
00037 #define _GNU_SOURCE
00038 
00039 #include <config.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <strings.h>
00044 #include <fcntl.h>
00045 #include <errno.h>
00046 #include <sys/types.h>
00047 #include <sys/wait.h>
00048 #include <sys/ioctl.h>
00049 #include <sys/param.h>
00050 #include <sys/stat.h>
00051 
00052 #include <gtk/gtk.h>
00053 #include <gdk/gdkkeysyms.h>
00054 
00055 #include <liberdm/display.h>
00056 #include <liberdm/connectionMgrConstants.h>
00057 #include <liberregxml/erregapi.h>
00058 #include <libergtk/ergtk.h>
00059 #include <liberipc/eripc.h>
00060 #include <liberipc/eripctoolbar.h>
00061 #include <libermanifest/ermanifest.h>
00062 
00063 #include "contentListerLog.h"
00064 #include "erConnect.h"
00065 #include "erMSDisk.h"
00066 #include "system.h"
00067 #include "gtkPincodeScreen.h"
00068 #include "control.h"
00069 #include "control_share.h"
00070 #include "programManager.h"
00071 #include "displayUpdate.h"
00072 #include "viewer.h"
00073 #include "cursor.h"
00074 #include "gtkErrorScreen.h"
00075 #include "button.h"
00076 #include "metadataStoreManager.h"
00077 #include "icons.h"
00078 #include "pagebar.h"
00079 #include "history.h"
00080 #include "erbusy.h"
00081 #include "languages.h"
00082 #include "programManager.h"
00083 #include "regValue.h"
00084 #include "toolbar.h"
00085 #include "powerManager.h"
00086 #include "system.h"
00087 #include "gtkMetadataWnd.h"
00088 #include "gtkPincodeScreen.h"
00089 #include "pincodeIdleTime.h"
00090 #include "gtkSearchWnd.h"
00091 #include "gtkSortWnd.h"
00092 #include "gtkDistListWnd.h"
00093 #include "timedids.h"
00094 
00095 // local vars
00096 static listerState_t    g_listerState = STATE_NORMAL;
00097 static ContentLister*   gContentLister = NULL;
00098 static ctrlErrorType_e  g_errorTypeDisplayed = ctrlNoError;
00099 static gboolean         g_shutdownPending = FALSE;
00100 static gchar            restoreUaOnTop[UAID_MAX_SIZE] = CONTENTLISTER_UAID;
00101 static connectStruct_t  connectStruct;
00102 static gboolean         g_background_connect_enable = FALSE;
00103 static gboolean         g_new_content_received = FALSE;
00104 static gboolean         g_new_content_acknowledged = FALSE;
00105 static guint            g_idle_check_battery_id = 0;
00106 
00107 // pending actions on toolbar_synchronise event
00108 typedef void (*on_tbsync_action_t) (void);
00109 static on_tbsync_action_t on_toolbar_sync_actions[] = { NULL, NULL };
00110 
00111 // data for listitem select timer
00112 typedef void on_item_selected_t(const int* index_tbl, ContentLister* theContentLister);
00113 static struct
00114 {
00115     int                 iconID;           // toolbar icon
00116     gboolean            confirm_with_icon;// confirm selection by clicking icon again?
00117     guint               ticks;            // for timer
00118     guint               timerID;          // for timer
00119     gboolean            active;           // is selection mode active?
00120     gboolean            icon_clicked;     // is selected icon clicked again?
00121     gboolean            item_selected[MAX_ITEMS_ON_ONE_PAGE];
00122     on_item_selected_t* on_item_selected; // callback on item selected
00123 } g_select = { ICON_ID_NOTUSED, FALSE, 0, 0, FALSE, FALSE, {}, NULL };
00124 
00125 // for meta data editor
00126 static struct
00127 {
00128     clDisplayItem_t*    item;           // current selected item
00129 } g_md_editor_mgr;
00130 
00131 // internally used functions
00132 static void             ctrl_init_screen_layout(GtkWidget * topLevelWindow, ContentLister * theContentLister);
00133 static void             ctrl_display_item_view(ContentLister * theContentLister);
00134 static int              ctrl_scan_content(ContentLister * theContentLister, ctrlScanType_e scanType, char *folder);
00135 static void             ctrl_get_content_name(st_ContentType_e theType, char *name);
00136 static int              ctrl_goto_item(const gchar* szFilename);
00137 static gboolean         ctrl_start_viewer(st_ContentType_e theType, clDisplayItem_t * theItem, char *location);
00138 static void             ctrl_start_application(gchar* szExtID, gchar* options);
00139 static void             ctrl_select_stop(gboolean restore_toolbar);
00140 static gboolean         ctrl_file_exist(const char *pathName);
00141 static gboolean         ctrl_check_extension(const char *extension);
00142 static gboolean         ctrl_create_manifest(clDisplayItem_t * theItem, const char *dir, const char *name);
00143 static const char*      ctrl_get_current_location(ContentLister * theContentLister);
00144 static gboolean         ctrl_current_location_is_outbox(void);
00145 static void             ctrl_background_connect_timeout_start_withinterval(gboolean read_settings, gboolean immediate, gint interval);
00146 static gboolean         ctrl_show_search_wnd(gpointer data);
00147 static void             ctrl_show_sort_wnd_trigger(void);
00148 static gboolean         ctrl_show_sort_wnd(gpointer data);
00149 static void             ctrl_hide_sort_wnd(gboolean bSort);
00150 static void             ctrl_on_sort_clicked(int iconState);
00151 static void             ctrl_sort_current(void);
00152 static gint             ctrl_save_sort_settings(void);
00153 static void             ctrl_sort_wnd_setting_init(void);
00154 
00155 static void             ctrl_add_on_toolbar_sync_action(on_tbsync_action_t action);
00156 static void             ctrl_show_keyboard();
00157 static void             ctrl_hide_keyboard(int iconState);
00158 static void             ctrl_select_listitem(int iconID, gboolean confirm_with_icon, on_item_selected_t* callback_on_selected);
00159 static void             ctrl_listItem_edit(const int* index_tbl, ContentLister* theContentLister);
00160 static void             ctrl_metadata_editor_close(gboolean bSave);
00161 static void             ctrl_listItem_delete(const int* index_tbl, ContentLister* theContentLister);
00162 static gboolean         ctrl_not_create_manifest(const char *path);
00163 
00164 static gboolean         ctrl_current_location_is_mobipocket(void);
00165 static gboolean         ctrl_current_location_is_empty(void);
00166 
00167 // callbacks 
00168 static gboolean hook_screen_refresh_typing(GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data);
00169 static guint    ctrl_listerArea_keypress(GtkWidget * widget, GdkEventKey * event, ContentLister * theContentLister);
00170 static gboolean ctrl_main_window_expose_event(GtkWidget * widget, GdkEventExpose * event, ContentLister * theContentLister);
00171 static void     ctrl_main_window_realize_event(GtkWidget * widget, ContentLister * theContentLister);
00172 static guint    ctrl_errorScreen_buttonpress(GtkWidget * widget, GdkEventButton * event, ContentLister * theContentLister);
00173 static gboolean ctrl_on_idle_show_keyboard(gpointer data);
00174 static gboolean ctrl_on_idle_hide_keyboard(gpointer data);
00175 static gboolean on_idle_connect_start(gpointer user_data);
00176 static void     ctrl_on_search_clicked(int iconState);
00177 
00178 // for pincode
00179 static void ctrl_pincode_idle_time_callback();
00180 static void ctrl_pincode_set_toolbar_icon();
00181 
00182 static void ctrl_start_setup();
00183 static void ctrl_lock_screen(void);
00184 
00185 // user customized start-up behaviour
00186 static gboolean ctrl_on_idle_select_language(gpointer data);
00187 static void ctrl_start_up_behaviour(void);
00188 static gboolean ctrl_open_quick_start_guide(const char *documentPath);
00189 static void ctrl_display_reference_materials(void);
00190 static gboolean ctrl_open_last_read_document(void);
00191 static void ctrl_display_recent_documents();
00192 static gboolean startup_idle_handler(gpointer data);
00193 static gboolean startup_idle_display(gpointer data);
00194 
00195 ContentLister *ctrlInit(GtkWidget * topLevelWindow)
00196 {
00197     ContentLister *theContentLister = NULL;
00198     guint         signal_id;
00199 
00200     // create one theContentLister struct and fill it with zeros
00201     theContentLister = g_new0(ContentLister, 1);
00202     theContentLister->topLevelWindow = topLevelWindow;
00203     gContentLister = theContentLister;
00204 
00205     // init the connect fsm thread
00206     erConnectInit(&connectStruct);
00207 
00208     // init the msdisk application
00209     erMSDiskInit();
00210 
00211     // load the frequently used icons
00212     icons_init();
00213 
00214     // init the meta data store (including the contenttype history/stack)
00215     mdsInit();
00216 
00217     // init the history information
00218     hsInit();
00219 
00220     viewerInstallIpcServer();
00221 
00222     // whether or not the viewers are actually there is not important
00223     // during the init phase
00224     viewerInit(BROWSER_APP);
00225 
00226     erbusy_init();
00227     pagebar_init();
00228     toolbar_init();
00229 
00230     // power Manager init
00231     // MvdW: power manager disabled for now, needs more testing...
00232     // power_init();
00233 
00234     // init content key handling
00235     button_init(theContentLister);
00236 
00237     // init the program manager
00238     if (pm_InitProgramManager() != TRUE)
00239     {
00240         CL_ERRORPRINTF("Error initializing programManager, this will most likely cause a crash...");
00241     }
00242 
00243     // init the screen layout
00244     ctrl_init_screen_layout(topLevelWindow, theContentLister);
00245     theContentLister->lister = lsInit(theContentLister->listerArea, theContentLister);
00246     create_content_metadata_wnd(theContentLister->contentEditWnd);
00247     create_search_wnd(theContentLister->searchWnd);
00248     create_sort_wnd(theContentLister->sortWnd);
00249     create_dist_list_wnd(theContentLister->distListWnd);
00250     ctrlSetScreenTexts();
00251 
00252     // install class-specific screen update handlers
00253     //   erGtkEntry
00254     signal_id = g_signal_lookup("screen-refresh", ERGTK_ENTRY_TYPE);
00255     g_assert(signal_id > 0);
00256     g_signal_add_emission_hook(signal_id, 0, hook_screen_refresh_typing, (gpointer)TEXTENTRY_CHANGED_LEVEL, NULL);
00257     //   erGtkToggleButton
00258     signal_id = g_signal_lookup("toggled", ERGTK_TOGGLE_BUTTON_TYPE);
00259     g_assert(signal_id > 0);
00260     g_signal_add_emission_hook(signal_id, 0, hook_screen_refresh_typing, (gpointer)TEXTENTRY_CHANGED_LEVEL, NULL);
00261 
00262     cursor_init(theContentLister);
00263 
00264     theContentLister->itemCount = 0;
00265     theContentLister->currentContentType = st_ContentTypeUndefined;
00266     theContentLister->previousContentType = st_ContentTypeUndefined;
00267     theContentLister->currentFocus = 0;
00268     theContentLister->pagecount = 0;
00269     theContentLister->currentPage = 0;
00270     theContentLister->currentError = ctrlNoError;
00271 
00272     // Re-connect to server when requested
00273     gboolean do_connect = FALSE;
00274     int err = scGet_Reconnect(&do_connect);
00275     if (err == 0 && do_connect)
00276     {
00277         display_update_increase_level(NO_DISPLAY_UPDATE_LEVEL);
00278         g_idle_add(on_idle_connect_start, NULL);
00279     }
00280     else if (get_timedids_connect_reason() == connect_after_wakeup)
00281     {
00282         // iLiad is waken up by RTC alarm, need to connect to iDS
00283         display_update_increase_level(NO_DISPLAY_UPDATE_LEVEL);
00284         g_idle_add(on_timedids_connect_after_wakeup, NULL);
00285     }
00286     else
00287     {
00288         // Normal startup actions: select language, open QuickRef, etc.
00289         ctrl_startup();
00290     }
00291 
00292     return theContentLister;
00293 }
00294 
00295 static gboolean hook_screen_refresh_typing(GSignalInvocationHint *ihint, guint n_param_values, 
00296         const GValue *param_values, gpointer user_data)
00297 {
00298         int level = (int)user_data;
00299 
00300         CL_WARNPRINTF("entry: level [%d]", level);
00301 
00302         display_update_request_screen_refresh(level);
00303 
00304         return TRUE;  // please call again
00305 }
00306 
00307 void ctrlSetScreenTexts()
00308 {
00309     content_metadata_set_text();
00310     search_wnd_set_text();
00311     sort_wnd_set_text();
00312 }
00313 
00314 static gboolean on_idle_connect_start(gpointer user_data)
00315 {
00316     CL_LOGPRINTF("entry");
00317 
00318     ctrl_connect(connectScrMode, connect_after_reboot);
00319     
00320     return FALSE;               // don't call again
00321 }
00322 
00323 gboolean on_idle_connect_start_background(gpointer p)
00324 {
00325     CL_LOGPRINTF("entry");
00326 
00327     g_assert(p);
00328 
00329     e_ctrl_connect_reason_t connReason = (e_ctrl_connect_reason_t)p;
00330 
00331     const gchar* uaOnTop = pm_getUaOnTop();
00332 
00333     if (   strcmp(uaOnTop, PROFILES_APP) == 0
00334         || strcmp(uaOnTop, SETUP_APP   ) == 0
00335         || listerIsErrorScreenVisible()
00336         || g_select.active                   )
00337     {
00338         // profile editor or manual connect is running
00339         // or settings applicationf is running
00340         // or error screen is visible
00341         //     --> try again after retry interval
00342         CL_WARNPRINTF("Retry after [%d] minutes", BG_CONNECT_RETRY_INTERVAL);
00343         if (connReason == connect_timed_ids_background)
00344         {
00345             timed_ids_handle_recreate_timer(BG_CONNECT_RETRY_INTERVAL);
00346         }
00347         else
00348         {
00349             ctrl_background_connect_timeout_start_withinterval(FALSE, FALSE, BG_CONNECT_RETRY_INTERVAL);
00350         }
00351     }
00359     else
00360     {
00361         // no problems -> do background connect to iDS
00362         CL_WARNPRINTF("Do background connect");
00363 
00364         if (connReason == connect_timed_ids_background)
00365         {
00366             set_timedids_connect_reason(connect_when_running);
00367         }
00368         
00369         ctrl_connect(connectScrUnchanged, connReason);
00370     }
00371 
00372     return FALSE;  // don't call again
00373 }
00374 
00375 static void ctrl_background_connect_timeout_start_withinterval(gboolean read_settings, gboolean immediate, gint interval)
00376 {
00377     CL_LOGPRINTF("entry: read_settings [%d] interval [%d]", read_settings, interval);
00378 
00379     static gint  background_connect_interval = 0;
00380     static gint  background_timeout_id       = 0;  // 0 = initially no timeout running
00381 
00382     // read background-connect settings from registry
00383     if (read_settings)
00384     {
00385         regAutoConnect_t* autoconnect_settings = NULL;
00386 
00387         // get settings from registry 
00388         autoconnect_settings = erRegGetAutoConnect();
00389         if (autoconnect_settings)
00390         {
00391             // remember settings
00392             g_background_connect_enable = autoconnect_settings->backgroundEnable;
00393             background_connect_interval = autoconnect_settings->backgroundInterval;
00394             CL_WARNPRINTF("registry read: enable [%d] interval [%d]", g_background_connect_enable, background_connect_interval);
00395             g_free(autoconnect_settings);
00396         }
00397         else
00398         {
00399             CL_ERRORPRINTF("no settings from erRegReadAutoconnect");
00400         }
00401     }
00402 
00403     // stop time-out if running
00404     if (background_timeout_id > 0)
00405     {
00406         g_source_remove(background_timeout_id);
00407         background_timeout_id = 0;
00408     }
00409 
00410     // start new time-out if requested
00411     if (immediate)
00412     {
00413         interval = 0;
00414     }
00415     else if (interval <= 0)
00416     {
00417         interval = background_connect_interval;
00418     }
00419     if (g_background_connect_enable  ||  immediate)
00420     {
00421         background_timeout_id = g_timeout_add( 100 + (interval * 60 * 1000),
00422                                                on_idle_connect_start_background,
00423                                                (gpointer)connect_background);
00424         CL_WARNPRINTF("timeout started, interval [%d] id [%d]", interval, background_timeout_id);
00425     }
00426 }
00427 
00428 void ctrl_background_connect_timeout_start(gboolean read_settings)
00429 {
00430     CL_LOGPRINTF("entry: read_settings [%d]", read_settings);
00431 
00432     ctrl_background_connect_timeout_start_withinterval(read_settings, FALSE, 0);
00433 }
00434 
00435 void ctrl_set_connect_icon()
00436 {
00437 
00438     CL_LOGPRINTF("entry");
00439     
00440     // update connect-state on toolbar
00441     if (g_new_content_received)
00442     {
00443         if (gContentLister->currentContentType == st_DownloadHistory)
00444         {
00445             toolbar_setIconState(iconID_connect, 
00446                 g_new_content_acknowledged ? iconState_IDconnect_newcontent_selected : iconState_IDconnect_newcontent);
00447         }
00448         else if (g_new_content_acknowledged)
00449         {
00450             toolbar_setIconState(iconID_connect, g_background_connect_enable ? iconState_IDconnect_time : iconState_normal);
00451             g_new_content_received = FALSE;
00452         }
00453         else
00454         {
00455             toolbar_setIconState(iconID_connect, iconState_IDconnect_newcontent);
00456         }
00457     }
00458     else
00459     {
00460         toolbar_setIconState(iconID_connect, g_background_connect_enable ? iconState_IDconnect_time : iconState_normal);
00461     }
00462 }
00463 
00464 void ctrl_new_content_received()
00465 {
00466     CL_LOGPRINTF("entry");
00467 
00468     g_new_content_received     = TRUE;
00469     g_new_content_acknowledged = FALSE;
00470 }
00471 
00472 void ctrlDestroy(ContentLister * contentLister)
00473 {
00474     g_return_if_fail(contentLister != NULL);
00475 
00476     // TODO : store the last read content 
00477 
00478     // destroy the history information
00479     hsDestroy();
00480 
00481     pm_DestroyProgramManager();
00482 
00483     // store the loggin information 
00484     // g_free(contentLister);
00485 
00486     // free page content
00487     // mdsDestroy();
00488 
00489     // free pixmaps
00490     // icons_destroy();
00491 }
00492 
00500 static void ctrl_listItem_focus_no_redraw(int index, gpointer data)
00501 {
00502     ContentLister *theContentLister = (ContentLister *) data;
00503     CL_CURSORPRINTF("entry: index [%d]", index);
00504 
00505     // move cursor to specified item
00506     cursor_set_state(theContentLister->currentFocus, e_cursor_hide);
00507     cursor_set_state(index, e_cursor_show);
00508 
00509     // remember where the focus is
00510     theContentLister->currentFocus = index;
00511 
00512     // update the stored index value
00513     if (index >= 0)
00514     {
00515         mdsSetIndex( theContentLister->currentContentType, 
00516                      (MAX_ITEMS_ON_ONE_PAGE * (theContentLister->currentPage - 1)) + index );
00517     }
00518 }
00519 
00520 static void ctrl_listItem_focus(int index, gpointer data)
00521 {
00522     CL_CURSORPRINTF("entry: index [%d]", index);
00523 
00524     ctrl_listItem_focus_no_redraw(index, data);
00525     cursor_redraw();
00526 }
00527 
00528 
00529 static void ctrl_listItem_delete(const int* index_tbl, ContentLister* theContentLister)
00530 {
00531     clDisplayItem_t* theItem;
00532     int              itemIndex = 0;
00533     int              index;
00534     const int*       indexPtr;
00535     gboolean         deleted = FALSE;
00536     char*            argv[10];
00537     int              argc;
00538     char*            dir = NULL;
00539     char*            cp;
00540 
00541     CL_CONTROLPRINTF("entry: index [%d]", index_tbl[0]);
00542 
00543     for (indexPtr = index_tbl ; *indexPtr >= 0 ; indexPtr++)
00544     {
00545         index = *indexPtr;
00546 
00547         if (index >= 0  &&  index < theContentLister->itemCount)
00548         {
00549             CL_CURSORPRINTF("index [%d] [%s] itemCount [%d] trashcan [%d]",
00550                                     index,
00551                                          theContentLister->items[index].szFilename,
00552                                                         theContentLister->itemCount,
00553                                                                       toolbar_is_trashcan_selected() );
00554 
00555             // Trashcan mode: delete the item
00556             erbusy_blink();
00557             theItem = &theContentLister->items[index];
00558 
00559             if (theItem->modifyEnable.bDelete == FALSE)
00560             {
00561                 CL_WARNPRINTF("Delete disabled by manifest: item [%s]", theItem->szFilename);
00562             }
00563             else
00564             {
00565                 // update the stored index value
00566                 itemIndex = MAX_ITEMS_ON_ONE_PAGE * (theContentLister->currentPage - 1) + index;
00567                 mdsSetIndex(theContentLister->currentContentType, itemIndex);
00568                 switch (theItem->fit)
00569                 {
00570                     case mdsFitFolder:
00571                         CL_WARNPRINTF("-- deleting folder [%s]", theItem->szFilename);
00572                         argc = 0;
00573                         argv[argc++] = "rm";
00574                         argv[argc++] = "-rf";
00575                         argv[argc++] = theItem->szFilename;
00576                         argv[argc] = NULL;
00577                         g_assert( argc < (sizeof(argv)/sizeof(argv[0])) );
00578                         fork_exec(argc, argv);
00579                         deleted = TRUE;
00580                         break;
00581 
00582                     case mdsFitContainer:
00583                     case mdsFitManifestDirectory:
00584                         CL_WARNPRINTF("-- deleting container [%s]", theItem->szManifest);
00585                         dir = alloca( strlen(theItem->szManifest) + 1 );
00586                         g_assert(dir != NULL);
00587                         strcpy(dir, theItem->szManifest);
00588                         cp = strrchr(dir, '/');
00589                         if (cp)
00590                         {
00591                             *cp = '\0';
00592                             argc = 0;
00593                             argv[argc++] = "rm";
00594                             argv[argc++] = "-rf";
00595                             argv[argc++] = dir;
00596                             argv[argc] = NULL;
00597                             g_assert( argc < (sizeof(argv)/sizeof(argv[0])) );
00598                             fork_exec(argc, argv);
00599                             deleted = TRUE;
00600                         }
00601                         else
00602                         {
00603                             CL_ERRORPRINTF("-- invalid container [%s]", theItem->szFilename);
00604                         }
00605                         break;
00606 
00607                     case mdsFitFile:
00608                         CL_WARNPRINTF("-- deleting file [%s]", theItem->szFilename);
00609                         unlink(theItem->szFilename);
00610                         deleted = TRUE;
00611                         break;
00612 
00613                     case mdsFitApplication:
00614                     case mdsFitStorage:
00615                     case mdsFitSymlink:
00616                         CL_ERRORPRINTF("-- not allowed to delete item [%s] fit [%d] ", theItem->szFilename, theItem->fit);
00617                         break;
00618 
00619                     default:
00620                         CL_ERRORPRINTF("-- unknown fit [%d] item [%s]", theItem->fit, theItem->szFilename);
00621                         break;
00622                 }
00623             }
00624         }
00625     }
00626 
00627     if (deleted)
00628     {
00629         sync();
00630         ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
00631     }
00632 }
00633 
00634 void ctrl_listItem_clicked(int index, gpointer data)
00635 {
00636     ContentLister    *theContentLister = (ContentLister *) data;
00637     clDisplayItem_t  *theItem;
00638     int              itemIndex = 0;
00639     st_ContentType_e storageType;
00640     gboolean         ret;
00641 
00642     CL_CONTROLPRINTF("Entry: index [%d]", index);
00643 
00644     // action required only when content lister in normal state and visible
00645     if (   g_listerState != STATE_NORMAL
00646         || strcmp(pm_getUaOnTop(), CONTENTLISTER_UAID) != 0)
00647     {
00648         CL_WARNPRINTF("Ignore because contentLister in special state or not visible");
00649         return;
00650     }
00651 
00652     if (g_select.active)
00653     {
00654         // select mode: blink or hide cursor for this item
00655         if (g_select.item_selected[index])
00656         {
00657             g_select.item_selected[index] = FALSE;
00658             cursor_set_state(index, e_cursor_hide);
00659             cursor_redraw();
00660         }
00661         else
00662         {
00663             g_select.item_selected[index] = TRUE;
00664             cursor_set_state(index, e_cursor_blink);
00665             cursor_redraw();
00666 
00667             if ( !g_select.confirm_with_icon )
00668             {
00669                 g_select.icon_clicked = TRUE;
00670             }
00671         }
00672 
00673         // restart the select timeout
00674         g_select.ticks = ITEM_SELECT_TIMEOUT_TICKS;
00675     }
00676     else if ( !ctrl_current_location_is_outbox() )
00677     {
00678         // Not in select mode: open the item
00679         erbusy_blink();
00680 
00681         theItem = &theContentLister->items[index];
00682 
00683         // position cursor on the selected item
00684         ctrl_listItem_focus(index, theContentLister);
00685 
00686         // update the stored index value
00687         itemIndex = ctrl_get_item_index(theContentLister);
00688         mdsSetIndex(theContentLister->currentContentType, itemIndex);
00689 
00690         // now act on the selected item
00691         switch (theItem->fit)
00692         {
00693             case mdsFitFolder:
00694                 ctrl_scan_content(theContentLister, ctrlScanNext, theItem->szFilename);
00695                 break;
00696 
00697             case mdsFitApplication:
00698                 CL_CONTROLPRINTF("mdsFitApplication");
00699                 // before enter setup, ask user input pincode
00700                 if (0 == strcmp(theItem->szExtID, SETUP_APP))
00701                 {
00702                     gboolean enable = FALSE;
00703                     gchar pincode[PINCODE_MAX_LENGTH + 1];
00704 
00705                     gtk_pincode_screen_get_pincode_settings(theContentLister->pincodeScreen, &enable, pincode);
00706                     if (FALSE == enable || 0 == strlen(pincode))
00707                     {
00708                         ctrl_start_application(theItem->szExtID, NULL);
00709                     }
00710                     else
00711                     {
00712                         ctrl_show_pincode_screen(enterSettings_t, ctrl_start_setup, NULL);
00713                     }
00714                 }
00715                 else
00716                 {
00717                     ctrl_start_application(theItem->szExtID, NULL);
00718                 }
00719                 break;
00720 
00721             case mdsFitManifestDirectory:
00722                 CL_CONTROLPRINTF("mdsFitManifestDirectory -> %s", theItem->szFilename);
00723                 ctrl_scan_content(theContentLister, ctrlScanNext, theItem->szFilename);
00724                 break;
00725 
00726             case mdsFitStorage:
00727                 storageType = ctrl_get_storageType(theItem->szExtID);
00728 
00729                 if (stackIsStorage(storageType) == TRUE)
00730                 {
00731                     CL_CONTROLPRINTF("scan storage type %d", storageType);
00732 
00733                     // update the contentType
00734                     theContentLister->previousContentType = theContentLister->currentContentType;
00735                     theContentLister->currentContentType = storageType;
00736                     ctrl_scan_content(theContentLister, ctrlScanCurrent, 0);
00737                 }
00738                 else
00739                 {
00740                     CL_ERRORPRINTF("invalid storage type");
00741                 }
00742                 break;
00743                 
00744             case mdsFitContainer:
00745                 ret = ctrl_start_viewer(theContentLister->currentContentType, theItem, NULL);
00746                 if (ret == FALSE)
00747                 {
00748                     // Not busy!
00749                     erbusy_off();
00750                 }
00751                 break;
00752                 
00753             case mdsFitFile:
00754                 ctrl_before_file_clicked(theItem);
00755                 ret = ctrl_start_viewer(theContentLister->currentContentType, theItem, NULL);
00756                 if (ret == FALSE)
00757                 {
00758                     // Not busy!
00759                     erbusy_off();
00760                 }
00761                 break;
00762 
00763             case mdsFitSymlink:
00764             default:
00765                 CL_ERRORPRINTF("theItem->fit %d - UNKNOWN", theItem->fit);
00766         }
00767     }
00768 }
00769 
00770 void ctrl_storage_changed(st_ContentType_e storageType, gboolean storagePresent)
00771 {
00772     ContentLister *theContentLister = gContentLister;
00773     
00774     CL_CONTROLPRINTF("Entry: storageType [%d] Present [%d]", storageType, storagePresent);
00775 
00776     if (storagePresent)
00777     {
00778         // if the archive locations are redirected to the storage device,
00779         // check the archive folders exits or not, if not create them
00780         mdsRecreateArchives(storageType);
00781     }
00782 
00783     if (theContentLister != NULL 
00784         && (theContentLister->currentContentType == storageType 
00785             || mdsArcLocIsChanged(theContentLister->currentContentType, storageType)) )
00786     {
00787         if (!storagePresent)
00788         {
00789             ctrl_hide_misc_screen();
00790         }
00791         ctrl_select_stop(TRUE);
00792 
00793         if (stackIsStorage(storageType) == TRUE)
00794         {
00795             CL_CONTROLPRINTF("scan storage type %d", storageType);
00796             stackClear(theContentLister->currentContentType);
00797             ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
00798         }
00799         else
00800         {
00801             CL_ERRORPRINTF("invalid storage type");
00802         }
00803     }
00804 
00805     erMSDisk_storage_changed(storageType, storagePresent);
00806 }
00807 
00818 static gboolean ctrl_start_viewer(st_ContentType_e theType, clDisplayItem_t * theItem, char *location)
00819 {
00820     char *viewer_id;
00821     gboolean returnValue = TRUE;
00822     int viewerReturn = 0;
00823     gboolean isActive = FALSE;
00824     st_ContentType_e ContentTypeUsingViewer;
00825     gboolean viewerStartNeeded = TRUE;
00826 
00827     g_assert(theItem != NULL);
00828     CL_CONTROLPRINTF("Entry: contentType [%d] file [%s]", theType, theItem->szFilename);
00829 
00830     viewer_id = pm_getUaID(theItem->szFileExt);
00831     if (NULL != viewer_id)
00832     {
00833         // => only request a refresh on the main window expose event
00834         CL_SCREENPRINTF("");
00835 
00836         display_update_increase_level(TOOLBAR_UPDATE_LEVEL);
00837 
00838         // check if the viewer is already active
00839         isActive = pm_IsActive(viewer_id);
00840 
00841         CL_HISTORYPRINTF("viewer %s is active = %s", viewer_id, (isActive ? "TRUE" : "FALSE"));
00842 
00843         if (isActive)
00844         {
00845             ContentTypeUsingViewer = hsGetContentType(viewer_id);
00846             CL_HISTORYPRINTF(" ContentTypeUsingViewer = %d", ContentTypeUsingViewer);
00847 
00848             if ((ContentTypeUsingViewer == theType) && (stackIsArchive(ContentTypeUsingViewer)))
00849             {
00850                 //viewer is alreay active for this archive content type
00851                 CL_HISTORYPRINTF("Viewer still active => RaiseViewer %s", viewer_id);
00852                 //pm_RaiseViewer(viewer_id);
00853                 //viewerStartNeeded = FALSE;
00854             }
00855             else
00856             {
00857                 //viewer is active for an archive key 
00858                 if (stackIsArchive(ContentTypeUsingViewer))
00859                 {
00860                     CL_HISTORYPRINTF("viewerStore viewer [id=%s] ", viewer_id);
00861                     viewerStore(viewer_id, ContentTypeUsingViewer);
00862                 }
00863             }
00864         }
00865 
00866         if (viewerStartNeeded)
00867         {
00868             CL_HISTORYPRINTF("viewerStartNeeded (loc = %s)", (location == NULL) ? "NULL" : location);
00869 
00870             viewerReturn = pm_RunViewer(viewer_id, theItem->szFilename, theItem->szManifest, NULL, 0);
00871 
00872             if (viewerReturn == ERR_OK)
00873             {
00874                 // keep track of which content type is using which viewer
00875                 hsSetActiveViewer(theType, viewer_id);
00876 
00877                 // keep track of the last viewed content Item
00878                 hsStoreItem(theType, theItem);
00879 
00880                 //clear the last viewed location
00881                 hsRemoveLocation(theType);
00882                 
00883                 // start progress indication (knight rider)
00884                 start_progress_indicator();
00885             }
00886             else
00887             {
00888                 CL_ERRORPRINTF("pmRunViewer returned %d", viewerReturn);
00889                 returnValue = FALSE;
00890             }
00891         }                   //(viewerStartNeeded)  
00892     }
00893     else
00894     {
00895         CL_ERRORPRINTF("theItem->szFileExt [%s] - UNHANDLED FILE TYPE", theItem->szFileExt);
00896         returnValue = FALSE;
00897     }
00898 
00899     return returnValue;
00900 }
00901 
00915 static int ctrl_scan_content(ContentLister * theContentLister, ctrlScanType_e scanType, char *folder)
00916 {
00917     int totalItemCount;
00918     int result = ERMDS_CONTENT_SCAN_FAILED;
00919     int req_cnt = MAX_ITEMS_ON_ONE_PAGE;
00920     int itemIndex = 0;
00921     int startindex;
00922 
00923     CL_CONTROLPRINTF("Entry: folder [%s] type [%d]", folder, theContentLister->currentContentType);
00924 
00925     if (   theContentLister->currentContentType <  0
00926         || theContentLister->currentContentType >= st_ContentTypeUndefined)
00927     {
00928         return ERMDS_CONTENT_SCAN_FAILED;
00929     }
00930 
00931     // remove dangling symlinks
00932     if (   theContentLister->currentContentType == st_RecentDocuments
00933         || theContentLister->currentContentType == st_DownloadHistory )
00934     {
00935         char dirname[ERMDS_MAX_FILENAME_SIZE];
00936         if ( mdsGetRootLocation(theContentLister->currentContentType, dirname, sizeof(dirname)) > 0 )
00937         {
00938             if (getListerState() != STATE_USB_CONNECTED)
00939             {
00940                 hsCleanupSymlinks(dirname);
00941             }
00942             else
00943             {
00944                 CL_WARNPRINTF("Not cleaning up history when listerState is STATE_USB_CONNECTED");
00945             }
00946         }
00947     }
00948 
00949     // update toolbar icon "connect"
00950     ctrl_set_connect_icon();
00951     
00952     // scan the specified type and location
00953     switch (scanType)
00954     {
00955         case ctrlScanCurrent:
00956             result = mdsScanCurrent(theContentLister->currentContentType);
00957             itemIndex = mdsGetIndex(theContentLister->currentContentType);
00958             CL_CURSORPRINTF("ctrlScanCurrent itemIndex %d", itemIndex);
00959             break;
00960         case ctrlScanNext:
00961             CL_CONTROLPRINTF("scan folder %s", folder);
00962             itemIndex = 0;
00963             CL_CURSORPRINTF("ctrlScanNext itemIndex %d", itemIndex);
00964             result = mdsScanNext(theContentLister->currentContentType, folder, 0);
00965             break;
00966         case ctrlScanPrevious:
00967             result = mdsScanPrevious(theContentLister->currentContentType);
00968             itemIndex = mdsGetIndex(theContentLister->currentContentType);
00969             CL_CURSORPRINTF("ctrlScanCurrent itemIndex %d", itemIndex);
00970             break;
00971     }
00972 
00973     if ((ERMDS_CONTENT_SCAN_OK == result) || (ERMDS_CONTENT_SCAN_TOO_MANY_ITEMS == result))
00974     {
00975         // possibly second time in the loop => undo error indication
00976         theContentLister->currentError = ctrlNoError;
00977 
00978         totalItemCount = mdsGetItemCount();
00979         if (itemIndex >= totalItemCount)
00980         {
00981             itemIndex = totalItemCount - 1;
00982         }
00983 
00984         if (totalItemCount > 0)
00985         {
00986             theContentLister->pagecount = (totalItemCount + (MAX_ITEMS_ON_ONE_PAGE - 1)) / MAX_ITEMS_ON_ONE_PAGE;
00987             theContentLister->currentPage = (itemIndex / MAX_ITEMS_ON_ONE_PAGE) + 1;
00988             theContentLister->currentFocus = itemIndex % MAX_ITEMS_ON_ONE_PAGE;
00989             CL_CURSORPRINTF("page %d focus %d", theContentLister->currentPage, theContentLister->currentFocus);
00990 
00991             startindex = MAX_ITEMS_ON_ONE_PAGE * (theContentLister->currentPage - 1);
00992             mdsSetPageContent(theContentLister->items, startindex, &req_cnt);
00993             theContentLister->itemCount = req_cnt;
00994 
00995         }
00996         else
00997         {
00998             theContentLister->itemCount = 0;
00999             theContentLister->pagecount = 0;
01000             theContentLister->currentPage = 0;
01001             theContentLister->currentFocus = 0;
01002         }
01003 
01004         ctrl_display_item_view(theContentLister);
01005     }
01006     else
01007     {
01008         theContentLister->currentError = ctrlScanFailedError;
01009 
01010         if (scanType == ctrlScanNext)
01011         {
01012             // restore the stack
01013             stackPop(theContentLister->currentContentType);
01014         }
01015 
01016         listerShowErrorScreen(ctrlScanFailedError);
01017     }
01018     return result;
01019 }
01020 
01021 // convert the ID from the manifest file to the known storage types
01022 st_ContentType_e ctrl_get_storageType(gchar * szExtID)
01023 {
01024     st_ContentType_e theType = st_ContentTypeUndefined;
01025 
01026     if (strncmp(szExtID, CF_ID, ERMDS_MAX_EXTENSION_ID_SIZE) == 0)
01027     {
01028         theType = st_StorageTypeCF;
01029     }
01030     else if (strncmp(szExtID, SD_ID, ERMDS_MAX_EXTENSION_ID_SIZE) == 0)
01031     {
01032         theType = st_StorageTypeSD;
01033     }
01034     else if (strncmp(szExtID, USB_ID, ERMDS_MAX_EXTENSION_ID_SIZE) == 0)
01035     {
01036         theType = st_StorageTypeUSB;
01037     }
01038     else if (strncmp(szExtID, MAIN_MEMORY_ID, ERMDS_MAX_EXTENSION_ID_SIZE) == 0)
01039     {
01040         theType = st_StorageTypeMain;
01041     }
01042     else if (strncmp(szExtID, RECENT_DOCS_ID, ERMDS_MAX_EXTENSION_ID_SIZE) == 0)
01043     {
01044         theType = st_RecentDocuments;
01045     }
01046 
01047     return theType;
01048 }
01049 
01050 unsigned int ctrl_get_item_index(ContentLister * theContentLister)
01051 {
01052     unsigned int itemIndex;
01053     int pageIndex;
01054 
01055     pageIndex = (theContentLister->currentPage - 1);
01056     if (pageIndex < 0)
01057     {
01058         pageIndex = 0;
01059     }
01060 
01061     itemIndex = (pageIndex * MAX_ITEMS_ON_ONE_PAGE);
01062     if (itemIndex >= 0)
01063     {
01064         itemIndex += theContentLister->currentFocus;
01065     }
01066 
01067     CL_CURSORPRINTF ("item index %d (current page %d, pageindex %d, currentFocus %d)",
01068                                  itemIndex,       theContentLister->currentPage,
01069                                                                 pageIndex,       theContentLister->currentFocus);
01070 
01071     return itemIndex;
01072 }
01073 
01074 static void ctrl_init_screen_layout(GtkWidget * topLevelWindow, ContentLister * theContentLister)
01075 {
01076     GtkWidget *topLevelVBox;
01077 
01078     // object hierarchy:
01079     //     topLevelWindow
01080     //       |-- topLevelVBox
01081     //             |
01082     topLevelVBox = gtk_vbox_new(FALSE, 0);
01083     gtk_container_add(GTK_CONTAINER(topLevelWindow), topLevelVBox);
01084     //             |
01085     //             |-- theContentLister->listerScreen
01086     //             |     |-- alignment
01087     //             |           |-- vbox
01088     //             |                 |
01089     theContentLister->listerScreen = gtk_event_box_new();
01090     gtk_widget_set_name(GTK_WIDGET(theContentLister->listerScreen), "lister_background");
01091     gtk_box_pack_start(GTK_BOX(topLevelVBox), theContentLister->listerScreen, TRUE, TRUE, 0);
01092     gtk_widget_show(theContentLister->listerScreen);
01093     //
01094     GtkWidget* alignment = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
01095     gtk_widget_show(alignment);
01096     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), LISTER_BOX_BORDER, 0, 0, 0);
01097     gtk_container_add(GTK_CONTAINER(theContentLister->listerScreen), alignment);
01098     // 
01099     GtkWidget *vbox = gtk_vbox_new(FALSE, LIST_ITEM_SPACING);
01100     gtk_container_add(GTK_CONTAINER(alignment), vbox);
01101     gtk_widget_show(vbox);
01102     //             |                 |-- theContentLister->listerArea (event box)
01103     //             |                 |
01104     theContentLister->listerArea = gtk_event_box_new();
01105     gtk_widget_set_name(GTK_WIDGET(theContentLister->listerArea), "lister_background");
01106     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(theContentLister->listerArea), GTK_CAN_FOCUS);
01107     gtk_box_pack_start(GTK_BOX(vbox), theContentLister->listerArea, FALSE, FALSE, 0);
01108     gtk_widget_show(theContentLister->listerArea);
01109     //             |                 |
01110     //             |                 |-- alignment
01111     //             |                       |-- vbox
01112     //             |                             |
01113     alignment = gtk_alignment_new(0.0, 0.0, 0.0, 0.0);
01114     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, LISTER_BOX_BORDER, 0);
01115     gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0);
01116     gtk_widget_show(alignment);
01117     // 
01118     vbox = gtk_vbox_new(FALSE, 0);
01119     gtk_container_add(GTK_CONTAINER(alignment), vbox);
01120     gtk_widget_show(vbox);
01121     //             |                             |
01122     //             |                             |-- theContentLister->contentEditWnd (event box)
01123     theContentLister->contentEditWnd = gtk_event_box_new();
01124     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(theContentLister->contentEditWnd), GTK_CAN_FOCUS);
01125     gtk_widget_set_name(GTK_WIDGET(theContentLister->contentEditWnd), "lister_background");
01126     gtk_box_pack_start(GTK_BOX(vbox), theContentLister->contentEditWnd, FALSE, FALSE, METADATA_WND_SPACE_ABOVE);
01127     //             |                             |
01128     //             |                             |-- theContentLister->searchWnd (event box)
01129     theContentLister->searchWnd = gtk_event_box_new();
01130     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(theContentLister->searchWnd), GTK_CAN_FOCUS);
01131     gtk_widget_set_name(GTK_WIDGET(theContentLister->searchWnd), "lister_background");
01132     gtk_box_pack_start(GTK_BOX(vbox), theContentLister->searchWnd, FALSE, FALSE, SEARCH_WND_SPACE_ABOVE);
01133     //             |                             |
01134     //             |                             |-- theContentLister->sortWnd (event box)
01135     theContentLister->sortWnd = gtk_event_box_new();
01136     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(theContentLister->sortWnd), GTK_CAN_FOCUS);
01137     gtk_widget_set_name(GTK_WIDGET(theContentLister->sortWnd), "lister_background");
01138     gtk_box_pack_start(GTK_BOX(vbox), theContentLister->sortWnd, FALSE, FALSE, 0);
01139     //             |                             |
01140     //             |                             |-- theContentLister->distListWnd (event box)
01141     //             |
01142     theContentLister->distListWnd = gtk_event_box_new();
01143     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(theContentLister->distListWnd), GTK_CAN_FOCUS);
01144     gtk_widget_set_name(GTK_WIDGET(theContentLister->distListWnd), "lister_background");
01145     gtk_box_pack_start(GTK_BOX(vbox), theContentLister->distListWnd, FALSE, FALSE, 0);
01146     //             |
01147     //             |-- theContentLister->errorScreen (GtkErrorScreen)
01148     //             |
01149     theContentLister->errorScreen = gtk_error_screen_new();
01150     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(theContentLister->errorScreen), GTK_CAN_FOCUS);
01151     gtk_box_pack_start(GTK_BOX(topLevelVBox), theContentLister->errorScreen, TRUE, TRUE, 0);
01152     //             |
01153     //             |-- theContentLister->pincodeScreen (GtkPincodeScreen)
01154     //
01155     theContentLister->pincodeScreen = gtk_pincode_screen_new();
01156     GTK_WIDGET_SET_FLAGS(GTK_WIDGET(theContentLister->pincodeScreen), GTK_CAN_FOCUS);
01157     gtk_box_pack_start(GTK_BOX(topLevelVBox), theContentLister->pincodeScreen, TRUE, TRUE, 0);
01158 
01159     gtk_widget_show(topLevelVBox);
01160 
01161     g_signal_connect(G_OBJECT(theContentLister->listerArea),
01162                      "key_press_event", G_CALLBACK(ctrl_listerArea_keypress), theContentLister);
01163     g_signal_connect(G_OBJECT(theContentLister->errorScreen),
01164                      "button_press_event", G_CALLBACK(ctrl_errorScreen_buttonpress), theContentLister);
01165 
01166     g_signal_connect(G_OBJECT(topLevelWindow), "expose-event",
01167                      G_CALLBACK(ctrl_main_window_expose_event), theContentLister);
01168     g_signal_connect(G_OBJECT(topLevelWindow), "realize", G_CALLBACK(ctrl_main_window_realize_event), theContentLister);
01169 }
01170 
01179 static void ctrl_display_item_view(ContentLister * theContentLister)
01180 {
01181     char page_title[ERCL_MAX_TITLE_SIZE];
01182 
01183     CL_CONTROLPRINTF("entry");
01184 
01185     if (theContentLister)
01186     {
01187         switch (theContentLister->currentContentType)
01188         {
01189             case st_ContentTypeBooks:
01190             case st_ContentTypeNews:
01191             case st_ContentTypeDocs:
01192             case st_ContentTypeNotes:
01193             case st_StorageTypeMain:        // MAIN MEMORY
01194             case st_StorageTypeCF:      // Should check if filesystem is readonly, but how?
01195             case st_StorageTypeSD:      // Should check if filesystem is readonly, but how?
01196             case st_StorageTypeUSB:     // Should check if filesystem is readonly, but how?
01197                 toolbar_disableUpdate();
01198                 // Custom toolbar states for certain special folders
01199                 if ( ctrl_current_location_is_empty() )
01200                 {
01201                     toolbar_setIconState(iconID_trashcan, iconState_grey);
01202                 }
01203                 else
01204                 {
01205                     toolbar_setIconState(iconID_trashcan, iconState_normal);
01206                 }
01207 
01208                 if ( ctrl_current_location_is_mobipocket() 
01209                         || ctrl_current_location_is_outbox() 
01210                         || ctrl_current_location_is_empty() )
01211                 {
01212                     toolbar_setIconState(iconID_share,    iconState_grey  );
01213                     toolbar_setIconState(iconID_tagging,  iconState_grey  );
01214                 }
01215                 else
01216                 {
01217                     toolbar_setIconState(iconID_share,    iconState_normal);
01218                     toolbar_setIconState(iconID_tagging,  iconState_normal);
01219                 }
01220                 
01221                 if ( ctrl_current_location_is_outbox() || ctrl_current_location_is_empty() ) 
01222                 {
01223                     toolbar_setIconState(iconID_search,   iconState_grey  );
01224                     toolbar_setIconState(iconID_sort,     iconState_grey  );
01225                 }
01226                 else
01227                 {
01228                     toolbar_setIconState(iconID_search,   iconState_normal);
01229                     toolbar_setIconState(iconID_sort,     iconState_normal);
01230                 }
01231                 
01232                 toolbar_enableUpdate();
01233                 break;
01234                 
01235             case st_MenuTypeMode:
01236             case st_DownloadHistory:
01237             case st_RecentDocuments:
01238                 toolbar_disableUpdate();
01239                 toolbar_setIconState(iconID_search,   iconState_grey);
01240                 toolbar_setIconState(iconID_sort,     iconState_grey);
01241                 toolbar_setIconState(iconID_share,    iconState_grey);
01242                 toolbar_setIconState(iconID_tagging,  iconState_grey);
01243                 toolbar_setIconState(iconID_trashcan, iconState_grey);
01244                 toolbar_enableUpdate();
01245                 break;
01246 
01247             case st_SearchResult:
01248                 toolbar_disableUpdate();
01249                 toolbar_setIconState(iconID_trashcan,    iconState_grey  );
01250                 toolbar_setIconState(iconID_tagging,     iconState_grey  );
01251                 if ( ctrl_current_location_is_empty() )
01252                 {
01253                     toolbar_setIconState(iconID_search,      iconState_grey);
01254                 }
01255                 else
01256                 {
01257                     toolbar_setIconState(iconID_search,      iconState_normal);
01258                 }
01259                 toolbar_setIconState(iconID_sort,        iconState_grey);
01260                 toolbar_setIconState(iconID_share,       iconState_grey  );
01261                 toolbar_enableUpdate();
01262                 break;
01263 
01264             default:
01265                 CL_ERRORPRINTF("Unknown currentContentType: %d", theContentLister->currentContentType);
01266                 toolbar_disableUpdate();
01267                 toolbar_setIconState(iconID_search,   iconState_grey);
01268                 toolbar_setIconState(iconID_sort,     iconState_grey);
01269                 toolbar_setIconState(iconID_share,    iconState_grey);
01270                 toolbar_setIconState(iconID_tagging,  iconState_grey);
01271                 toolbar_setIconState(iconID_trashcan, iconState_grey);
01272                 toolbar_enableUpdate();
01273         }
01274 
01275         // hide cursor for outbox
01276         if (ctrl_current_location_is_outbox())
01277         {
01278             ctrl_listItem_focus(-1, theContentLister);
01279         }
01280 
01281         ctrl_get_content_name(theContentLister->currentContentType, page_title);
01282 
01283         // get current location information. display location in title bar
01284         const char* location;
01285         if (theContentLister->currentContentType == st_DownloadHistory)
01286         {
01287             location = "";
01288         }
01289         else
01290         {
01291             location = ctrl_get_current_location(theContentLister);
01292         }
01293         lsUpdatePage(theContentLister->lister, theContentLister->items,
01294                      theContentLister->itemCount, theContentLister->currentFocus, page_title, location);
01295 
01296         pagebar_reset();        // a little overkill, but this ensures the 
01297         // pageBar always has the correct
01298         // currentApp
01299         pagebar_set_pagecount(theContentLister->pagecount);
01300         pagebar_goto_page(theContentLister->currentPage);
01301         pagebar_redraw();
01302     }
01303     else
01304     {
01305         CL_ERRORPRINTF("theContentLister == NULL");
01306     }
01307 }
01308 
01309 static guint ctrl_listerArea_keypress(GtkWidget * widget, GdkEventKey * event, ContentLister * theContentLister)
01310 {
01311     int newPage;
01312     int returnValue = 0;        // return FALSE => default gtk
01313     // handling
01314     int newFocus;
01315 
01316     CL_CONTROLPRINTF("entry: keyval [0x%04X]", event->keyval);
01317 
01318     CL_TIMEDISPLAY("keypress handling");
01319 
01320     // ignore all keys during select or rename action
01321     if (   g_select.active
01322         || toolbar_is_tagging_selected() )
01323     {
01324         erbusy_off();
01325         return returnValue;
01326     }
01327 
01328     switch (event->keyval)
01329     {
01330         case GDK_Page_Down:
01331             newPage = theContentLister->currentPage + 1;
01332             ctrl_goto_page(newPage);
01333 
01334             // return TRUE => stop event handling 
01335             returnValue = 1;
01336             break;
01337 
01338         case GDK_F1:
01339             // long PAGETURN_FORWARD keypress
01340             newPage =
01341                 ((theContentLister->currentPage + 5) <= theContentLister->pagecount) ? (theContentLister->currentPage + 5)
01342                                                                                      : theContentLister->pagecount;
01343             ctrl_goto_page(newPage);
01344 
01345             // return TRUE => stop event handling 
01346             returnValue = 1;
01347             break;
01348 
01349         case GDK_Page_Up:
01350             newPage = theContentLister->currentPage - 1;
01351             ctrl_goto_page(newPage);
01352 
01353             // return TRUE => stop event handling 
01354             returnValue = 1;
01355             break;
01356 
01357         case GDK_F2:
01358             // long PAGETURN_BACK keypress
01359             newPage = ((theContentLister->currentPage - 5) < 1) ? (1) : (theContentLister->currentPage - 5);
01360             ctrl_goto_page(newPage);
01361 
01362             // return TRUE => stop event handling 
01363             returnValue = 1;
01364             break;
01365 
01366         case GDK_Home:
01367             // long press
01368             CL_CONTROLPRINTF("jumping back to root (Home)");
01369             stackClear(theContentLister->currentContentType);
01370             ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01371             // return TRUE => stop event handling 
01372             returnValue = 1;
01373             break;
01374 
01375         case GDK_F5:
01376             // OVERVIEW keypress
01377             CL_CONTROLPRINTF("jumping one level up (F5)");
01378             if ( (st_StorageTypeCF   == theContentLister->currentContentType ||
01379                   st_StorageTypeSD   == theContentLister->currentContentType ||
01380                   st_StorageTypeUSB  == theContentLister->currentContentType ||
01381                   st_StorageTypeMain == theContentLister->currentContentType ||
01382                   st_RecentDocuments == theContentLister->currentContentType   ) &&
01383                 0 >= stackHeight(theContentLister->currentContentType))
01384             {
01385                 // goto device manager
01386                 theContentLister->currentContentType = st_MenuTypeMode;
01387                 ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01388             }
01389             else if (st_SearchResult == theContentLister->currentContentType
01390                      && 0 >= stackHeight(theContentLister->currentContentType))
01391             {
01392                 CL_WARNPRINTF("    -- Search result: return to previous");
01393                 theContentLister->currentContentType = theContentLister->previousContentType;
01394                 theContentLister->previousContentType = st_SearchResult;
01395                 ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01396             }
01397             else
01398             {
01399                 ctrl_scan_content(theContentLister, ctrlScanPrevious, NULL);
01400             }
01401             // return TRUE => stop event handling 
01402             returnValue = 1;
01403             break;
01404 
01405         case GDK_Return:
01406         case GDK_F6:
01407             if (theContentLister->itemCount > 0)
01408             {
01409                 CL_CONTROLPRINTF("jumping to focused item %d", theContentLister->currentFocus);
01410 
01411                 // find the item that has the focus
01412                 if (theContentLister->currentFocus >= 0 && theContentLister->currentFocus < MAX_ITEMS_ON_ONE_PAGE)
01413                 {
01414                     ctrl_listItem_clicked(theContentLister->currentFocus, theContentLister);
01415                 }
01416             }
01417             else
01418             {
01419                 erbusy_off();
01420             }
01421             // return TRUE => stop event handling 
01422             returnValue = 1;
01423             break;
01424 
01425         case GDK_Up:
01426             if ( !ctrl_current_location_is_outbox() )
01427             {
01428                 if (theContentLister->itemCount > 0)
01429                 {
01430                     CL_CONTROLPRINTF("prev item -- current %d itemCount %d",
01431                                      theContentLister->currentFocus, theContentLister->itemCount);
01432                     if (theContentLister->currentFocus == -1)
01433                     {
01434                         newFocus = 0;
01435                     }
01436                     else if (theContentLister->currentFocus == 0)
01437                     {
01438                         newFocus = theContentLister->itemCount - 1;
01439                     }
01440                     else
01441                     {
01442                         newFocus = theContentLister->currentFocus - 1;
01443                     }
01444                     ctrl_listItem_focus(newFocus, theContentLister);
01445                 }
01446             }
01447             erbusy_off();
01448             // return TRUE => stop event handling 
01449             returnValue = 1;
01450             break;
01451 
01452         case GDK_F4:
01453             // long PREVIOUS_LINK_BUTTON keypress
01454             CL_CURSORPRINTF("long prev item -- current %d", theContentLister->currentFocus);
01455             if ( !ctrl_current_location_is_outbox() )
01456             {
01457                 if (theContentLister->currentFocus != 0)
01458                 {
01459                     ctrl_listItem_focus(0, theContentLister);
01460                 }
01461             }
01462             erbusy_off();
01463             // return TRUE => stop event handling 
01464             returnValue = 1;
01465             break;
01466 
01467         case GDK_Down:
01468             if ( !ctrl_current_location_is_outbox() )
01469             {
01470                 if (theContentLister->itemCount > 0)
01471                 {
01472                     CL_CONTROLPRINTF("next item -- current %d itemCount %d",
01473                                      theContentLister->currentFocus, theContentLister->itemCount);
01474                     newFocus = theContentLister->currentFocus + 1;
01475                     if (newFocus >= theContentLister->itemCount)
01476                     {
01477                         newFocus = 0;
01478                     }
01479                     ctrl_listItem_focus(newFocus, theContentLister);
01480                 }
01481             }
01482             erbusy_off();
01483             // return TRUE => stop event handling 
01484             returnValue = 1;
01485             break;
01486 
01487         case GDK_F3:
01488             // long NEXT_LINK_BUTTON keypress
01489             CL_CURSORPRINTF("long next item -- current %d", theContentLister->currentFocus);
01490             if ( !ctrl_current_location_is_outbox() )
01491             {
01492                 if (theContentLister->currentFocus != (theContentLister->itemCount - 1))
01493                 {
01494                     ctrl_listItem_focus(theContentLister->itemCount - 1, theContentLister);
01495                 }
01496             }
01497             erbusy_off();
01498             // return TRUE => stop event handling 
01499             returnValue = 1;
01500             break;
01501 
01502 #ifdef COMMAND_LINE_INPUT
01503         case GDK_F12:
01504             // test case 
01505             ctrl_contentType_button_clicked(st_ContentTypeBooks);
01506             break;
01507         case GDK_F11:
01508             // test case 
01509             ctrl_contentType_button_clicked(st_ContentTypeNews);
01510             break;
01511         case GDK_F10:
01512             // test case 
01513             ctrl_contentType_button_clicked(st_ContentTypeDocs);
01514             break;
01515         case GDK_F9:
01516             // test case 
01517             ctrl_contentType_button_clicked(st_ContentTypeNotes);
01518             break;
01519         case GDK_F8:
01520             // test case 
01521             ctrl_mode_button_clicked();
01522             break;
01523         case GDK_F7:
01524             // test case 
01525             ctrl_display_download_history();
01526             break;
01527 #endif // COMMAND_LINE_INPUT
01528 
01529     }                           // end switch
01530 
01531     return returnValue;
01532 }
01533 
01534 void ctrl_goto_page(int pagenumber)
01535 {
01536     CL_SCREENPRINTF("entry: pagenum [%d]", pagenumber);
01537 
01538     int startindex;
01539     int req_cnt = MAX_ITEMS_ON_ONE_PAGE;
01540     ContentLister *theContentLister = gContentLister;
01541 
01542     if (   getListerState() == STATE_MISC
01543         && GTK_WIDGET_VISIBLE(theContentLister->distListWnd))
01544     {
01545         dist_list_wnd_goto_page(pagenumber);
01546     }
01547     else if ((pagenumber > 0) && (pagenumber != theContentLister->currentPage)
01548              && (pagenumber <= theContentLister->pagecount))
01549     {
01550         theContentLister->currentPage = pagenumber;
01551         startindex = MAX_ITEMS_ON_ONE_PAGE * (pagenumber - 1);
01552 
01553         ctrl_select_stop(TRUE);
01554 
01555         // retrieve new page content
01556         mdsSetPageContent(theContentLister->items, startindex, &req_cnt);
01557 
01558         // update the stored index value
01559         mdsSetIndex(theContentLister->currentContentType, startindex);
01560 
01561         theContentLister->itemCount = req_cnt;
01562         theContentLister->currentFocus = 0;
01563         ctrl_display_item_view(theContentLister);
01564     }
01565     else
01566     {
01567         erbusy_off();
01568     }
01569 }
01570 
01571 
01572 int ctrl_goto_item(const gchar * szFilename)
01573 {
01574     CL_SCREENPRINTF("entry: filename [%s]", szFilename);
01575 
01576     int startindex;
01577     int req_cnt = MAX_ITEMS_ON_ONE_PAGE;
01578     ContentLister *theContentLister = gContentLister;
01579 
01580     // find index for specified file
01581     int index = mdsGetItemIndex(szFilename);
01582     if (index < 0)
01583     {
01584         CL_WARNPRINTF("Cannot find filename [%s]", szFilename);
01585         index = 0;
01586     }
01587     // display and select the specified file
01588     int pagenumber = (index / MAX_ITEMS_ON_ONE_PAGE) + 1;
01589     int pageindex = index % MAX_ITEMS_ON_ONE_PAGE;
01590     if ((pagenumber > 0) && (pagenumber <= theContentLister->pagecount))
01591     {
01592         // select the correct page
01593         theContentLister->currentPage = pagenumber;
01594         startindex = MAX_ITEMS_ON_ONE_PAGE * (pagenumber - 1);
01595 
01596         // retrieve new page content
01597         mdsSetPageContent(theContentLister->items, startindex, &req_cnt);
01598         theContentLister->itemCount = req_cnt;
01599 
01600         // select the correct item on this page
01601         g_assert(pageindex < theContentLister->itemCount);
01602         theContentLister->currentFocus = pageindex;
01603     }
01604     // and finally display this page
01605     ctrl_display_item_view(theContentLister);
01606     return 0;
01607 }
01608 
01609 static gboolean ctrl_main_window_expose_event(GtkWidget * widget, GdkEventExpose * event, ContentLister * theContentLister)
01610 {
01611     CL_SCREENPRINTF("entry");
01612 
01613     display_update_request_screen_refresh(MAIN_WINDOW_EXPOSE_LEVEL);
01614     return FALSE;
01615 }
01616 
01617 // an X window for this main window widget was created
01618 static void ctrl_main_window_realize_event(GtkWidget * widget, ContentLister * theContentLister)
01619 {
01620     Window xwin;
01621     static int count = 0;
01622 
01623     CL_SCREENPRINTF("entry");
01624 
01625     if (count == 0)
01626     {
01627         // init the program manager
01628         xwin = GDK_WINDOW_XID(widget->window);
01629         CL_SCREENPRINTF("Toplevel XWindow: 0x%x", (int)xwin);
01630 
01631         pm_SetMyWindow(xwin);
01632 
01633         count = 1;
01634     }
01635 }
01636 
01637 // rescan current contentype and dir,for application quited initiatively.
01638 void ctrl_rescan_current()
01639 {
01640     CL_CONTROLPRINTF("entry: currentError [%d]", gContentLister->currentError);
01641 
01642     if (gContentLister->currentError == ctrlNoError)
01643     {
01644         CL_CONTROLPRINTF("rescan folder only, current content type = %d", gContentLister->currentContentType);
01645         ctrl_scan_content(gContentLister, ctrlScanCurrent, NULL);
01646     }
01647 }
01648 
01649 
01650 void ctrl_contentType_button_clicked(st_ContentType_e theContentType)
01651 {
01652     ContentLister *theContentLister = gContentLister;
01653     clDisplayItem_t theItem;
01654     const gboolean cl_OnTop = (strcmp(pm_getUaOnTop(), CONTENTLISTER_UAID) == 0) ? TRUE : FALSE;
01655     const gboolean dm_OnTop = (strcmp(pm_getUaOnTop(), PROFILES_APP      ) == 0) ? TRUE : FALSE;
01656     char *location;
01657 
01658     // check whether contentlister is visible
01659     CL_CONTROLPRINTF("entry: theContentLister [%p] type [%d] UaOnTop [%s]", theContentLister, theContentType, pm_getUaOnTop());
01660     if ( !cl_OnTop )
01661     {
01662         // contentLister not "On Top" => scan current content and show contentlister 
01663         CL_CONTROLPRINTF("CL NOT on top - current type was = %d", theContentLister->currentContentType);
01664 
01665         theContentLister->previousContentType = theContentLister->currentContentType;
01666         theContentLister->currentContentType = theContentType;
01667         // change acording to design, do not record history
01668         stackClear(theContentType);
01669 
01670         pm_RaiseContentLister();
01671 
01672         if (dm_OnTop)
01673         {
01674             // This scan_content only needed after download manager,
01675             // because the sigchld handler already rescans (see programMgr.c)
01676             ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01677         }
01678     }
01679     else
01680     {
01681         // contentLister is "On Top"
01682         if (theContentType != theContentLister->currentContentType)
01683         {
01684             // contentLister "On Top" but different contentType => scan
01685             // new contentType 
01686             CL_CONTROLPRINTF
01687                 ("CL on top - current type (%d) != theContentType (%d)",
01688                  theContentLister->currentContentType, theContentType);
01689 
01690             if (getListerState() == STATE_MISC)
01691             {
01692                 ctrl_hide_misc_screen();
01693             }
01694             ctrl_select_stop(TRUE);
01695 
01696             theContentLister->previousContentType = theContentLister->currentContentType;
01697             theContentLister->currentContentType  = theContentType;
01698             // change acording to design, do not record history
01699             stackClear(theContentType);
01700 
01701             ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01702         }
01703         else if (theContentLister->currentError != ctrlNoError)
01704         {
01705             CL_CONTROLPRINTF("currentError %d", theContentLister->currentError);
01706             ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01707         }
01708         else if (g_select.active)
01709         {
01710             ctrl_select_stop(TRUE);
01711             toolbar_synchronise();
01712         }
01713         else if (getListerState() == STATE_MISC)
01714         {
01715             ctrl_hide_misc_screen();
01716         }
01717         else
01718         {
01719             CL_CONTROLPRINTF("CL on top - current type (%d) == theContentType", theContentLister->currentContentType);
01720 
01721             CL_HISTORYPRINTF("Goto last read content of the contentType %d", theContentType);
01722 
01723             hsGetItem(theContentType, &theItem);
01724             location = hsGetLocation(theContentType);
01725 
01726             CL_HISTORYPRINTF("hsGetLocation (for %d) returned %s",
01727                              theContentType, (location == NULL) ? "NULL" : location);
01728 
01729             if (ctrl_start_viewer(theContentLister->currentContentType, &theItem, location) == FALSE)
01730             {
01731                 CL_CONTROLPRINTF("ctrl_start_viewer returned FALSE");
01732                 ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01733             }
01734 
01735             if (location)
01736             {
01737                 g_free(location);
01738                 location = NULL;
01739             }
01740         }
01741     }
01742 }
01743 
01744 void ctrl_connect_button_clicked(void)
01745 {
01746     CL_LOGPRINTF("entry");
01747 
01748     // stop background connect, to avoid conflicts
01749     ctrl_disconnect_wait();
01750 
01751     // connect to iDS
01752     ctrl_connect(connectScrDownloadHistory, connect_manual);
01753 }
01754 
01755 void ctrl_connect(connectScr_e screen, e_ctrl_connect_reason_t reason)
01756 {
01757     CL_LOGPRINTF("entry: reason [%d]", reason);
01758 
01759     gboolean use_last_connected  = FALSE;
01760     gboolean background          = FALSE;
01761     gboolean content_only        = FALSE;
01762     gchar*   content_uuid        = NULL;
01763     gboolean from_pincode_screen = FALSE;
01764     gboolean force_ids           = FALSE;
01765     gboolean after_reboot        = FALSE;
01766 
01767     switch (reason)
01768     {
01769         case connect_manual:
01770             break;
01771         case connect_background:
01772             use_last_connected  = TRUE;
01773             background          = TRUE;
01774             content_only        = TRUE;
01775             break;
01776         case connect_from_pincode:
01777             use_last_connected  = TRUE;
01778             content_only        = TRUE;
01779             content_uuid        = "reset-pin-code";
01780             from_pincode_screen = TRUE;
01781             force_ids           = TRUE;
01782             break;
01783         case connect_after_reboot:
01784             use_last_connected  = TRUE;
01785             force_ids           = TRUE;
01786             after_reboot        = TRUE;
01787             break;
01788         case connect_timed_ids_with_sw:
01789             force_ids           = TRUE;
01790             break;
01791         case connect_timed_ids_content_only:
01792             content_only        = TRUE;
01793             force_ids           = TRUE;
01794             break;
01795         case connect_timed_ids_background:
01796             use_last_connected  = TRUE;
01797             background          = TRUE;
01798             content_only        = TRUE;
01799             force_ids           = TRUE;
01800             break;
01801         default:
01802             CL_ERRORPRINTF("Illegal reason [%d]", reason);
01803             return;
01804     }
01805 
01806     if (    gContentLister->currentError == ctrlNoError
01807          && connectStruct.state          == connectStateIdle )
01808     {
01809         // Show toolbar icon "connected"
01810         toolbar_setIconState(iconID_connect, iconState_selected);
01811 
01812         // Put contentlister on top
01813         if ( background )
01814         {
01815             toolbar_synchronise();
01816         }
01817         else
01818         {
01819             const char* UaOnTop = pm_getUaOnTop();
01820             CL_CONTROLPRINTF("UaOnTop = %s", UaOnTop);
01821             if ((strncmp(UaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0))
01822             {
01823                 // contentLister not "On Top" => show contentlister
01824                 CL_CONTROLPRINTF("CL NOT on top - current type was = %d", gContentLister->currentContentType);
01825                 pm_RaiseContentLister();
01826             }
01827             setListerState(STATE_DOWNLOADMGR);
01828             pm_setUaOnTop(PROFILES_APP);  // set connection mgr as application-on-top, so key events will be sent here
01829             toolbar_restore();
01830         }
01831 
01832         // Block USB connect while connectionMgr running
01833         erStopMSDiskApp();
01834 
01835         // Start the connectionMgr, 
01836         // who connects to the IDS server
01837         // end then starts the downloadMgr
01838         snprintf( connectStruct.szCommand,
01839                   sizeof(connectStruct.szCommand),
01840                   "%s%s%s%s%s%s%s%s",
01841                   CONNECTIONMGR_EXECUTABLE,
01842                   use_last_connected ? " --use-last-connected"   : "",
01843                   background         ? " --background"           : "",
01844                   content_only       ? " --content-only"         : "",
01845                   content_uuid       ? " --content-uuid "        : "",
01846                   content_uuid       ?   content_uuid            : "",
01847                   force_ids          ? " --connect-ids"          : "",
01848                   after_reboot       ? " --connect-after-reboot" : ""  );
01849 
01850         connectStruct.screen               = screen;
01851         connectStruct.background           = background;
01852         connectStruct.connect_from_pincode = from_pincode_screen;
01853         connectStruct.connect_after_reboot = after_reboot;
01854         connectStruct.command              = connectCmdStart;
01855         pthread_mutex_unlock( &(connectStruct.mutex) );
01856     }
01857     else
01858     {
01859         CL_SCREENPRINTF("cannot connect now");
01860         display_update_request_screen_refresh(MAIN_WINDOW_EXPOSE_LEVEL);
01861     }
01862 }
01863 
01864 void ctrl_disconnect(connectScr_e screen)
01865 {
01866     CL_LOGPRINTF("entry: screen [%d]", screen);
01867     
01868     if (connectStruct.state == connectStateConnected)
01869     {
01870         connectStruct.screen  = screen;
01871         connectStruct.command = connectCmdStop;
01872     }
01873 }
01874 
01875 void ctrl_disconnect_wait(void)
01876 {
01877     CL_LOGPRINTF("entry");
01878     
01879     ctrl_disconnect(connectStruct.screen);
01880 
01881     while (connectStruct.state != connectStateIdle)
01882     {
01883         CL_WARNPRINTF("Waiting for connectStateIdle [%d], current state [%d]", connectStateIdle, connectStruct.state);
01884         sleep(1);
01885     }
01886 }
01887 
01888 
01889 void ctrl_mode_button_long_clicked(void)
01890 {
01891     ctrl_display_recent_documents();
01892 }
01893 
01894 void ctrl_mode_button_clicked(void)
01895 {
01896     ContentLister *theContentLister = gContentLister;
01897     char *UaOnTop;
01898 
01899     CL_CONTROLPRINTF("entry 0x%x", (unsigned int)theContentLister);
01900 
01901     UaOnTop = pm_getUaOnTop();
01902 
01903     CL_CONTROLPRINTF("UaOnTop = %s", UaOnTop);
01904 
01905     if ((strncmp(UaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0))
01906     {
01907         // contentLister not "On Top" => scan mode directory content and
01908         // show contentlister 
01909         CL_CONTROLPRINTF("CL NOT on top");
01910         theContentLister->previousContentType = theContentLister->currentContentType;
01911         theContentLister->currentContentType = st_MenuTypeMode;
01912         // reset the st_MenuTypeMode stack
01913         stackClear(theContentLister->currentContentType);
01914 
01915         pm_RaiseContentLister();
01916 
01917         // Disabled this scan_content, because the signal handler already
01918         // rescans (see programMgr.c)
01919         // ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01920         CL_CONTROLPRINTF("Not scanning content, this will be done in the sigchld handler");
01921     }
01922     else
01923     {
01924         // contentLister "On Top" => scan new contentType 
01925         CL_CONTROLPRINTF("CL on top - current type (%d)", theContentLister->currentContentType);
01926 
01927         if ((theContentLister->currentError != ctrlNoError) && (stackIsStorage(theContentLister->currentContentType)))
01928         {
01929             CL_CONTROLPRINTF("Error screen for storage (%d)", theContentLister->currentContentType);
01930             ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01931         }
01932         else
01933         {
01934             // back to the mode menu 
01935             CL_CONTROLPRINTF("Back to mode menu");
01936             ctrl_hide_misc_screen();
01937             theContentLister->previousContentType = theContentLister->currentContentType;
01938             theContentLister->currentContentType = st_MenuTypeMode;
01939             // reset the st_MenuType1 stack
01940             stackClear(theContentLister->currentContentType);
01941             ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01942         }
01943     }
01944 }
01945 
01946 void ctrl_display_download_history()
01947 {
01948     ContentLister *theContentLister = gContentLister;
01949     char *UaOnTop;
01950 
01951     CL_CONTROLPRINTF("entry 0x%x", (unsigned int)theContentLister);
01952 
01953     // back to the download history menu 
01954     CL_CONTROLPRINTF("Back to the download history menu");
01955     theContentLister->previousContentType = theContentLister->currentContentType;
01956     theContentLister->currentContentType = st_DownloadHistory;
01957     if (g_new_content_received)
01958     {
01959         g_new_content_acknowledged = TRUE;
01960     }
01961 
01962     ctrl_cleanup_download_history();
01963 
01964     // reset the st_DownloadHistory stack
01965     stackClear(theContentLister->currentContentType);
01966     // always display the first page
01967     mdsSetIndex(theContentLister->currentContentType, 0);
01968     ctrl_scan_content(theContentLister, ctrlScanCurrent, NULL);
01969     UaOnTop = pm_getUaOnTop();
01970     CL_CONTROLPRINTF("UaOnTop = %s", UaOnTop);
01971     if ((strncmp(UaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0))
01972     {
01973         // contentLister not "On Top" => show contentlister 
01974         CL_CONTROLPRINTF("CL NOT on top");
01975         pm_RaiseContentLister();
01976     }
01977 }
01978 
01979 void ctrl_cleanup_download_history(void)
01980 {
01981     char   dirname[ERMDS_MAX_FILENAME_SIZE];
01982 
01983     if ( mdsGetRootLocation(st_DownloadHistory, dirname, sizeof(dirname)) > 0 )
01984     {
01985         // remove dangling symlinks
01986         hsCleanupSymlinks(dirname);
01987 
01988         // restrict the number of symlinks
01989         hsLimitSymlinks(dirname, MAX_DOWNLOAD_ITEMS);
01990     }
01991 }
01992 
01993 static void ctrl_start_application(gchar * szExtID, gchar* options)
01994 {
01995     // avoid conflict between profile-editor/settings and background connection
01996     if (   strcmp(szExtID, PROFILES_APP) == 0
01997         || strcmp(szExtID, SETUP_APP)    == 0 )
01998     {
01999         ctrl_disconnect_wait();
02000         toolbar_setIconState(iconID_connect, iconState_grey);
02001     }
02002 
02003     // start application
02004     if (pm_RunViewer(szExtID, NULL, NULL, options, 0) != ERR_OK)
02005     {
02006         CL_ERRORPRINTF("Error running application [%s]", szExtID);
02007         erbusy_off();
02008     }
02009 }
02010 
02011 // temp used routine thes values should come from ???? in the future
02012 static void ctrl_get_content_name(st_ContentType_e theType, char *name)
02013 {
02014     if (name)
02015     {
02016         switch (theType)
02017         {
02018             case st_ContentTypeBooks:
02019                 strcpy(name, _("Books"));
02020                 break;
02021             case st_ContentTypeNews:
02022                 strcpy(name, _("Newspapers"));
02023                 break;
02024             case st_ContentTypeDocs:
02025                 strcpy(name, _("Documents"));
02026                 break;
02027             case st_ContentTypeNotes:
02028                 strcpy(name, _("Notes"));
02029                 break;
02030             case st_StorageTypeCF:
02031                 strcpy(name, _("CF"));
02032                 break;
02033             case st_StorageTypeSD:
02034                 strcpy(name, _("MMC"));
02035                 break;
02036             case st_StorageTypeUSB:
02037                 strcpy(name, _("USB"));
02038                 break;
02039             case st_StorageTypeMain:
02040                 strcpy(name, _("Internal Memory"));
02041                 break;
02042             case st_MenuTypeMode:
02043                 strcpy(name, _("Device Manager"));
02044                 break;
02045             case st_DownloadHistory:
02046                 strcpy(name, _("Download History"));
02047                 break;
02048             case st_SearchResult:
02049                 strcpy(name, _("Search Results"));
02050                 break;
02051             case st_RecentDocuments:
02052                 strcpy(name, _("Recent Documents"));
02053                 break;
02054             default:
02055                 strcpy(name, _("Unknown"));
02056                 break;
02057         }
02058     }
02059 }
02060 
02061 
02062 listerState_t getListerState()
02063 {
02064     CL_CONTROLPRINTF("return [%d]", g_listerState);
02065     return g_listerState;
02066 }
02067 
02068 void setListerState(listerState_t newstate)
02069 {
02070     CL_CONTROLPRINTF("entry: state old [%d] new [%d]", g_listerState, newstate);
02071 
02072     // need to rescan if state changes from STATE_USB_CONNECTED to normal
02073     if (STATE_USB_CONNECTED == g_listerState && STATE_NORMAL == newstate)
02074     {
02075         // set new state and rescan
02076         g_listerState = newstate; // set new state before rescan (ref. BT 802)
02077         CL_CONTROLPRINTF("rescan after disconnected from PC");
02078         ctrl_scan_content(gContentLister, ctrlScanCurrent, 0);
02079     }
02080     else
02081     {
02082         g_listerState = newstate;
02083     }
02084 }
02085 
02086 void listerShowUSBScreen()
02087 {
02088     CL_CONTROLPRINTF("entry");
02089 
02090     if (get_exported_memory_type() == get_memory_type_used())
02091     {
02092         listerShowErrorScreen(ctrlConnectedUSBError);
02093     }
02094     else
02095     {
02096         listerShowErrorScreen(ctrlExportingDevUnavailError);
02097     }
02098 }
02099 
02100 void listerHideUSBScreen()
02101 {
02102     CL_CONTROLPRINTF("entry");
02103 
02104     if (gContentLister)
02105     {
02106         if (gContentLister->currentError == ctrlNoError)
02107         {
02108             listerHideErrorScreen();
02109         }
02110         else
02111         {
02112             listerShowErrorScreen(gContentLister->currentError);
02113         }
02114     }
02115 }
02116 
02117 void ctrl_hide_misc_screen()
02118 {
02119     CL_CONTROLPRINTF("entry");
02120 
02121     if (getListerState() == STATE_MISC)
02122     {
02123         ctrl_metadata_editor_close(FALSE);
02124         ctrl_hide_search_wnd();
02125         ctrl_hide_sort_wnd(FALSE);
02126         ctrl_hide_sel_list_wnd(gContentLister, FALSE);
02127     }
02128     else
02129     {
02130         ctrl_select_stop(TRUE);
02131     }
02132 }
02133 
02134 void ctrl_battery_low_screen(gint percentage, gint time_left, gboolean shutdown)
02135 {
02136     static int ignore_count = 0;
02137 
02138     CL_CONTROLPRINTF("entry: percentage [%d] time_left [%d]", percentage, time_left);
02139 
02140     // We don't do anything with the battery status at the moment...
02141 
02142     if (shutdown && g_errorTypeDisplayed == ctrlBatteryLowError)
02143     {
02144         ctrl_shutdown();
02145     }
02146     else if (   ctrl_is_connect_from_pincode()
02147              && ignore_count < 2               ) 
02148     {
02149         ignore_count++;
02150     }
02151     else
02152     {
02153         ignore_count = 0;
02154         listerShowErrorScreen(ctrlBatteryLowError);
02155     }
02156 }
02157 
02158 gboolean listerIsErrorScreenVisible()
02159 {
02160     gboolean ret = FALSE;
02161 
02162     if (gContentLister->errorScreen)
02163     {
02164         ret = GTK_WIDGET_VISIBLE(gContentLister->errorScreen);
02165     }
02166 
02167     CL_CONTROLPRINTF("return [%d]", ret);
02168     return ret;
02169 }
02170 
02171 void ctrl_usbmode_keypress(void)
02172 {
02173     CL_CONTROLPRINTF("entry");
02174 
02175     ctrl_errorScreen_buttonpress(NULL, NULL, gContentLister);
02176 }
02177 
02178 static guint ctrl_errorScreen_buttonpress(GtkWidget*      widget_notused,
02179                                           GdkEventButton* event_notused,
02180                                           ContentLister*  theContentLister_notused)
02181 {
02182     CL_CONTROLPRINTF("entry");
02183 
02184     if (   g_errorTypeDisplayed == ctrlConnectedUSBError
02185         || g_errorTypeDisplayed == ctrlSystemShutdownError )
02186     {
02187         CL_WARNPRINTF("Ignore button-press while USB or shutdown screen shown");
02188         return 1;               // TRUE => no further processing
02189     }
02190 
02191     erbusy_blink();
02192 
02193     if (g_shutdownPending && g_errorTypeDisplayed == ctrlBatteryLowError && is_battery_charging() == FALSE)
02194     {
02195         ctrl_shutdown();
02196     }
02197     else if (g_listerState == STATE_USB_CONNECTED)
02198     {
02199         listerShowErrorScreen(ctrlConnectedUSBError);
02200     }
02201     else
02202     {
02203         listerHideErrorScreen();
02204     }
02205 
02206     return 0;                   // FALSE => default GTK handling
02207 }
02208 
02209 
02210 gboolean idle_CheckBattery_HideErrorScreen(gpointer data)
02211 {
02212     if ( is_battery_charging() )
02213     {
02214         ctrl_errorScreen_buttonpress(NULL, NULL, NULL);
02215         g_idle_check_battery_id = 0;
02216         return FALSE;  // stop idle handler
02217     }
02218     else
02219     {
02220         return TRUE;  // continue idle handler
02221     }
02222 }
02223 
02224 // analyse current implemention:
02225 // 1.there's no way to show pincode screen when error screen is visible,
02226 //   for error screen is full and we have no automatic screen lock yet
02227 // 2.but it's possible to show error screen when pincode screen is visible
02228 // 3.and no way to change contentLister state when pincode screen is visible except users 
02229 //   press CONNECT LONG. for pincode is visible, no way to connect USB and no way to search or rename.
02230 //
02231 // how to deal with error screen together with pincode screen as below:
02232 // 1. in ctrl_shutdown, first ctrl_hide_pincode_screen, then listerShowErrorScreen()
02233 // 2. in listerShowErrorScreen, hide pincode screen before show error screen
02234 // 3. in listerHideErrorScreen, check if connect from pincode screen, if yes we set contentLister state to STATE_PINCODE 
02235 //    after that, check if contentLister state is STATE_PINCODE, if yes, back to pincode screen, otherwise show listerArea
02236 // 4. in button_handler, 
02237 //    if it's in download state, if launched connect from pincode, block all keys 
02238 //    if it's in pincode state, first hide error screen,  afterwards block all keys except CONNECT LONG or OVERVIEW
02239 //
02240 void listerShowErrorScreen(ctrlErrorType_e errorType)
02241 {
02242     char *UaOnTop;
02243 
02244     CL_SCREENPRINTF("entry: errorType [%d]", errorType);
02245 
02246     if (gContentLister)
02247     {
02248         toolbar_disableUpdate();
02249 
02250         // abort miscellaneous contentLister windows
02251         ctrl_hide_misc_screen();
02252         toolbar_setIconState(iconID_search,   iconState_grey);
02253         toolbar_setIconState(iconID_sort,     iconState_grey);
02254         toolbar_setIconState(iconID_share,    iconState_grey);
02255         toolbar_setIconState(iconID_tagging,  iconState_grey);
02256         toolbar_setIconState(iconID_trashcan, iconState_grey);
02257 
02258         // hide keyboard
02259         ctrl_hide_keyboard(iconState_grey);
02260         toolbar_enableUpdate();
02261 
02262         // bring contentlister on top
02263         UaOnTop = pm_getUaOnTop();
02264         strncpy(restoreUaOnTop, UaOnTop, sizeof(restoreUaOnTop));
02265         if ((strncmp(UaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0))
02266         {
02267             display_update_increase_level(NO_DISPLAY_UPDATE_LEVEL);
02268             CL_SCREENPRINTF("restoreUaOnTop=%s", restoreUaOnTop);
02269             pm_RaiseContentLister();
02270         }
02271 
02272         const char* card_name = NULL;
02273         char buf[ERROR_STRING_BUFLEN];
02274         switch (errorType)
02275         {
02276             case ctrlConnectedUSBError:
02277                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen), _("Connected to PC..."));
02278                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlDontDisconnectNWIcon);
02279                 break;
02280 
02281             case ctrlExportingDevUnavailError:
02282                 switch (get_exported_memory_type())
02283                 {
02284                     case expMMC:
02285                         card_name = _("MMC card");
02286                         break;
02287                     case expUSB:
02288                         card_name = _("USB stick");
02289                         break;
02290                     case expCF:
02291                         card_name = _("CF card");
02292                         break;
02293                     default:
02294                         break;
02295                 }
02296                 snprintf(buf, ERROR_STRING_BUFLEN, _("Connected to PC.\nThe %s storage is not available, Internal Memory is exported instead."), card_name);
02297 
02298                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen), buf);
02299                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlWarningIcon);
02300                 break;
02301 
02302             case ctrlBatteryLowError:
02303                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen),
02304                         _("Your battery is almost empty, please connect the power adapter to keep working."));
02305                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlBatteryLowIcon);
02306                 g_idle_check_battery_id = g_idle_add(idle_CheckBattery_HideErrorScreen, NULL);
02307                 break;
02308 
02309             case ctrlSystemShutdownError:
02310                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen),
02311                         _("The iLiad is preparing for power down."));
02312                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlSystemShutdownIcon);
02313                 break;
02314 
02315             case ctrlScanTooManyItemsError:
02316                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen),
02317                         _("There are too many items to display. Only the first 1000 items will be listed."));
02318                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlWarningIcon);
02319                 break;
02320 
02321             case ctrlScanFailedError:
02322                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen),
02323                         _("Reading of content has failed due to an unknown reason."));
02324                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlErrorIcon);
02325                 break;
02326 
02327             case ctrlContentNotAvailableError:
02328                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen),
02329                         _("Content isn't accessible any more."));
02330                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlInfoIcon);
02331                 break;
02332 
02333             case ctrlNoNetworkConfiguredError:
02334                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen),
02335                         _("No network configured."));
02336                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlErrorIcon);
02337                 break;
02338 
02339             default:
02340                 gtk_error_screen_set_text(GTK_ERROR_SCREEN(gContentLister->errorScreen),
02341                         _("An unknown event occurred."));
02342                 gtk_error_screen_set_image(GTK_ERROR_SCREEN(gContentLister->errorScreen), ctrlInfoIcon);
02343         }
02344         g_errorTypeDisplayed = errorType;
02345 
02346         if (listerIsErrorScreenVisible() == FALSE)
02347         {
02348             // => only request a refresh on the main window expose event
02349             CL_SCREENPRINTF("Display error screen");
02350             if (display_update_get_level() == NO_DISPLAY_UPDATE_LEVEL)
02351             {
02352                 display_update_decrease_level(MAIN_WINDOW_EXPOSE_LEVEL);
02353             }
02354             else
02355             {
02356                 display_update_increase_level(MAIN_WINDOW_EXPOSE_LEVEL);
02357             }
02358             gtk_window_fullscreen(GTK_WINDOW(gContentLister->topLevelWindow));
02359             gtk_widget_hide(GTK_WIDGET(gContentLister->listerScreen ));
02360             gtk_widget_show(GTK_WIDGET(gContentLister->errorScreen  ));
02361             gtk_widget_hide(GTK_WIDGET(gContentLister->pincodeScreen));
02362             gtk_widget_grab_focus(GTK_WIDGET(gContentLister->errorScreen));
02363         }
02364     }
02365 }
02366 
02367 void listerHideErrorScreen()
02368 {
02369     CL_CONTROLPRINTF("entry");
02370 
02371     if (gContentLister && listerIsErrorScreenVisible())
02372     {
02373         // hide error screen
02374         // => only request a refresh on the main window expose event
02375         CL_SCREENPRINTF("");
02376         display_update_increase_level(MAIN_WINDOW_EXPOSE_LEVEL);
02377         
02378         if (ctrl_is_connect_from_pincode())
02379         {
02380             setListerState(STATE_PINCODE);
02381         }
02382 
02383         if (STATE_PINCODE == getListerState())
02384         {
02385             CL_WARNPRINTF("hide error, show pincode");
02386             gtk_window_fullscreen(GTK_WINDOW(gContentLister->topLevelWindow));
02387             gtk_widget_hide(GTK_WIDGET(gContentLister->listerScreen ));
02388             gtk_widget_hide(GTK_WIDGET(gContentLister->errorScreen  ));
02389             gtk_widget_show(GTK_WIDGET(gContentLister->pincodeScreen));
02390             gtk_widget_grab_focus(GTK_WIDGET(gContentLister->pincodeScreen));
02391         }
02392         else
02393         {
02394             CL_WARNPRINTF("hide error, show listArea");
02395             gtk_window_unfullscreen(GTK_WINDOW(gContentLister->topLevelWindow));
02396             gtk_widget_show(GTK_WIDGET(gContentLister->listerScreen ));
02397             gtk_widget_hide(GTK_WIDGET(gContentLister->errorScreen  ));
02398             gtk_widget_hide(GTK_WIDGET(gContentLister->pincodeScreen));
02399             gtk_widget_grab_focus(GTK_WIDGET(gContentLister->listerArea));
02400         }
02401         g_errorTypeDisplayed = ctrlNoError;
02402         
02403         if ((strncmp(restoreUaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0))
02404         {
02405             pm_RaiseUserApp(restoreUaOnTop);
02406             strncpy(restoreUaOnTop, CONTENTLISTER_UAID, sizeof(restoreUaOnTop));
02407         }
02408 
02409         if (g_idle_check_battery_id > 0)
02410         {
02411             g_source_remove(g_idle_check_battery_id);
02412             g_idle_check_battery_id = 0;
02413         }
02414     }
02415 }
02416 
02417 
02419 //
02420 static void ctrl_select_stop(gboolean restore_toolbar)
02421 {
02422     int      i;
02423     gboolean selected;
02424 
02425     CL_CONTROLPRINTF("entry");
02426 
02427     if (g_select.active)
02428     {
02429         // stop time-out
02430         gtk_timeout_remove(g_select.timerID);
02431         g_select.active = FALSE;
02432 
02433         // hide all cursors, stop blink
02434         cursor_hide_all();
02435 
02436         if (restore_toolbar)
02437         {
02438             // if nothing selected show cursor on first item
02439             selected = FALSE;
02440             for (i = 0 ; !selected && i < MAX_ITEMS_ON_ONE_PAGE; i++)
02441             {
02442                 if (g_select.item_selected[i])
02443                 {
02444                     ctrl_listItem_focus_no_redraw(i, gContentLister);
02445                     selected = TRUE;
02446                 }
02447             }
02448             if ( !selected )
02449             {
02450                 ctrl_listItem_focus_no_redraw(0, gContentLister);
02451             }
02452 
02453             // update toolbar
02454             toolbar_disableUpdate();
02455             if ( ctrl_current_location_is_empty() )
02456             {
02457                 toolbar_setIconState(iconID_search,      iconState_grey);
02458                 toolbar_setIconState(iconID_sort,        iconState_grey);
02459                 toolbar_setIconState(iconID_share,       iconState_grey);
02460                 toolbar_setIconState(iconID_tagging,     iconState_grey);
02461                 toolbar_setIconState(iconID_trashcan,    iconState_grey);
02462             }
02463             else
02464             {
02465                 if (ctrl_current_location_is_outbox())
02466                 {
02467                     toolbar_setIconState(iconID_search,   iconState_grey  );
02468                     toolbar_setIconState(iconID_sort,     iconState_grey  );
02469                     toolbar_setIconState(iconID_share,    iconState_grey  );
02470                     toolbar_setIconState(iconID_tagging,  iconState_grey  );
02471                     toolbar_setIconState(iconID_trashcan, iconState_normal);
02472                 }
02473                 else
02474                 {
02475                     toolbar_setIconState(iconID_search,   iconState_normal);
02476                     toolbar_setIconState(iconID_sort,     iconState_normal);
02477                     toolbar_setIconState(iconID_share,    iconState_normal);
02478                     toolbar_setIconState(iconID_tagging,  iconState_normal);
02479                     toolbar_setIconState(iconID_trashcan, iconState_normal);
02480                 }
02481             }
02482             toolbar_enableUpdate();
02483             toolbar_synchronise();
02484         }
02485     }
02486 }
02487 
02488 static gboolean ctrl_on_select_timer(gpointer data)
02489 {
02490     int      i;
02491     int      item_idx[MAX_ITEMS_ON_ONE_PAGE + 1];
02492     int*     ip;
02493     gboolean item_selected = FALSE;
02494     gboolean call_me_again = FALSE;
02495 
02496     CL_CONTROLPRINTF("entry");
02497 
02498     if (g_select.active)
02499     {
02500         if (g_select.icon_clicked)
02501         {
02502             // listitem select procedure ends
02503             if (g_select.on_item_selected != NULL)
02504             {
02505                 // report the currently selected item(s)
02506                 ip = item_idx;
02507                 for (i = MAX_ITEMS_ON_ONE_PAGE - 1 ; i >= 0 ; i--)
02508                 {
02509                     if (g_select.item_selected[i])
02510                     {
02511                         item_selected = TRUE;
02512                         *ip = i;
02513                         ip++;
02514                     }
02515                 }
02516                 *ip = -1;
02517                 if (item_selected)
02518                 {
02519                     // start the registered function, i.e. callback function
02520                     g_select.on_item_selected(item_idx, gContentLister);
02521                     ctrl_select_stop(g_select.confirm_with_icon);
02522                 }
02523                 else
02524                 {
02525                     // no items selected: abort select mode
02526                     ctrl_select_stop(TRUE);
02527                     toolbar_synchronise();
02528                 }
02529             }
02530             else
02531             {
02532                 // no callback registered: abort select mode
02533                 ctrl_select_stop(TRUE);
02534                 toolbar_synchronise();
02535             }
02536         }
02537         else if (g_select.ticks > 0)
02538         {
02539             // decrement time-out counter
02540             g_select.ticks--;
02541             call_me_again = TRUE;
02542         }
02543         else
02544         {
02545             // abort select mode and show cursor at the top-most contentlister item
02546             ctrl_select_stop(TRUE);
02547             toolbar_synchronise();
02548         }
02549     }
02550 
02551     return call_me_again;
02552 }
02553 
02554 void ctrl_select_listitem(int iconID, gboolean confirm_with_icon, on_item_selected_t* callback_on_selected)
02555 {
02556     int i;
02557 
02558     CL_CONTROLPRINTF("entry: iconID [%d]", iconID);
02559     g_assert(callback_on_selected != NULL);
02560 
02561     // abort (background) connect, as this may interfere
02562     ctrl_disconnect_wait();
02563 
02564     // remember the settings
02565     g_select.iconID            = iconID;
02566     g_select.on_item_selected  = callback_on_selected;
02567     g_select.confirm_with_icon = confirm_with_icon;
02568 
02569     // update toolbar
02570     toolbar_disableUpdate();
02571     toolbar_setIconState(iconID_search,   iconState_grey);
02572     toolbar_setIconState(iconID_sort,     iconState_grey);
02573     toolbar_setIconState(iconID_share,    iconState_grey);
02574     toolbar_setIconState(iconID_tagging,  iconState_grey);
02575     toolbar_setIconState(iconID_trashcan, iconState_grey);
02576     toolbar_setIconState(iconID, iconState_selected);
02577     toolbar_enableUpdate();
02578     
02579     // de-select contentlister items
02580     ctrl_listItem_focus(-1, gContentLister);
02581     for (i = 0 ; i < MAX_ITEMS_ON_ONE_PAGE; i++)
02582     {
02583         g_select.item_selected[i] = FALSE;
02584     }
02585     
02586     // start time-out
02587     g_select.ticks        = ITEM_SELECT_TIMEOUT_TICKS;
02588     g_select.timerID      = g_timeout_add(500, ctrl_on_select_timer, 0);
02589     g_select.icon_clicked = FALSE;
02590     g_select.active       = TRUE;
02591 
02592     // update screen when toolbar icons ok
02593     toolbar_synchronise();
02594 }
02595 
02597 
02598 
02599 void ctrl_on_icon_clicked(int iconID, int iconState)
02600 {
02601     CL_TBPRINTF("entry: iconID [%d] iconState [%d]", iconID, iconState);
02602 
02603     if (   g_select.active
02604         && iconID    == g_select.iconID
02605         && iconState == iconState_selected)
02606     {
02607         // icon clicked again -> listitem select procedure ends
02608         // Note: ipc messages like toolbar icon clicked are received on a separate thread, therefore the current
02609         //       function is NOT called on the GTK thread, so the order of events cannot be guaranteed.
02610         //       More precisely: pen-click listitem, pen-click toolbar icon sometimes is received in the inverse order.
02611         //       To avoid these issues we set a flag, which is checked by the timer function who then ends the select.
02612         g_select.icon_clicked = TRUE;
02613     }
02614     else
02615     {
02616         // icon actions regardless the icon state
02617         switch (iconID)
02618         {
02619             case iconID_search:
02620                 ctrl_on_search_clicked(iconState);
02621                 break;
02622 
02623             case iconID_sort:
02624                 ctrl_on_sort_clicked(iconState);
02625                 break;
02626 
02627             case iconID_locked:
02628                 switch (iconState)
02629                 {
02630                     case iconState_normal:
02631                         toolbar_setIconState(iconID_locked, iconState_selected);
02632                         toolbar_synchronise();
02633                         break;
02634                     case iconState_selected:
02635                         toolbar_setIconState(iconID_locked, iconState_normal);
02636                         toolbar_synchronise();
02637                         break;
02638                     case iconState_grey:
02639                         // ignore
02640                         break;
02641                     default:
02642                         CL_ERRORPRINTF("iconID_locked: state [%d] unknown", iconState);
02643                 }
02644                 break;
02645 
02646             case iconID_lock_screen:
02647                 ctrl_on_lock_screen_clicked(iconState);
02648                 break;
02649 
02650             case iconID_connect:
02651                 switch (iconState)
02652                 {
02653                     case iconState_normal:
02654                     case iconState_IDconnect_time:
02655                         ctrl_background_connect_timeout_start_withinterval(FALSE, TRUE, 0);
02656                         break;
02657                     case iconState_selected:
02658                         ctrl_disconnect(connectScrUnchanged);
02659                         break;
02660                     case iconState_IDconnect_newcontent:
02661                         ctrl_display_download_history();
02662                         break;
02663                     case iconState_IDconnect_newcontent_selected:
02664                         g_new_content_received = FALSE;
02665                         ctrl_set_connect_icon();
02666                         toolbar_synchronise();
02667                         break;
02668                     default:
02669                         CL_ERRORPRINTF("iconID_connect state [%d] unknown", iconState);
02670                 }
02671                 break;
02672 
02673             default:
02674                 break; //ignore
02675         }
02676 
02677         // icon actions for icon state normal
02678         if (iconState == iconState_normal)
02679         {
02680             switch (iconID)
02681             {
02682                 case iconID_share:
02683                     ctrl_select_listitem(iconID_share, FALSE, ctrl_listItem_share);
02684                     break;
02685 
02686                 case iconID_tagging:
02687                     ctrl_select_listitem(iconID_tagging, FALSE, ctrl_listItem_edit);
02688                     break;
02689                 
02690                 case iconID_trashcan:
02691                     ctrl_select_listitem(iconID_trashcan, TRUE, ctrl_listItem_delete);
02692                     break;
02693 
02694                 default:
02695                     break;  // ignore
02696             }
02697         }
02698 
02699         // icon actions for icon state selected
02700         if (iconState == iconState_selected)
02701         {
02702             switch (iconID)
02703             {
02704                 case iconID_share:
02705                     ctrl_doc_share_now(gContentLister);
02706                     break;
02707 
02708                 case iconID_tagging:
02709                     ctrl_metadata_editor_close(TRUE);
02710                     break;
02711 
02712                 default:
02713                     break;  // ignore
02714             }
02715         }
02716     }
02717 }
02718 
02719 
02720 static void ctrl_add_on_toolbar_sync_action(on_tbsync_action_t action)
02721 {
02722     int i;
02723 
02724     CL_LOGPRINTF("entry");
02725     g_assert(action != NULL);
02726 
02727     for (i = 0; i < sizeof(on_toolbar_sync_actions) / sizeof(on_toolbar_sync_actions[0]); i++)
02728     {
02729         if (on_toolbar_sync_actions[i] == NULL)
02730         {
02731             on_toolbar_sync_actions[i] = action;
02732             return;
02733         }
02734     }
02735 
02736     g_assert_not_reached();
02737 }
02738 
02739 void ctrl_on_toolbar_synchronised()
02740 {
02741     int i;
02742 
02743     CL_IPCPRINTF("entry");
02744 
02745     display_update_request_screen_refresh(TOOLBAR_UPDATE_LEVEL);
02746 
02747     // call functions for registered on_toolbar_sync_actions
02748     for (i = 0; i < sizeof(on_toolbar_sync_actions) / sizeof(on_toolbar_sync_actions[0]); i++)
02749     {
02750         if (on_toolbar_sync_actions[i] != NULL)
02751         {
02752             on_toolbar_sync_actions[i] ();
02753             on_toolbar_sync_actions[i] = NULL;
02754         }
02755     }
02756 }
02757 
02758 void ctrl_show_lister_area(void)
02759 {
02760     if (gContentLister->listerArea)
02761     {
02762         gtk_widget_show(gContentLister->listerArea);
02763     }
02764 }
02765 
02766 void ctrl_hide_lister_area(void)
02767 {
02768     if (gContentLister->listerArea)
02769     {
02770         gtk_widget_hide(gContentLister->listerArea);
02771     }
02772 }
02773 
02774 
02775 // ////////////////////////////////////////////////////////////////////////
02776 // keyboard handling
02777 
02778 // show keyboard:
02779 // wait for GTK objects updated then show keyboard
02780 // block display updates while updating GTK objects, rely on keyboard
02781 // display update
02782 static void ctrl_show_keyboard()
02783 {
02784     erbusy_blink();
02785 
02786     // block screen updates until keyboard shows
02787     display_update_increase_level(KEYBOARD_SHOW_HIDE_LEVEL);
02788 
02789     // update GTK objects then show keyboard, rely on display update by
02790     // keyboard
02791     g_idle_add(ctrl_on_idle_show_keyboard, NULL);
02792 }
02793 
02794 static gboolean ctrl_on_idle_show_keyboard(gpointer data)
02795 {
02796     // request keyboard but first disable keyboard,
02797     // this makes sure the keyboard (re-)appears and does a display update
02798     toolbar_setIconState(iconID_keyboard, iconState_normal);
02799     toolbar_setIconState(iconID_keyboard, iconState_selected);
02800 
02801     // allow display updates again
02802     display_update_decrease_level(LOWEST_LEVEL);
02803 
02804     return FALSE;  // don't call me again
02805 }
02806 
02807 // hide keyboard:
02808 // wait for GTK objects updated then show keyboard
02809 // block display updates while updating GTK objects, rely on keyboard
02810 // display update
02811 static void ctrl_hide_keyboard(int iconState)
02812 {
02813     g_assert((iconState == iconState_grey) || (iconState == iconState_normal));
02814 
02815     erbusy_blink();
02816 
02817     // block screen updates until keyboard hides
02818     display_update_increase_level(KEYBOARD_SHOW_HIDE_LEVEL);
02819 
02820     // update GTK objects then hide keyboard, rely on display update by
02821     // keyboard
02822     g_idle_add(ctrl_on_idle_hide_keyboard, (gpointer) iconState);
02823 }
02824 
02825 static gboolean ctrl_on_idle_hide_keyboard(gpointer data)
02826 {
02827     int iconState = (int)data;
02828 
02829     // hide keyboard but first show keyboard,
02830     // this makes sure the keyboard (re-)disappears and does a display
02831     // update
02832     toolbar_setIconState(iconID_keyboard, iconState_selected);
02833     toolbar_setIconState(iconID_keyboard, iconState);
02834 
02835     display_update_request_screen_refresh(KEYBOARD_SHOW_HIDE_LEVEL);
02836 
02837     return FALSE;  // don't call me again
02838 }
02839 
02840 
02841 // ////////////////////////////////////////////////////////////////////////
02842 // for content metadata editor
02843 
02844 // close metadata edtior, save them if bSave == TRUE
02845 // otherwise ignore change
02846 static void ctrl_metadata_editor_close(gboolean bSave)
02847 {
02848     CL_CONTROLPRINTF("entry");
02849 
02850     gchar szContainerDir[ERMDS_MAX_FILENAME_SIZE];
02851 
02852     if ( (getListerState() == STATE_MISC) 
02853           && (gContentLister->contentEditWnd)
02854           && GTK_WIDGET_VISIBLE(gContentLister->contentEditWnd) )
02855     {
02856         erbusy_blink();
02857         ctrl_hide_keyboard(iconState_grey);
02858 
02859         // store modified metadata
02860         if (bSave)
02861         {
02862             // rename container as needed
02863             content_metadata_rename_container(g_md_editor_mgr.item->szManifest, szContainerDir, sizeof(szContainerDir));
02864 
02865             // update manifest file
02866             content_metadata_write_manifest(szContainerDir);
02867 
02868             // show updated item on screen
02869             ctrl_rescan_current();
02870             ctrl_goto_item(szContainerDir);
02871 
02872             // update the stored index value
02873             int itemIndex = ctrl_get_item_index(gContentLister);
02874             mdsSetIndex(gContentLister->currentContentType, itemIndex);
02875         }
02876         else
02877         {
02878             // re-display all items
02879             ctrl_rescan_current();
02880         }
02881 
02882         // show contentlister page
02883         gtk_widget_hide(GTK_WIDGET(gContentLister->contentEditWnd));
02884         gtk_widget_grab_focus(GTK_WIDGET(gContentLister->listerArea));
02885         setListerState(STATE_NORMAL);
02886 
02887         toolbar_synchronise();
02888     }
02889 
02890     CL_CONTROLPRINTF("leave");
02891 }
02892 
02893 // edit content attributes
02894 static void ctrl_listItem_edit(const int* index_tbl, ContentLister* theContentLister)
02895 {
02896     const int  index = *index_tbl;  // only one item expected
02897 
02898     CL_CONTROLPRINTF("entry");
02899 
02900     if (getListerState() == STATE_MISC)
02901     {
02902         // already editing an item: ignore
02903         return;
02904     }
02905 
02906     clDisplayItem_t *theItem = &theContentLister->items[index];
02907     if (theItem->modifyEnable.bTagging == FALSE)
02908     {
02909         CL_WARNPRINTF("Rename disabled by manifest: item [%s]", theItem->szFilename);
02910         goto error_exit;
02911     }
02912 
02913     // check current item state 
02914     switch (theItem->fit)
02915     {
02916         case mdsFitFile:
02917             CL_CONTROLPRINTF("File [%s]", theItem->szFilename);
02918             int i = ctrl_before_file_clicked(theItem);  // create manifest file for it
02919             if (i != 0)
02920             {
02921                 CL_ERRORPRINTF("ctrl_before_file_clicked failed for [%s]", theItem->szFilename);
02922                 toolbar_setIconState(iconID_tagging, iconState_normal);
02923                 toolbar_synchronise();
02924                 return;
02925             }
02926             break;
02927 
02928         case mdsFitContainer:
02929             CL_CONTROLPRINTF("Container [%s]", theItem->szFilename);
02930             break;
02931 
02932         case mdsFitFolder:
02933         case mdsFitApplication:
02934         case mdsFitManifestDirectory:
02935         case mdsFitStorage:
02936         default:
02937             CL_WARNPRINTF("Cannot rename item [%s]", theItem->szFilename);
02938             goto error_exit;
02939     }
02940 
02941     // update toolbar, show keyboard
02942     toolbar_setIconState(iconID_tagging, iconState_selected);
02943     ctrl_show_keyboard();
02944 
02945     // remember the item we are editing
02946     g_md_editor_mgr.item = &(theContentLister->items[index]);
02947 
02948     // get manifest data
02949     content_metadata_read_manifest(theItem->szManifest);
02950 
02951     // update pagebar. maybe it should be moved into gtkMetadataWnd, multi 
02952     // pages? 
02953     pagebar_set_pagecount(1);
02954     pagebar_goto_page(1);
02955     pagebar_redraw();
02956 
02957     // hide not-selected lister items, then show edit screen
02958     int i;
02959     GtkWidget *listItem;
02960     for (i = 0; i < MAX_ITEMS_ON_ONE_PAGE; i++)
02961     {
02962         if (i != index)
02963         {
02964             listItem = lsGetListerItem(theContentLister->lister, i);
02965             gtk_widget_hide(listItem);
02966         }
02967     }
02968     gtk_widget_show(GTK_WIDGET(theContentLister->contentEditWnd));
02969 
02970     // remember contentLister state
02971     setListerState(STATE_MISC);
02972     return;
02973 
02974 error_exit:
02975     ctrl_select_stop(TRUE);
02976     return;
02977 }
02978 
02979 
02980 // ////////////////////////////////////////////////////////////////////////
02981 // for searching
02982 // 
02983 void ctrl_show_search_wnd_trigger(void)
02984 {
02985     g_timeout_add(500, ctrl_show_search_wnd, NULL);
02986 }
02987 
02988 static gboolean ctrl_show_search_wnd(gpointer data)
02989 {
02990     gboolean nRet = FALSE;      // don't me call again
02991 
02992     CL_SEARCHPRINTF("entry");
02993 
02994     if (getListerState() == STATE_MISC)
02995     {
02996         // already searching: ignore
02997         return nRet;
02998     }
02999     // update state and ui
03000     erbusy_blink();
03001     setListerState(STATE_MISC);
03002 
03003     // update toolbar, show keyboard
03004     toolbar_disableUpdate();
03005     toolbar_setIconState(iconID_search,   iconState_selected);
03006     toolbar_setIconState(iconID_sort,     iconState_grey    );
03007     toolbar_setIconState(iconID_share,    iconState_grey    );
03008     toolbar_setIconState(iconID_tagging,  iconState_grey    );
03009     toolbar_setIconState(iconID_trashcan, iconState_grey    );
03010     ctrl_show_keyboard();
03011     toolbar_enableUpdate();
03012 
03013     // update pagebar. maybe it should be moved into gtkSearchWnd, multi
03014     // pages? 
03015     pagebar_set_pagecount(1);
03016     pagebar_goto_page(1);
03017     pagebar_redraw();
03018 
03019     // hide lister items, then show edit screen
03020     int i;
03021     GtkWidget *listItem;
03022     for (i = 0; i < MAX_ITEMS_ON_ONE_PAGE; i++)
03023     {
03024         listItem = lsGetListerItem(gContentLister->lister, i);
03025         gtk_widget_hide(listItem);
03026     }
03027     gtk_widget_show(GTK_WIDGET(gContentLister->searchWnd));
03028 
03029     return nRet;
03030 }
03031 
03032 void ctrl_hide_search_wnd(void)
03033 {
03034     CL_SEARCHPRINTF("entry");
03035 
03036     if ( (getListerState() == STATE_MISC) 
03037          && (gContentLister->searchWnd)
03038          && GTK_WIDGET_VISIBLE(gContentLister->searchWnd) )
03039     {
03040         // update toolbar, hide keyboard
03041         toolbar_disableUpdate();
03042         toolbar_setIconState(iconID_search,   iconState_normal);
03043         toolbar_setIconState(iconID_sort,     iconState_normal);
03044         toolbar_setIconState(iconID_share,    iconState_normal);
03045         toolbar_setIconState(iconID_tagging,  iconState_normal);
03046         toolbar_setIconState(iconID_trashcan, iconState_normal);
03047         ctrl_hide_keyboard(iconState_grey);
03048         toolbar_enableUpdate();
03049 
03050         // show contentlister page
03051         gtk_widget_hide(GTK_WIDGET(gContentLister->searchWnd));
03052         gtk_widget_grab_focus(GTK_WIDGET(gContentLister->listerArea));
03053         setListerState(STATE_NORMAL);
03054         ctrl_rescan_current();
03055     }
03056 }
03057 
03058 void ctrl_on_search_clicked(int iconState)
03059 {
03060     switch (iconState)
03061     {
03062         case iconState_normal:
03063             if (getListerState() == STATE_NORMAL)
03064             {
03065                 // de-select contentlister items
03066                 ctrl_listItem_focus(-1, gContentLister);
03067 
03068                 // update toolbar, show search window after toolbar updated
03069                 toolbar_disableUpdate();
03070                 toolbar_setIconState(iconID_search,   iconState_selected);
03071                 toolbar_setIconState(iconID_sort,     iconState_grey    );
03072                 toolbar_setIconState(iconID_share,    iconState_grey    );
03073                 toolbar_setIconState(iconID_tagging,  iconState_grey    );
03074                 toolbar_setIconState(iconID_trashcan, iconState_grey    );
03075                 ctrl_add_on_toolbar_sync_action(ctrl_show_search_wnd_trigger);
03076                 toolbar_enableUpdate();
03077                 toolbar_synchronise();
03078             }
03079             break;
03080 
03081         case iconState_selected:
03082             ctrl_hide_search_wnd();
03083             break;
03084 
03085         default:
03086             /*
03087              * ignore 
03088              */ ;
03089     }
03090 }
03091 
03092 void ctrl_display_search_result()
03093 {
03094     CL_SEARCHPRINTF("entry");
03095 
03096     gContentLister->previousContentType = gContentLister->currentContentType;
03097     gContentLister->currentContentType = st_SearchResult;
03098 
03099     // reset the st_SearchResult stack, always display the first page
03100     stackClear(gContentLister->currentContentType);
03101     mdsSetIndex(gContentLister->currentContentType, 0);
03102     ctrl_scan_content(gContentLister, ctrlScanCurrent, NULL);
03103 
03104     char *UaOnTop = pm_getUaOnTop();
03105     CL_SEARCHPRINTF("UaOnTop = %s", UaOnTop);
03106     if ((strncmp(UaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0))
03107     {
03108         // contentLister not "On Top" => show contentlister 
03109         CL_SEARCHPRINTF("CL NOT on top");
03110         pm_RaiseContentLister();
03111     }
03112 }
03113 
03114 // //////////////end searching///////////////////////////////////////////
03115 
03116 
03117 // internal helper function
03118 gboolean ctrl_file_exist(const char *pathName)
03119 {
03120     struct stat statbuf;
03121     if (0 != stat(pathName, &statbuf))
03122     {
03123         return FALSE;
03124     }
03125     return TRUE;
03126 }
03127 
03128 // Called before a file item is to be clicked. 
03129 // Change a simple file to a container
03130 // 1. retrieve extension name, file name and dir name from item
03131 // 2. check extension
03132 // 3. create dir if necessary
03133 // 4. create default manifest file for it.
03134 // 5. change item to mdsFitContainer
03135 // 2006-2008-07-27. dir name is changed, use filename as dirname
03136 int ctrl_before_file_clicked(clDisplayItem_t * theItem)
03137 {
03138     CL_LOGPRINTF("entry: szFilename [%s] szFileExt [%s]", theItem->szFilename, theItem->szFileExt);
03139 
03140     int ret = -1;               // -1 = error, 0 = ok
03141 
03142     if (strlen(theItem->szFilename) >= ERMDS_MAX_FILENAME_SIZE)
03143     {
03144         CL_ERRORPRINTF("Filename too long: [%s]", theItem->szFilename);
03145         return ret;
03146     }
03147 
03148     // maximum tries for file rename, arbitary value
03149     static const int MAX_COUNT = 5;
03150     char * viewer_id;
03151 
03152     int  i;
03153     char dirname [    ERMDS_MAX_FILENAME_SIZE            ];
03154     char filename[    ERMDS_MAX_FILENAME_SIZE            ];
03155     char tmp_file[    ERMDS_MAX_FILENAME_SIZE + MAX_COUNT];
03156     char new_dir [    ERMDS_MAX_FILENAME_SIZE            ];
03157     char new_file[2 * ERMDS_MAX_FILENAME_SIZE            ];
03158     char new_fil2[    ERMDS_MAX_FILENAME_SIZE            ];
03159 
03160     // 1. get extname, filename and dirname    
03161     char *name      = strrchr(theItem->szFilename, '/');
03162     char *extension = theItem->szFileExt;    
03163     if (name == NULL  || extension == NULL  || strlen(name) <= strlen(extension))
03164     {
03165         // it must be a fatal error, ignore this file
03166         CL_ERRORPRINTF("No extension or file name error!");
03167         return ret;
03168     }
03169     name++;
03170 
03171     i = strlen(theItem->szFilename) - strlen(name);
03172     strncpy(dirname, theItem->szFilename, i);
03173     dirname[i] = '\0';
03174 
03175     // verify if the path is trusted, otherwise we will *not* create the
03176     // manifest
03177     if (ctrl_is_trusted_path(dirname) == NULL)
03178     {
03179         CL_ERRORPRINTF("The fully qualified path [%s] is not trusted, not creating manifest", dirname);
03180         return ret;
03181     }
03182 
03183     // check if for this path we cannot create manifest folders
03184     if (ctrl_not_create_manifest(dirname))
03185     {
03186         CL_ERRORPRINTF("Configured to not create manifest folder for [%s]", dirname);
03187         return ret;
03188     }
03189 
03190     strcpy(filename, name);     // including extension
03191 
03192     // 2. check. we only handle the file we can handle
03193     if (!ctrl_check_extension(extension))
03194     {
03195         CL_ERRORPRINTF("Invalid extension: [%s]", extension);
03196         return ret;
03197     }
03198     
03199     // 3. create directory and move file if needed
03200     // Determine new directory and filename
03201     sprintf(new_dir,  "%s%s",    dirname, filename);
03202     sprintf(new_file, "%s%s/%s", dirname, filename, filename);
03203     if (strlen(new_file) >= ERMDS_MAX_FILENAME_SIZE)
03204     {
03205         CL_ERRORPRINTF("Filename too long to make it a container: [%s]", theItem->szFilename);
03206         return ret;
03207     }
03208     // before we create the dir, we need to change the file name
03209     // otherwise the dir will not be created successfully
03210     strcpy(tmp_file, theItem->szFilename);
03211     for(i = 0; i < MAX_COUNT; ++i)
03212     {
03213         strcat(tmp_file, "_");
03214         if (!ctrl_file_exist(tmp_file))
03215         {
03216             rename(theItem->szFilename, tmp_file);
03217             break;
03218         }
03219     }
03220     if (MAX_COUNT == i)
03221     {
03222         // could not change filename
03223         CL_ERRORPRINTF("Could not change name to %s", tmp_file);
03224         return ret;
03225     }
03226     //
03227     // create dir now                
03228     if (0 != mkdir(new_dir, 0755))
03229     {
03230         CL_ERRORPRINTF("Can not create directory for this content!");             
03231         rename(tmp_file, theItem->szFilename);
03232         return ret;
03233     }
03234     if (0 != rename(tmp_file, new_file))
03235     {
03236         // restore the file name and remove dir
03237         rmdir(new_dir);
03238         rename(tmp_file, theItem->szFilename);
03239         CL_ERRORPRINTF("Can not move file!");             
03240         return ret;
03241     }
03242 
03243     // if this is Mobipocket, check if there is a *.mbp file with the same name
03244     viewer_id = pm_getUaID(extension);
03245     if (viewer_id  &&  strcmp(viewer_id, "MOBIPOCKET") == 0)
03246     {
03247         struct stat file_stat;
03248 
03249         // strip extension
03250         char * tmp;
03251         char * fname = strdup(filename);
03252         tmp = strrchr(fname, '.');
03253         if (tmp) *tmp = '\0';
03254 
03255         snprintf(tmp_file, sizeof(tmp_file), "%s%s.%s", dirname, fname, "mbp");
03256         snprintf(new_fil2, sizeof(new_fil2), "%s%s/%s.%s", dirname, filename, fname, "mbp");
03257         free(fname);
03258         if (stat(tmp_file, &file_stat) == 0 && S_ISREG(file_stat.st_mode))
03259         {
03260             CL_CONTROLPRINTF("Going to rename %s to %s", tmp_file, new_fil2);
03261             if (rename(tmp_file, new_fil2) != 0)
03262             {
03263                 unlink(tmp_file);
03264                 CL_ERRORPRINTF("Could not move %s, deleted it instead!", tmp_file);
03265             }
03266         }
03267     }
03268         
03269     // update the file name, so that it can be open successfully
03270     strncpy(theItem->szFilename, new_file, ERMDS_MAX_FILENAME_SIZE);
03271     
03272     // 4. create the manifest file 
03273     ctrl_create_manifest(theItem, new_dir, filename);
03274     
03275     // 5. change item to mdsFitContainer
03276     theItem->fit = mdsFitContainer;
03277 
03278     ret = 0;
03279     return ret;
03280 }
03281 
03282 
03283 gboolean ctrl_check_extension(const char *extension)
03284 {
03285     // for the following file, we can handle them directly. temp solution
03286     static const char *ext_table[] = {
03287         "pdf",
03288         "xeb",
03289         "eba",
03290         "prc",
03291         "pdb",
03292         "mobi"
03293     };
03294 
03295     const int size = sizeof(ext_table) / sizeof(ext_table[0]);
03296 
03297     int i = 0;
03298     for (; i < size; ++i)
03299     {
03300         if (0 == strcasecmp(extension, ext_table[i]))
03301             return TRUE;
03302     }
03303     return FALSE;
03304 }
03305 
03306 // create a default manifest file for the item.
03307 // if necessary, this function can be moved into ermanifest lib.
03308 // read information from system register
03309 // get type from ext
03310 // get icon from ext
03311 // get .... from ext
03312 gboolean ctrl_create_manifest(clDisplayItem_t * theItem, const char *dir, const char *name)
03313 {
03314     char pathName[ERMDS_MAX_FILENAME_SIZE] = {0};
03315         
03316     // remember manifest name
03317     int  nPathLength = g_snprintf(pathName, ERMDS_MAX_FILENAME_SIZE, "%s/" MANIFEST_FILENAME, dir);
03318     if (nPathLength > ERMDS_MAX_FILENAME_SIZE)
03319     {
03320         CL_ERRORPRINTF("manifest path name is too long: %d\n", nPathLength);
03321         return FALSE;
03322     }
03323     strcpy(theItem->szManifest, pathName);
03324 
03325     // call lib/ermanifest to create a xml file
03326     erManifest manifest;
03327     int ret = RET_ERR;
03328     ret = ermXmlCreateManifest(dir, &manifest);
03329     if (ret == RET_ERR)
03330     {
03331         CL_ERRORPRINTF("Could not create xml manifest file!\n");
03332         return FALSE;
03333     }
03334 
03335     ermXmlNewString(&manifest, "/", "package", "");
03336     ermXmlNewString(&manifest, "/package", "metadata", "");
03337 
03338     // dc-metadata
03339     ermXmlNewString(&manifest, "/package/metadata", "dc-metadata", "");
03340     ermXmlNewString(&manifest, "/package/metadata/dc-metadata", "Title", name);
03341     ermXmlNewString(&manifest, "/package/metadata/dc-metadata", "Description", "");
03342     ermXmlNewString(&manifest, "/package/metadata/dc-metadata", "Date", theItem->szDate);
03343 
03344     // y-metadata 
03345     ermXmlNewString(&manifest, "/package/metadata", "y-metadata", "");
03346 
03347     // startpage serves as an entry point for app.
03348     ermXmlNewString(&manifest, "/package/metadata/y-metadata", "startpage", name);
03349 
03350     ermXmlNewString(&manifest, "/package/metadata/y-metadata", "version", "000");
03351 
03352     // save
03353     ermXmlSaveAndClose(&manifest);
03354 
03355     return TRUE;
03356 }
03357 
03358 // Check to see if this folder is an exception to the rule of moving
03359 // files into a manifest folder. 
03360 // If this function returns TRUE, a manifest folder is not created.
03361 static gboolean ctrl_not_create_manifest(const char *path)
03362 {
03363     int i;
03364 
03365     // Folders that can be matched.
03366     // Must be full path names _including_ trailing slash
03367     static const char *path_table[] = {
03368         "/mnt/free"   MOBIPOCKET_FOLDER "/",
03369         "/mnt/cf"     MOBIPOCKET_FOLDER "/",
03370         "/media/card" MOBIPOCKET_FOLDER "/",
03371         "/mnt/usb"    MOBIPOCKET_FOLDER "/"
03372     };
03373 
03374     const int size = sizeof(path_table) / sizeof(path_table[0]);
03375 
03376     for (i = 0; i < size; i++)
03377     {
03378         if (strcasecmp(path, path_table[i]) == 0)
03379             return TRUE;
03380     }
03381     return FALSE;
03382 }
03383 
03384 void ctrl_shutdown()
03385 {
03386     CL_WARNPRINTF("entry");
03387 
03388     g_shutdownPending = TRUE;
03389 
03390     // keep busy led on
03391     erbusy_shutdown();
03392 
03393     // block all keys
03394     button_block_all_keys(TRUE);
03395     
03396     // hide pincode screen
03397     ctrl_hide_pincode_screen();
03398 
03399     // show a "System will shutdown now message"
03400     listerShowErrorScreen(ctrlSystemShutdownError);
03401 
03402     // store last view content logging data before killing the
03403     // contentLister process
03404     ctrlDestroy(gContentLister);
03405 
03406     // re-create RTC alarm if needed
03407     timed_ids_final();
03408 
03409     // stop usb export of filesystem
03410     erStopMSDiskApp();
03411 
03412     // and stop the system
03413     system("halt");
03414 
03415     CL_WARNPRINTF("end");
03416 }
03417 
03418 // show location information 
03419 const char *ctrl_get_current_location(ContentLister * theContentLister)
03420 {
03421     CL_CONTROLPRINTF("entry: contentType [%d]", theContentLister->currentContentType);
03422 
03423     char root[ERMDS_MAX_FILENAME_SIZE] = { 0 };
03424     if (0 >= mdsGetRootLocation(theContentLister->currentContentType, root, ERMDS_MAX_FILENAME_SIZE))
03425     {
03426         return NULL;
03427     }
03428 
03429     stItem_t *pItem = stackPeek(theContentLister->currentContentType);
03430     if (NULL == pItem)
03431     {
03432         // no stack item -> report top directory
03433         return "";
03434     }
03435     else
03436     {
03437         // stack item found -> report its path
03438         mdsDirectory_t *directory = &g_array_index(pItem->dirArray, mdsDirectory_t, 0);
03439         if (directory)
03440         {
03441             if (strstr(directory->szFilename, root))
03442             {
03443                 return (directory->szFilename + strlen(root));
03444             }
03445         }
03446     }
03447     return NULL;
03448 }
03449 
03450 // show absolute current location information 
03451 const char *ctrl_get_abscurr_location(char *sPath, int iSize)
03452 {
03453     memset(sPath, 0, iSize);
03454     if (0 >= mdsGetRootLocation(gContentLister->currentContentType, sPath, iSize))
03455     {
03456         return sPath;
03457     }
03458 
03459     stItem_t *pItem = stackPeek(gContentLister->currentContentType);
03460     if (NULL != pItem)
03461     {
03462         mdsDirectory_t *directory = &g_array_index(pItem->dirArray, mdsDirectory_t, 0);
03463         if (directory)
03464         {
03465             return directory->szFilename;
03466         }
03467     }
03468     return sPath;
03469 }
03470 
03471 gboolean ctrl_location_is_outbox(const char* location)
03472 {
03473     if ( location != NULL && strncmp(location, "/" OUTBOX_NAME, 1 + strlen(OUTBOX_NAME)) == 0 )
03474     {
03475         return TRUE;
03476     }
03477     else
03478     {
03479         return FALSE;
03480     }
03481 }
03482 
03483 gboolean ctrl_current_location_is_outbox()
03484 {
03485     const char* location = ctrl_get_current_location(gContentLister);
03486     
03487     return ctrl_location_is_outbox(location);
03488 }
03489 
03490 
03491 // Exception folder(s) in which all manifest-related functionality is disabled
03492 // At the moment used for Mobipocket to disable share/rename
03493 gboolean ctrl_current_location_is_mobipocket()
03494 {
03495     char location[ERMDS_MAX_FILENAME_SIZE];
03496     char * cp;
03497     
03498     location[0] = '\0';
03499     stItem_t *pItem = stackPeek(gContentLister->currentContentType);
03500     if (pItem != NULL)
03501     {
03502         mdsDirectory_t *directory = &g_array_index(pItem->dirArray, mdsDirectory_t, 0);
03503         if (directory)
03504         {
03505             strncpy(location, directory->szFilename, sizeof(location));
03506         }
03507         else
03508         {
03509             return FALSE;
03510         }
03511     }
03512     else
03513     {
03514         return FALSE;
03515     }
03516 
03517     cp = &location[0];
03518     
03519     CL_CONTROLPRINTF("check location: [%s]", cp);
03520     
03521     // TODO: We could use a simple
03522     // return ctrl_not_create_manifest(location);
03523     // here. Is this what we want?
03524     
03525     if (strlen(location) > strlen(MOBIPOCKET_FOLDER))
03526     {
03527         cp += (strlen(location) - strlen(MOBIPOCKET_FOLDER));
03528     }
03529     
03530     CL_CONTROLPRINTF("found: [%s]", cp);
03531 
03532     if (strcmp(cp, MOBIPOCKET_FOLDER) == 0)
03533     {
03534         return TRUE;
03535     }
03536     else
03537     {
03538         return FALSE;
03539     }
03540 }
03541 
03542 // detect whether the current content location is empty or not
03543 // returns: TRUE is empty, FALSE is not empty
03544 static gboolean ctrl_current_location_is_empty(void)
03545 {
03546     CL_CONTROLPRINTF("empty");
03547 
03548     if (gContentLister && gContentLister->itemCount > 0)
03549     {
03550         return FALSE;
03551     }
03552     else
03553     {
03554         CL_CONTROLPRINTF("Current location is empty.");
03555         return TRUE;
03556     }
03557 }
03558 
03559 // ///////////////////////////////////////////////////////////////////////////////
03560 // for pincode
03561 //
03562 
03563 // re-read the values of pincode from sysset and re-set the lock screen icon on toolbar
03564 void ctrl_pincode_setting_init()
03565 {
03566     gboolean enable = FALSE;
03567     gchar pincode[PINCODE_MAX_LENGTH + 1];
03568     ContentLister *theContentLister = gContentLister;
03569 
03570     g_return_if_fail(NULL != theContentLister);
03571     g_return_if_fail(NULL != theContentLister->pincodeScreen);
03572     sysset_read_pincode_onoff(&enable);
03573     sysset_read_pincode_string(pincode);
03574     
03575     gtk_pincode_screen_set_pincode_settings(theContentLister->pincodeScreen, enable, pincode);
03576     ctrl_pincode_set_toolbar_icon();
03577 }
03578 
03579 void ctrl_show_pincode_screen(showPincodeReason_t reason, on_passed_callback_t* on_passed_callback, on_cancel_callback_t* on_cancel_callback)
03580 {
03581     CL_LOGPRINTF("PINCODE screen show");
03582 
03583     ContentLister *theContentLister = gContentLister;
03584     char *UaOnTop = NULL;
03585 
03586     g_return_if_fail(theContentLister != NULL);
03587     g_return_if_fail(theContentLister->pincodeScreen != NULL);
03588     g_return_if_fail(g_listerState != STATE_PINCODE);
03589 
03590     if (reason != startup_t)
03591     {
03592         // abort miscellaneous contentLister windows
03593         ctrl_hide_misc_screen();
03594 
03595         // bring contentlister on top
03596         UaOnTop = pm_getUaOnTop ();
03597         CL_CONTROLPRINTF ("%s on top", UaOnTop);
03598         strncpy (restoreUaOnTop, UaOnTop, sizeof (restoreUaOnTop)); 
03599         if ((strncmp (UaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0)) 
03600         { 
03601             // contentLister not "On Top" => show contentlister 
03602             CL_CONTROLPRINTF ("CL NOT on top");
03603             display_update_increase_level(NO_DISPLAY_UPDATE_LEVEL);
03604             pm_RaiseContentLister (); 
03605         }
03606     }
03607 
03608     if (GTK_WIDGET_VISIBLE(theContentLister->pincodeScreen) == FALSE)
03609     {
03610         // => only request a refresh on the main window expose event
03611         CL_SCREENPRINTF("Display pincode screen");
03612         if (display_update_get_level() == NO_DISPLAY_UPDATE_LEVEL)
03613         {
03614             display_update_decrease_level(MAIN_WINDOW_EXPOSE_LEVEL);
03615         }
03616         else
03617         {
03618             display_update_increase_level(MAIN_WINDOW_EXPOSE_LEVEL);
03619         }
03620         gtk_window_fullscreen(GTK_WINDOW(theContentLister->topLevelWindow));
03621         gtk_widget_hide(GTK_WIDGET(theContentLister->listerScreen ));
03622         gtk_widget_hide(GTK_WIDGET(theContentLister->errorScreen  ));
03623         gtk_widget_show(GTK_WIDGET(theContentLister->pincodeScreen));
03624         gtk_widget_grab_focus(GTK_WIDGET(theContentLister->pincodeScreen));
03625     }
03626     // it's possible user change or reset pincode after we create gtkPincdeScreen
03627     ctrl_pincode_setting_init();
03628 
03629     // when show pincode screen
03630     // and disable usb connect with pc
03631     // and begin to accumulate idle time 
03632     // and reset the pincode passed
03633 
03634     // attention: when launched downloadMgr, will change contentlister status to STATE_DOWNLOADMGR
03635     setListerState(STATE_PINCODE);
03636     erStopMSDiskApp();
03637    
03638     accumulate_idle_time_set_callback(ctrl_pincode_idle_time_callback);
03639     accumulate_idle_time_set_threshold(PINCODE_MAX_IDLE_TIME);
03640     gtk_pincode_screen_layout_reset(theContentLister->pincodeScreen);
03641     gtk_pincode_screen_data_reset(theContentLister->pincodeScreen);
03642     gtk_pincode_screen_set_reason(theContentLister->pincodeScreen, reason);
03643     gtk_pincode_screen_set_on_passed_callback(theContentLister->pincodeScreen, on_passed_callback);
03644 
03645     if (ctrl_pincode_is_for_locking())
03646     {
03647         gtk_pincode_screen_set_on_cancel_callback(theContentLister->pincodeScreen, NULL);
03648     }
03649     else
03650     {
03651         gtk_pincode_screen_set_on_cancel_callback(theContentLister->pincodeScreen, on_cancel_callback);
03652     }
03653 }
03654 
03655 void ctrl_hide_pincode_screen()
03656 {
03657     showPincodeReason_t reason;
03658     CL_LOGPRINTF("PINCODE screen hide");
03659 
03660     ContentLister *theContentLister = gContentLister;
03661     if (g_listerState != STATE_PINCODE)
03662     {
03663         return;
03664     }
03665 
03666     if (theContentLister && theContentLister->pincodeScreen && GTK_WIDGET_VISIBLE(theContentLister->pincodeScreen))
03667     {
03668         // => only request a refresh on the main window expose event
03669         CL_SCREENPRINTF("");
03670         display_update_increase_level(MAIN_WINDOW_EXPOSE_LEVEL);
03671 
03672         gtk_window_unfullscreen(GTK_WINDOW(theContentLister->topLevelWindow));
03673         gtk_widget_show(GTK_WIDGET(theContentLister->listerScreen ));
03674         gtk_widget_hide(GTK_WIDGET(theContentLister->errorScreen  ));
03675         gtk_widget_hide(GTK_WIDGET(theContentLister->pincodeScreen));
03676         gtk_widget_grab_focus(GTK_WIDGET(theContentLister->listerArea));
03677 
03678         reason = gtk_pincode_screen_get_reason(theContentLister->pincodeScreen);
03679         if (reason != startup_t)
03680         {
03681             if ((strncmp (restoreUaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0)) 
03682             { 
03683                 pm_RaiseUserApp (restoreUaOnTop);
03684                 strncpy (restoreUaOnTop, CONTENTLISTER_UAID, sizeof(restoreUaOnTop)); 
03685             } 
03686         }
03687         if (   reason != startup_t
03688             && reason != enterSettings_t)
03689         {
03690             erStartMSDiskApp();
03691         }
03692     }
03693 
03694     // when hide pincode screen, 
03695     // and set contentlister to be normal state
03696     // and enable usb connect with pc
03697     // and end to accumulate idle time
03698     setListerState(STATE_NORMAL);
03699     accumulate_idle_time_end();
03700 }
03701 
03702 gboolean ctrl_pincode_is_for_locking()
03703 {
03704     gboolean bIsForLocking=TRUE;
03705     ContentLister *theContentLister;
03706     showPincodeReason_t reason;
03707     
03708     theContentLister = gContentLister;
03709     if (NULL == theContentLister)
03710         return bIsForLocking;
03711     if (NULL == theContentLister->pincodeScreen)
03712         return bIsForLocking;
03713     reason = (showPincodeReason_t)gtk_pincode_screen_get_reason(theContentLister->pincodeScreen);
03714     switch (reason)
03715     {
03716         case startup_t:
03717         case lockScreen_t:
03718             bIsForLocking = TRUE;
03719         break;
03720         
03721         case signDocument_t:
03722         case enterSettings_t:
03723         case importSettings_t:
03724             bIsForLocking = FALSE;
03725         break;
03726         
03727         default:
03728             bIsForLocking = TRUE;
03729     }
03730     return bIsForLocking;
03731 }
03732 
03733 // when pincode screen for locking purpose, we need to lock all keys except 'connect long'
03734 // when pincode screen for anthorizing purpose, we need to lock all keys except 'up key'
03735 //
03736 // cancel the pincode screen
03737 //
03738 void ctrl_pincode_overview_button_clicked(void)
03739 {
03740    showPincodeReason_t reason;
03741    gboolean bIsForLocking;
03742 
03743     accumulate_idle_time_reset();
03744 
03745     bIsForLocking = ctrl_pincode_is_for_locking();
03746     if (bIsForLocking)
03747     {
03748         erbusy_off();
03749         return;
03750     }
03751 
03752     ContentLister *theContentLister = gContentLister;
03753     reason = gtk_pincode_screen_get_reason(theContentLister->pincodeScreen);
03754     ctrl_hide_pincode_screen();
03755     gtk_pincode_screen_on_cancel_callback(theContentLister->pincodeScreen);
03756 }
03757 
03758 // want to reset pincode, launch connectMgr, pincode screen is at the background
03759 void ctrl_pincode_connect_button_clicked()
03760 {
03761     gboolean bIsForLocking;
03762 
03763     accumulate_idle_time_reset();
03764 
03765     bIsForLocking = ctrl_pincode_is_for_locking();
03766     if (!bIsForLocking)
03767     {
03768         erbusy_off();
03769         return;
03770     }
03771     
03772     CL_LOGPRINTF("Connect from PINCODE...");
03773     // when downloading, we should remove accumulate_idle_time
03774     // to prevent shutdown device due to idle
03775     accumulate_idle_time_end();
03776 
03777     ctrl_connect(connectScrUnchanged, connect_from_pincode);
03778 }
03779 
03780 void ctrl_pincode_button_clicked(void)
03781 {
03782     accumulate_idle_time_reset();
03783     erbusy_off();
03784 }
03785 
03786 gboolean ctrl_is_connect_from_pincode(void)
03787 {
03788     gboolean bRet = FALSE;
03789    
03790     if (   getListerState() == STATE_DOWNLOADMGR
03791         && connectStruct.connect_from_pincode   )
03792     {
03793         bRet = TRUE;
03794     }
03795     CL_LOGPRINTF("return %d", bRet);
03796     return bRet;
03797 }
03798 
03799 void ctrl_connect_back_to_pincode_screen()
03800 {
03801     ContentLister *theContentLister = gContentLister;
03802     char *UaOnTop = NULL;
03803     showPincodeReason_t reason;
03804 
03805     g_return_if_fail(NULL != theContentLister);
03806     g_return_if_fail(NULL != theContentLister->pincodeScreen);
03807 
03808     // set contentliser to STATE_PINCODE
03809     setListerState(STATE_PINCODE);
03810 
03811     // when finishing downloading reset pincode,  we should continue accumulate_idle_time
03812 
03813     // re-read pincode from sysset
03814     // from pincode screen user can connect to iDS and download a pincode reset package
03815     ctrl_pincode_setting_init();
03816 
03817     reason = gtk_pincode_screen_get_reason(theContentLister->pincodeScreen);
03818     if (reason != startup_t)
03819     {
03820         UaOnTop = pm_getUaOnTop();
03821         CL_CONTROLPRINTF("UaOnTop = %s", UaOnTop);
03822         if ((strncmp(UaOnTop, CONTENTLISTER_UAID, UAID_MAX_SIZE) != 0))
03823         {
03824             // contentLister not "On Top" => show contentlister 
03825             CL_CONTROLPRINTF("CL NOT on top");
03826             pm_RaiseContentLister();
03827         }
03828     }
03829 
03830     display_update_request_screen_refresh(MAIN_WINDOW_EXPOSE_LEVEL);
03831 }
03832 
03833 void ctrl_on_lock_screen_clicked(int iconState)
03834 {
03835     CL_IPCPRINTF("entry: iconState [%d]", iconState);
03836 
03837     switch (iconState)
03838     {
03839     case iconState_normal:
03840     // change icon to "selected",
03841 //        toolbar_setIconState(iconID_lock_screen, iconState_selected);
03842 //        toolbar_synchronise();
03843     ctrl_lock_screen();
03844     break;
03845 
03846 //    case iconState_selected:
03847     // change icon to "normal",
03848 //        toolbar_setIconState(iconID_lock_screen, iconState_normal);
03849 //        toolbar_synchronise();
03850     break;
03851 
03852     default:
03853         /*
03854         * ignore 
03855         */ ;
03856     }
03857 }
03858 
03859 static void ctrl_lock_screen(void)
03860 {
03861     if (g_listerState != STATE_DOWNLOADMGR)
03862     {
03863         erbusy_blink();
03864         ctrl_show_pincode_screen(lockScreen_t, NULL, NULL);
03865     }
03866 }
03867 
03868 static void ctrl_pincode_idle_time_callback()
03869 {
03870     CL_LOGPRINTF("system shutdown due to PINCODE screen idle");
03871     ctrl_hide_pincode_screen();
03872     ctrl_shutdown();
03873 }
03874 
03875 static void ctrl_pincode_set_toolbar_icon()
03876 {
03877     ContentLister *theContentLister = NULL;
03878     gboolean enable = FALSE;
03879     gchar pincode[PINCODE_MAX_LENGTH + 1];          
03880 
03881     theContentLister = gContentLister;
03882     if (theContentLister != NULL && theContentLister->pincodeScreen)
03883     {
03884         gtk_pincode_screen_get_pincode_settings(theContentLister->pincodeScreen, &enable, pincode);
03885         if (FALSE == enable || 0 == strlen(pincode))
03886         {
03887             toolbar_setIconState(iconID_lock_screen, iconState_grey);
03888         }
03889         else
03890         {
03891             toolbar_setIconState(iconID_lock_screen, iconState_normal);
03892         }
03893     }
03894 }
03895 
03896 static void ctrl_start_setup()
03897 {
03898     ctrl_start_application(SETUP_APP, NULL);
03899 }
03900 
03902 // for sorting
03903 //
03904 static void ctrl_show_sort_wnd_trigger(void)
03905 {
03906     g_timeout_add(500, ctrl_show_sort_wnd, NULL);
03907 }
03908 
03909 static gboolean ctrl_show_sort_wnd(gpointer data)
03910 {
03911     gboolean bRet = FALSE;      // don't me call again
03912 
03913     CL_LOGPRINTF("entry");
03914 
03915     if (getListerState() == STATE_MISC)
03916     {
03917         CL_WARNPRINTF("already sorting: igore");
03918         return bRet;
03919     }
03920    
03921     // update state and ui
03922     erbusy_blink();
03923     setListerState(STATE_MISC);
03924     
03925     // update toolbar
03926     toolbar_disableUpdate();
03927     toolbar_setIconState(iconID_search,   iconState_grey    );
03928     toolbar_setIconState(iconID_sort,     iconState_selected);
03929     toolbar_setIconState(iconID_share,    iconState_grey    );
03930     toolbar_setIconState(iconID_tagging,  iconState_grey    );
03931     toolbar_setIconState(iconID_trashcan, iconState_grey    );
03932     toolbar_enableUpdate();
03933 
03934     // update pagebar
03935     pagebar_set_pagecount(1);
03936     pagebar_goto_page(1);
03937     pagebar_redraw();
03938 
03939     // hide lister items, then show edit screen
03940     int i;
03941     GtkWidget *listItem;
03942     for (i = 0; i < MAX_ITEMS_ON_ONE_PAGE; i++)
03943     {
03944         listItem = lsGetListerItem(gContentLister->lister, i);
03945         gtk_widget_hide(listItem);
03946     }
03947    
03948     // increase level to prevent display from updating in 'ctrl_sort_wnd_setting_init()'
03949     display_update_increase_level(LISTER_EXPOSE_LEVEL);
03950     // 
03951     ctrl_sort_wnd_setting_init();
03952 
03953     gtk_widget_show(GTK_WIDGET(gContentLister->sortWnd));
03954 
03955     return bRet;
03956 }
03957 
03958 void ctrl_hide_sort_wnd(gboolean bSort)
03959 {
03960     CL_LOGPRINTF("entry");
03961 
03962     if ( (getListerState() == STATE_MISC) 
03963          && (gContentLister->sortWnd)
03964          && GTK_WIDGET_VISIBLE(gContentLister->sortWnd) )
03965     {
03966         // update toolbar
03967         toolbar_disableUpdate();
03968         toolbar_setIconState(iconID_search,   iconState_normal);
03969         toolbar_setIconState(iconID_sort,     iconState_normal);
03970         toolbar_setIconState(iconID_share,    iconState_normal);
03971         toolbar_setIconState(iconID_tagging,  iconState_normal);
03972         toolbar_setIconState(iconID_trashcan, iconState_normal);
03973         ctrl_hide_keyboard(iconState_grey);
03974         toolbar_enableUpdate();
03975         
03976         if (bSort)
03977         {
03978            ctrl_sort_current();
03979         }
03980         else
03981         {
03982             ctrl_rescan_current();
03983         }
03984         
03985         // show contentlister page
03986         gtk_widget_hide(GTK_WIDGET(gContentLister->sortWnd));
03987         gtk_widget_grab_focus(GTK_WIDGET(gContentLister->listerArea));
03988         setListerState(STATE_NORMAL);   
03989     }
03990 }
03991 
03992 static void ctrl_on_sort_clicked(int iconState)
03993 {
03994     switch (iconState)
03995     {
03996         case iconState_normal:
03997             if (getListerState() == STATE_NORMAL)
03998             {
03999                 // de-select contentlister items
04000                 ctrl_listItem_focus(-1, gContentLister);
04001 
04002                 // update toolbar, show sort window after toolbar updated
04003                 toolbar_disableUpdate();
04004                 toolbar_setIconState(iconID_search,   iconState_grey    );
04005                 toolbar_setIconState(iconID_sort,     iconState_selected);
04006                 toolbar_setIconState(iconID_share,    iconState_grey    );
04007                 toolbar_setIconState(iconID_tagging,  iconState_grey    ); 
04008                 toolbar_setIconState(iconID_trashcan, iconState_grey    );
04009                 ctrl_add_on_toolbar_sync_action(ctrl_show_sort_wnd_trigger);
04010                 toolbar_enableUpdate();
04011                 toolbar_synchronise();
04012             }
04013             break;
04014 
04015         case iconState_selected:
04016             ctrl_hide_sort_wnd(TRUE);
04017             break;
04018 
04019         default:
04020             /*
04021              * ignore 
04022              */ ;
04023     }
04024 }
04025 
04026 static void ctrl_sort_current(void)
04027 {
04028     CL_LOGPRINTF("entry");
04029     gint nSave = -1;
04030  
04031     erbusy_blink();
04032 
04033     nSave = ctrl_save_sort_settings();
04034     if (1 == nSave)
04035     {
04036         int      itemIndex;
04037         gchar    szFilename[ERMDS_MAX_FILENAME_SIZE];
04038         gboolean ret;
04039 
04040