jens-maus/yam

View on GitHub
src/mui/InfoBar.c

Summary

Maintainability
Test Coverage
/***************************************************************************

 YAM - Yet Another Mailer
 Copyright (C) 1995-2000 Marcel Beck
 Copyright (C) 2000-2022 YAM Open Source Team

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 YAM Official Support Site : http://www.yam.ch
 YAM OpenSource project     : http://sourceforge.net/projects/yamos/

 $Id$

 Superclass:  MUIC_Group
 Description: Displays additional information in the Main window

***************************************************************************/

#include "InfoBar_cl.h"

#include <string.h>

#include <proto/muimaster.h>

#include "YAM.h"
#include "YAM_utilities.h"

#include "mui/ImageArea.h"
#include "mui/FolderListtree.h"

#include "Busy.h"
#include "Config.h"
#include "DynamicString.h"
#include "MUIObjects.h"

#include "Debug.h"

/* CLASSDATA
struct Data
{
  Object *TX_FOLDER;
  Object *TX_FINFO;
  Object *TX_INFO;
  Object *GA_GROUP;
  Object *GA_INFO;
  Object *GA_LABEL;
  Object *BT_STOP;
  Object *actualImage;
  struct BusyNode *lastBusy;
  BOOL stopButtonPressed;
  struct TimeVal last_gaugemove;
  char gaugeInfoText[SIZE_SMALL];
  char folderInfo[SIZE_DEFAULT / 2];
};
*/

/* INCLUDE
#include "timeval.h"
*/

/* Private Functions */
/// GetFolderInfo()
// this function creates a folder string and returns it
static void GetFolderInfo(struct Data *data, struct Folder *folder)
{
  char *src;
  char *info = NULL;

  ENTER();

  // Lets create the label of the AppIcon now
  for(src = C->InfoBarText; *src; src++)
  {
    char dst[10];

    if(*src == '%')
    {
      switch(*++src)
      {
        case '%': dst[0] = '%'; dst[1] = '\0'; break;
        case 'n': snprintf(dst, sizeof(dst), "%d", folder->New);     break;
        case 'u': snprintf(dst, sizeof(dst), "%d", folder->Unread);  break;
        case 't': snprintf(dst, sizeof(dst), "%d", folder->Total);   break;
        case 's': snprintf(dst, sizeof(dst), "%d", folder->Sent);    break;
      }
    }
    else
    {
      dst[0] = *src;
      dst[1] = '\0';
    }

    dstrcat(&info, dst);
  }

  if(info != NULL)
  {
    strlcpy(data->folderInfo, info, sizeof(data->folderInfo));
    dstrfree(info);
  }
  else
    data->folderInfo[0] = '\0';


  LEAVE();
}

///

