GTK+/Kalkulator 0.0.1 - kalkulator.cpp

Z Wikibooks, biblioteki wolnych podręczników.
#include <stdlib.h>
#include <string>
#include <iostream>
#include <sstream>
#include <locale>

#include "kalkulator.hpp"

//#define DEBUG
//#define INFO
//#define NEW_VERSION_CALCULATE
//#define WIN

using namespace std;


Kalkulator::Kalkulator()
{
  #ifdef INFO
  __debug("Kalkulator konstruktor",false);
  #endif
  value1 = NULL;
  value2 = NULL;
  operation = NoSelectOprt;
  prev_operation = NoSelectOprt;
  is_value1 = FALSE;
  is_value2 = FALSE;
  is_result = FALSE;
  prev_button = NoSelectBtn;
  button_cache_comma = NoSelectBtn; 
  button_cache_result = NoSelectBtn; 
  memory = NULL;
}

Kalkulator::~Kalkulator()
{
  #ifdef INFO
  __debug("Kalkulator destruktor",false);
  #endif
  memory_free();
}

const char* Kalkulator::_btn_id_to_char(btn_id val)
{
  return   val==Button_1 ? "1" :
           val==Button_2 ? "2" :
           val==Button_3 ? "3" :
           val==Button_4 ? "4" :
           val==Button_5 ? "5" :
           val==Button_6 ? "6" :
           val==Button_7 ? "7" :
           val==Button_8 ? "8" :
           val==Button_9 ? "9" :
           val==Button_0 ? "0" :
           val==Button_add ? "Button_add" :
           val==Button_sub ? "Button_sub" :
           val==Button_multi ? "Button_multi" :
           val==Button_div ? "Button_div" :
           val==Button_result ? "Button_result" :
           val==Button_comma ? "Button_comma" :
           val==Button_back ? "Button_back" :
           val==Button_clear ? "Button_clear" :
           val==Button_signed ? "Button_signed" :
           val==Button_addmem ? "Button_addmem" :
           val==Button_readmem ? "Button_readmem" :
           val==Button_clearmem ? "Button_clearmem" :
           "NoSelectBtn(22)";
}

const char* Kalkulator::_operation_id_to_char(operation_id val)
{
  return   val==Add ? "+" :
           val==Sub ? "-" :
           val==Multi ? "*" :
           val==Div ? "/" :
           "NoSelectOprt(5)";
}

btn_id Kalkulator::_operation_id_to_btn_id(operation_id val)
{
  return   val==Add ? Button_add :
           val==Sub ? Button_sub :
           val==Multi ? Button_multi : 
           val==Div ? Button_div :
           NoSelectBtn;
}

void Kalkulator::__debug(const gchar* event, bool data)
{
  if (data)
  {
    printf (
"\n ===================[DEBUG]=====================\n \
event: %s \n \
 - - - - -\n \
Struktura:\n \
  value1: %s \n \
  value2: %s \n \
  operation: %s \n \
  prev_operation: %s \n \
  is_value1: %s \n \
  is_value2: %s \n \
  is_result: %s \n \
  prev_button: %s \n \
  button_cahce_comma: %s \n \
  button_cahce_result: %s \n \
  memory: %s \n \
===============================================\n\n\n",
      event,
      is_value1? value1->str :"",
      is_value2? value2->str :"",
      _operation_id_to_char(operation),
      _operation_id_to_char(prev_operation),
      is_value1?"TRUE":"FALSE",
      is_value2?"TRUE":"FALSE",
      is_result?"TRUE":"FALSE",
      _btn_id_to_char(prev_button),
      _btn_id_to_char(button_cache_comma),
      _btn_id_to_char(button_cache_result),
      memory? "TRUE": "NULL");
    
    if (memory)
    {
      cout << "Spis liczb w pamięci:" << endl;
      memory_print();
      cout << endl;
    }
  }
  else
    cout << event << endl;
}