/* Overloaded Methods */
/// OVERLOAD(OM_NEW)
OVERLOAD(OM_NEW)
{
  Object *folderString;
  Object *folderInfoStr;
  Object *statusGroup;
  Object *gauge;
  Object *gaugeLabel;
  Object *infoText;
  Object *stopButton;

  ENTER();

  if((obj = DoSuperNew(cl, obj,

    // Some objects are allowed to disappear if the available space in the window is too narrow.
    // This is a workaround for a bug in MUI.
    TextFrame,
    MUIA_Background,    MUII_TextBack,
    MUIA_Group_Horiz,   TRUE,
    Child, HGroup,
      InnerSpacing(0,0),
      MUIA_HorizWeight, 50,
      Child, folderString = TextObject,
        MUIA_HorizWeight,    0,
        MUIA_HorizDisappear, 2,
        MUIA_Font,           MUIV_Font_Big,
        MUIA_Text_SetMax,    FALSE,
        MUIA_Text_PreParse,  "\033b",
        MUIA_Text_Copy,      FALSE,
      End,
      Child, folderInfoStr = TextObject,
        MUIA_HorizWeight,    100,
        MUIA_HorizDisappear, 1,
        MUIA_Font,           MUIV_Font_Tiny,
        MUIA_Text_SetMax,    FALSE,
        MUIA_Text_PreParse,  "\033l",
        MUIA_Text_Copy,      FALSE,
      End,
    End,

    Child, HGroup,

      Child, gaugeLabel = TextObject,
        MUIA_HorizDisappear, 1,
        MUIA_Text_SetMax,   FALSE,
        MUIA_Text_PreParse, "\033r",
        MUIA_Text_Copy,     FALSE,
      End,

      Child, statusGroup = PageGroup,
        MUIA_HorizDisappear, 3,
        Child, HSpace(0),
        Child, HGroup,
          InnerSpacing(0,0),
          GroupSpacing(1),
          Child, gauge = GaugeObject,
            GaugeFrame,
            MUIA_Gauge_Horiz,    TRUE,
            MUIA_Gauge_InfoText, " ",
          End,
          Child, stopButton = MakeCloseButton(),
        End,
        Child, infoText = TextObject,
          MUIA_Text_SetMax,   FALSE,
          MUIA_Text_PreParse, "\033r",
          MUIA_Text_Copy,     FALSE,
        End,
      End,
    End,

    TAG_MORE, inittags(msg))) != NULL)
  {
    GETDATA;

    // per default we set the stop button as hidden
    set(stopButton, MUIA_ShowMe, FALSE);

    data->TX_FOLDER = folderString;
    data->TX_FINFO  = folderInfoStr;
    data->GA_GROUP  = statusGroup;
    data->GA_LABEL  = gaugeLabel;
    data->GA_INFO   = gauge;
    data->TX_INFO   = infoText;
    data->BT_STOP   = stopButton;
    data->stopButtonPressed = FALSE;

    // on a button press on the stop button, lets set the
    // correct variable to TRUE as well.
    DoMethod(data->BT_STOP, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, METHOD(StopProcess));
  }

  RETURN((IPTR)obj);
  return (IPTR)obj;
}

///

/* Public Methods */
/// DECLARE(SetFolder)
// set a new folder and update its name and image in the infobar
DECLARE(SetFolder) // struct Folder *newFolder
{
  GETDATA;
  struct Folder *folder = msg->newFolder;
  IPTR result = -1;

  ENTER();

  if(folder != NULL)
  {
    GetFolderInfo(data, folder);

    // set the name of the folder as the info text
    nnset(data->TX_FOLDER, MUIA_Text_Contents, folder->Name);
    // now we are going to set some status field at the right side of the folder name
    nnset(data->TX_FINFO, MUIA_Text_Contents, data->folderInfo);

    // prepare the object for a change
    if(DoMethod(obj, MUIM_Group_InitChange))
    {
      // only if the image should be changed we proceed or otherwise
      // MUI will refresh too often
      if(data->actualImage != NULL && (folder->imageObject == NULL ||
         stricmp((char *)xget(data->actualImage, MUIA_ImageArea_ID),
                 (char *)xget(folder->imageObject, MUIA_ImageArea_ID)) != 0))
      {
        DoMethod(obj, OM_REMMEMBER, data->actualImage);

        D(DBF_GUI, "disposing folder image: id '%s' file '%s'", xget(data->actualImage, MUIA_ImageArea_ID), xget(data->actualImage, MUIA_ImageArea_Filename));
        MUI_DisposeObject(data->actualImage);
        data->actualImage = NULL;
      }

      // and if we have a new one we generate the object an add it
      // to the grouplist of this infobar
      if(data->actualImage == NULL)
      {
        if(folder->imageObject != NULL)
        {
          char *imageID = (char *)xget(folder->imageObject, MUIA_ImageArea_ID);
          char *imageName = (char *)xget(folder->imageObject, MUIA_ImageArea_Filename);

          data->actualImage = MakeImageObject(imageID, imageName);

          D(DBF_GUI, "init imagearea: id '%s', file '%s'", imageID, imageName);
        }
        else if(folder->ImageIndex >= 0 && folder->ImageIndex < FI_MAX)
        {
          Object **imageArray = (Object **)xget(G->MA->GUI.LT_FOLDERS, MUIA_FolderListtree_ImageArray);

          D(DBF_GUI, "init imagearea: 0x%08lx[%ld]", imageArray, folder->ImageIndex);

          if(imageArray != NULL && imageArray[folder->ImageIndex] != NULL)
          {
            char *imageID = (char *)xget(imageArray[folder->ImageIndex], MUIA_ImageArea_ID);
            char *imageName = (char *)xget(imageArray[folder->ImageIndex], MUIA_ImageArea_Filename);

            data->actualImage = MakeImageObject(imageID, imageName);
          }
        }

        D(DBF_GUI, "init finished..: 0x%08lx %ld", data->actualImage, folder->ImageIndex);

        if(data->actualImage != NULL)
          DoMethod(obj, OM_ADDMEMBER, data->actualImage);
      }

      // now that we are finished we can call ExitChange to refresh the infobar
      DoMethod(obj, MUIM_Group_ExitChange);
    }

    result = 0;
  }

  RETURN(result);
  return result;
}