#ifndef NEW_VERSION_CALCULATE
void Kalkulator::calculate(bool prev_operation_priv)
{
  #ifndef WIN  
  long double d_value1=0,
  #else
  double d_value1=0,
  #endif
         d_value2=0,
         d_result=0;
  int len, test(0);
  char s_result[50];
  string ss_result;
  bool is_comma(false);
  
  d_value1 = strtod( value1->str, NULL );
  d_value2 = strtod( value2->str, NULL );
  
  if (prev_operation_priv)
  {
    test = prev_operation==Add ? 1 :
           prev_operation==Sub ? 2 :
           prev_operation==Multi ? 3 :
           prev_operation==Div ? 4 :
           NoSelectOprt;
  }
  else
  {
    test = operation==Add ? 1 :
           operation==Sub ? 2 :
           operation==Multi ? 3 :
           operation==Div ? 4 :
           NoSelectOprt;
  }
  
  switch(test)
  {
    case 1:
      d_result = d_value1 + d_value2;
      break;
    case 2:
      d_result = d_value1 - d_value2;
      break;
    case 3:
      d_result = d_value1 * d_value2;
      break;
    case 4:
      if ( d_value2 != 0.0 )
        d_result = d_value1 / d_value2;
      else
        d_result = d_value1;
      break;
    case 5:
      // Checkit!
      break;
  }

  len = sprintf( s_result, "%Lf", d_result );
  // można to spr.
  // if ( !len ) ...
  ss_result = s_result;

  for (unsigned int i=0; i < ss_result.length(); i++)
  {
    if (ss_result[i] == ',')
    {
      is_comma = true;
      #ifdef DEBUG
      cout << "\nis comma\n";
      #endif
      break;
    }
  }
  // tylko ,
  if (is_comma)
  {
    // usuwamy końcowe 0
    while (ss_result[ss_result.length()-1] == '0')
      ss_result.erase((ss_result.length()-1),1);
    // usuwamy przecinek jeżeli za nim byo same 0
    if (ss_result[ss_result.length()-1] == ',')
      ss_result.erase((ss_result.length()-1),1);
  }
  
  set_value1(ss_result.c_str());
  set_is_result(true);
  
  #ifdef DEBUG
    printf ("calculateby to %Lg , %Lg wynik to: %Lg \n",d_value1,d_value2,d_result);
  #endif
}
#endif

#ifdef NEW_VERSION_CALCULATE
void Kalkulator::calculate(bool prev_operation_priv)
{
  #ifndef WIN  
  long double d_value1=0,
  #else
  double d_value1=0,
  #endif
         d_value2=0,
         d_result=0;
  
  cout << "long double: " << sizeof(long double) << endl;
  cout << "float: " << sizeof(float) << endl;
  cout << "long: " << sizeof(long) << endl;
  
  bool is_comma(false);
  int len, test(0);
  string s_result, s1, s2;
  //string str1 = value1->str, str2 = value2->str;
  istringstream str1;
  istringstream str2;
  ostringstream rst;
  
  //s1.imbue(locale("pl_PL"));
  //s2.imbue(locale("pl_PL")); 
  
  str1.str(value1->str);
  str2.str(value2->str);
  
  s1 = str1.str();
  s2 = str2.str();
  
  for (unsigned int i=0; i < s1.length(); i++)
  {
    if (s1[i] == '.')
    {
      s1.replace(i,1,1,',');
      //is_comma = true;
      break;
    }
  }
  for (unsigned int i=0; i < s2.length(); i++)
  {
    if (s2[i] == '.')
    {
      s2.replace(i,1,1,',');
      //is_comma = true;
      break;
    }
  }
  str1.str(s1);
  str2.str(s1);
  
  // char* -> double
  str1 >> d_value1;
  //str2 >> fixed >> dec >> d_value2;
  str2 >> d_value2;
  str1 >> s1;
  str2 >> s2;
  cout << "\nval1: " << d_value1 << " s1: " << s1 << endl;
  cout << "\nval2: " << d_value2 << " s2: " << s2 << endl;
  cout << "\n s1: " << s1 << " s2: " << s2 << endl;
  if (prev_operation_priv)
  {
    test = prev_operation==Add ? 1 :
           prev_operation==Sub ? 2 :
           prev_operation==Multi ? 3 :
           prev_operation==Div ? 4 :
           NoSelectOprt;
  }
  else
  {
    test = operation==Add ? 1 :
           operation==Sub ? 2 :
           operation==Multi ? 3 :
           operation==Div ? 4 :
           NoSelectOprt;
  }
  switch(test)
  {
  case 1:
    d_result = d_value1 + d_value2;
    break;
  case 2:
    d_result = d_value1 - d_value2;
    break;
  case 3:
    d_result = d_value1 * d_value2;
    break;
  case 4:
    if ( d_value2 != 0.0 )
      d_result = d_value1 / d_value2;
    else
      d_result = d_value1;
    break;
  case 5:
    // Checkit!
    break;
  }
   
  rst << fixed << dec << d_result;
  s_result = rst.str(); 
  cout << "\n s_result: " << s_result << endl;
  //for (unsigned int i=0; i < s_result.length(); i++)
  //{
  //  if (s_result[i] == '.')
  //  {
  //    s_result.replace(i,1,1,',');
  //    is_comma = true;
  //    break;
  //  }
  //}
  for (unsigned int i=0; i < s_result.length(); i++)
  {
    if (s_result[i] == ',')
    {
      is_comma = true;
      break;
    }
  }
  cout << "\n s_result: " << s_result << endl;
  if (is_comma)
  {
    // usuwamy końcowe 0
    while (s_result[s_result.length()-1] == '0')
      s_result.erase((s_result.length()-1),1);
    // usuwamy przecinek jeżeli za nim byo same 0
    if (s_result[s_result.length()-1] == ',')
      s_result.erase((s_result.length()-1),1);
  }
  set_value1(s_result.c_str());

  set_is_result(true);
  
  #ifdef DEBUG
  cout << "\nval1: " << d_value1 << " val2: " << d_value2 << " rst: " << d_result << endl;
  #endif
}
#endif

char* Kalkulator::get_value1()
{
  if (is_value1) 
    return value1->str;
  else 
    return NULL;
}

void Kalkulator::set_value1(const gchar *val) 
{
  if (is_value1)
  {
    g_string_free(value1,TRUE);
    value1 = g_string_new(val);
  }
  else
  {
    value1 = g_string_new(val);
    is_value1 = TRUE;
  }
}

bool Kalkulator::del_value1()
{
  if (is_value1)
  {
    g_string_free(value1,TRUE);
    is_value1 = FALSE;
    return TRUE;
  }
  else
    return FALSE;
}

char* Kalkulator::get_value2()
{
  if (is_value2) 
    return value2->str;
  else 
    return NULL;
}

void Kalkulator::set_value2(const gchar *val) 
{
  if (is_value2)
  {
    g_string_free(value2,TRUE);
    value2 = g_string_new(val);
  }
  else
  {
    value2 = g_string_new(val);
    is_value2 = TRUE;
  }
}

bool Kalkulator::del_value2()
{
  if (is_value2)
  {
    g_string_free(value2,TRUE);
    is_value2 = FALSE;
    return TRUE;
  }
  else
    return FALSE;
}

void Kalkulator::add_to_memory(const gchar *val)
{
  GString *tmp = g_string_new(val);
  memory = g_list_append(memory, tmp);
}

void Kalkulator::memory_free()
{
  int n(0);
  // zwalniamy pamięć, na którą wskazują wskaźniki w liście
  // zobacz: http://mail.gnome.org/archives/gtk-app-devel-list/2005-January/msg00357.html
  while (memory)
  {
    GList *tmp = g_list_nth(memory,n++);
    if (tmp)
      g_string_free((GString*)tmp->data,TRUE);
    else
      break;
  }
  // zwalniamy pamięć, której używa lista
  g_list_free(memory);
  memory = NULL;
}

void Kalkulator::memory_print()
{
  int n(0);
  while (memory)
  {
    GList *tmp = g_list_nth(memory,n++);
    if (tmp)
      g_print("\n[ mem %d: %s ]",n,((GString*)tmp->data)->str);
    else
      break;
  }
}

guint Kalkulator::memory_count()
{
  return g_list_length(memory);
}