///
/// DECLARE(ShowBusyBar)
// show a busy bar with either a simple info text or a progress gauge
DECLARE(ShowBusyBar) // struct BusyNode *busy
{
  GETDATA;
  BOOL goOn = TRUE;

  ENTER();

  if(msg->busy != NULL)
  {
    switch(msg->busy->type)
    {
      case BUSY_TEXT:
      case BUSY_AREXX:
      {
        set(data->TX_INFO, MUIA_Text_Contents, msg->busy->infoText);
        set(data->GA_LABEL, MUIA_Text_Contents, NULL);
        set(data->GA_GROUP, MUIA_Group_ActivePage, 2);

        msg->busy->wasVisible = TRUE;
      }
      break;

      case BUSY_PROGRESS:
      case BUSY_PROGRESS_ABORT:
      {
        // update the busy bar whenever
        // - another busy action is to be shown, or
        // - the busy action was not visible before, or
        // - enough time since the last update has passed
        if(msg->busy != data->lastBusy || msg->busy->wasVisible == FALSE || TimeHasElapsed(&data->last_gaugemove, 250000) == TRUE)
        {
          // we need valid gauge limits to be able to show the gauge
          if(msg->busy->progressMax > 0 && msg->busy->progressCurrent <= msg->busy->progressMax)
          {
            set(data->GA_LABEL, MUIA_Text_Contents, msg->busy->infoText);

            snprintf(data->gaugeInfoText, sizeof(data->gaugeInfoText), "%%ld/%ld", msg->busy->progressMax);
            xset(data->GA_INFO,
                   MUIA_Gauge_InfoText,  data->gaugeInfoText,
                   MUIA_Gauge_Max,       msg->busy->progressMax,
                   MUIA_Gauge_Current,   msg->busy->progressCurrent);
            set(data->BT_STOP, MUIA_ShowMe, TRUE);
            set(data->GA_GROUP, MUIA_Group_ActivePage, 1);

            if(msg->busy->type == BUSY_PROGRESS_ABORT)
            {
              // give the application the chance to clear its event loop
              DoMethod(_app(obj), MUIM_Application_InputBuffered);

              if(data->stopButtonPressed == TRUE)
              {
                // abort the currently running action
                goOn = FALSE;
                // forget the pressed stop button again, otherwise all future
                // busy actions will be aborted immediately again
                data->stopButtonPressed = FALSE;
              }
              else
              {
                goOn = TRUE;
              }
            }

            // we have been visible at least once
            msg->busy->wasVisible = TRUE;
          }
        }
        break;

        default:
        {
          E(DBF_GUI, "invalid busy type %ld", msg->busy->type);
        }
        break;
      }
      break;
    }
  }
  else
  {
    // hide the busy bar
    set(data->TX_INFO, MUIA_Text_Contents, NULL);
    set(data->GA_LABEL, MUIA_Text_Contents, NULL);
    set(data->GA_GROUP, MUIA_Group_ActivePage, 0);
  }

  // remember the changed busy action
  data->lastBusy = msg->busy;
  // make sure to forget any pressed stop button in case the last busy action terminates
  if(data->lastBusy == NULL)
    data->stopButtonPressed = FALSE;

  RETURN(goOn);
  return goOn;
}

///
/// DECLARE(StopProcess)
DECLARE(StopProcess)
{
  GETDATA;

  ENTER();

  data->stopButtonPressed = TRUE;

  RETURN(0);
  return 0;
}

///