Blog (76)
Komentarze (5.3k)
Recenzje (0)

libgreattao: prosty edytor tekstu

@nintyfanlibgreattao: prosty edytor tekstu20.09.2014 21:56

Właśnie informuję, że wydałem nową wersję libgreattao(wciąż pre-alfa). Dodałem obsługę nowych tagów do plików opisu klas. Shell od teraz obsługuje zmienne.Jest więcej zmian.

Chciałbym się teraz zająć pisaniem prostej aplikacji - edytora tekstu. Ten edytor tekstu był dostępny jako program demonstracyjny w poprzednim wydaniu, teraz się rozwinął.

Zatem do dzieła! Tak będzie wyglądać ostateczny kod:


#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void *Window, *dialogWindow;
int edited;
char *backup_file;
char template[] = "/tmp/tao-editor-XXXXXX";
void *save_timer;
void timer_callback(void *data);

void config_callback(void *mesh, void *data)
{
  int seconds, error;
  if ((int) data == 1) {
    seconds = tao_get_integer(dialogWindow, "/category/filesystem/timeout/text", &error);
    if (error || seconds < 1) {
      return;
    }
    tao_remove_timer(save_timer);
    save_timer = tao_add_timer(seconds * 1000, timer_callback, 0);
  }
  else if ((int) data == 2) {
    seconds = tao_get_integer(dialogWindow, "/category/filesystem/timeout/text", &error);
    if (error || seconds < 1) {
      return;
    }
    tao_remove_timer(save_timer);
    save_timer = tao_add_timer(seconds * 1000, timer_callback, 0);
    tao_release_window(dialogWindow);
    dialogWindow = NULL;
  }
  else if ((int) data == 3) {
    tao_release_window(dialogWindow);
    dialogWindow = NULL;
  }
}

void dialog_open_callback(void *mesh, void *data)
{
  int error;
  char *filepath = NULL;
  char *buffer;
  int length;
  int fd;

  if (data == 1) {
    filepath =  tao_get_string(dialogWindow, "/file_name", &error);
  }

  tao_release_window(dialogWindow);
  dialogWindow = NULL;

  if (filepath) {
    
    fd = open(filepath, O_RDONLY);
    if (fd == -1) {
      return;
    }
    length = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);
    
    buffer = (char *) malloc(length+1);
    read(fd, buffer, length);
    buffer[length] = 0;
    tao_set_string(Window, "/text", buffer);
    free(buffer);
    close(fd);
  }
}

void timer_callback(void *data)
{
  int fd;
  char *text;
  int error;

  if (!edited) {
    return;
  }

  if (!backup_file) {
    backup_file = mktemp(template);
  }

  text = tao_get_string(Window, "/text", &error);
  if (error) {
    return;
  }
  fd = open(backup_file, O_RDWR | O_CREAT);
  if (fd == -1) {
    return;
  }
  write(fd, text, strlen(text));

  close(fd);

  edited = 0;
}

void dialog_save_callback(void *mesh, void *data)
{
 int error;
 char *filepath = 0;
 char *text;
 int fd;

  if (data == 3) {
    filepath =  tao_get_string(dialogWindow, "/file_name", &error);
  }

  tao_release_window(dialogWindow);
  dialogWindow = NULL;

  text = tao_get_string(Window, "/text", &error);
  if (!text || error || !filepath) {
    return;
  }
  fd = open(filepath, O_RDWR | O_CREAT);
  if (fd == -1) {
    return;
  }
  ftruncate(fd, 0);
  write(fd, text, strlen(text));
  close(fd);

}

void callback(void *mesh, void *data)
{
  if ((int) data == 0) {
    if (dialogWindow) {
      tao_release_window(dialogWindow);
    }
    
    tao_release_window(Window);
    
    tao_close();
  }
  else if ((int) data == 1) {
    tao_set_string(Window, "/text", "");
  }
  else if ((int) data == 2) {
    if (dialogWindow) {
      
      return;
    }
    
    dialogWindow = tao_new_window("/desktop/dialogs/open_file_dialog");
    
    tao_add_handler(dialogWindow, "/actions/ok", &dialog_open_callback, 1);
    tao_add_handler(dialogWindow, "/actions/cancel", &dialog_open_callback, 2);    
  }
  else if ((int) data == 3) {

    if (dialogWindow) {
      
      return;
    }
    dialogWindow = tao_new_window("/desktop/dialogs/save_file_dialog");
    
    tao_add_handler(dialogWindow, "/actions/ok", &dialog_save_callback, 3);
    tao_add_handler(dialogWindow, "/actions/cancel", &dialog_save_callback, 4);    
  }
  else if ((int) data == 4) {
    if (dialogWindow) {
      
      return;
    }
    dialogWindow = tao_new_window("/desktop/dialogs/config_dialog");
    tao_add_handler(dialogWindow, "/category/filesystem");
    tao_set_hint(dialogWindow, "/category/filesystem", HINT_NAME, "Backups");
    tao_set_hint(dialogWindow, "/category/filesystem", HINT_DESCRIPTION, "Control how often backups are made and name of backups");
    tao_add_handler(dialogWindow, "/category/filesystem/timeout/text", 0, 0);
    tao_set_hint(dialogWindow, "/category/filesystem/timeout/text", HINT_NAME, "How often doing backups?");
    tao_set_hint(dialogWindow, "/category/filesystem/timeout/text", HINT_DESCRIPTION, "in seconds");

    tao_add_handler(dialogWindow, "/actions/save", config_callback, 1);
    tao_add_handler(dialogWindow, "/actions/ok", config_callback, 2);
    tao_add_handler(dialogWindow, "/actions/cancel", config_callback, 3);
  }
  else if ((int) data == 5) {
    
      edited = 1;
  }
}

int main(int argc, char *argv[])
{
  tao_initialize("Tao demo", "Super", &argc, argv);
  Window=tao_new_window("/app/text_editor");

  tao_add_handler(Window, "/:abort", &callback, 0);
  tao_add_handler(Window, "/text", NULL, 0);
  tao_add_handler(Window, "/text/changed", callback, 5);

  tao_add_handler(Window, "/actions/file", NULL, 0);
  tao_add_handler(Window, "/actions/app", NULL, 0);

  tao_add_handler(Window, "/actions/file/new", &callback, 1);
  tao_add_handler(Window, "/actions/file/open", &callback, 2);
  tao_add_handler(Window, "/actions/file/save", &callback, 3);
  tao_add_handler(Window, "/actions/app/config", &callback, 4);
  tao_add_handler(Window, "/actions/app/close", &callback, 0);

  tao_change_weight(Window, "/actions/file/save", 500);
  tao_change_weight(Window, "/actions/app/close", 500);

  save_timer = tao_add_timer(1000 * 5, timer_callback, 0);

  tao_handle_events();
};

Od czego zacząć? Najpierw musimy się zaznajomić z klasami okien(by wiedzieć, jak aktywować odpowiednie szablony). Ponieważ nie ma jeszcze dokumentacji, to musimy się posiłkować definicjami klas okien. Jako referencję należy zawsze rozpatrywać wygląd/paczkę mWidgets, jako iż jest tworzona przez zespół(czyli mnie) libgreatao i możę korzystać tylko z podstawowych elementów.

Skorzystamy z czterech klas okien:

  • /desktop/app/text_editor/item] /destkop/dialogs/config_dialog
  • /desktop/dialogs/open_file_dialog
  • /desktop/dialogs/save_file_dialog

Pierwszy zostanie wykorzystany na okno główne, drugi zostanie wykorzystany na okno konfiguracji, a dwa pozostałe na okno otwarcia/zamknięcia pliku. Dwa ostatnie są wbudowane, więc nie znajdziemy ich w instalacji, natomiat można je zastąpić własnymi definicjami przez stworzenie plików pod odpowiednimi ścieżkami.

To, co nas interesuje, to templaty(szablony). To właśnie szablony będziemy tworzyć. Szablony mogą być zagnieżdżone jeden w drugim, więć utworzenie elementu podrzędnego wymaga utworzenia elementu podrzędnego(jeszcze nie jest wspierane automatyczne tworzenie rodzica, by utworzyć dziecko). Dodatkowo szablony mogą być względne lub bezwzględne. Względne nie rozpoczynają się od slasha i wymagają rodzica.

Szablony mogą mieć wagę. Oznacza to, że zostanie utworzony, jeżeli naszej akcji przyporządkujemy odpowiednią wagę. Jest to wykorzystywane w /desktop/dialogs/text_editor -- tam przyciski wyświetlane na górnej belce będą dodane, jeżeli ich akcji przyporządkujemy wagę minimum 500. Za to każda akcja (w sensie zaczynająca się na /actions/) będzie widoczna w menu.

Zaczniemy od inicjalizacji naszej biblioteki. To od tego kroku musi zaczynać swe wykonanie każdy program napisany w libgreattao. Podczas incijalizacji biblioteka poszukuje odpowiedniego backendu i wyglądu(zestawu klas okien). Wygląd ona tak:


tao_initialize("Tao demo", "Super", &argc, argv);

Podajemy tam kolejno: nazwę programu, tekst pomocy, wskaźnik do ilości przekazanych argumentów, wskaźnik na wskaźniki argumentów.

Poniżej tworzymy okno. Jako parametr należy podać ścieżkę do klasy okna. Należy zwrócić uwagę na to, że typ zwracanego wyniku to wskaźnik na cokolwiek. Jest to spodowane tym, że struktury danych w libgreattao mogą się zmienić, jak również tym, żę w trybie powłoki zwracany jest inny wynik niż w trybie UI.

Dalej tworzymy akcje. Chodzi o funcję tao_add_handler. Jej pierwszym parametrem jest okno, drugim ścieżka zdarzenia, trzecim wskaźnik na procedurę do wywołania w przypadku aktywacji zdarzenia, czwartym parametr przekazywany tej procedurze,. Jeże,li nie chcemy dostarczyć żadnej procedury obsługi, a chcemy jedynie, by element był widoczny, to przekazujemy NULL.

Tworzymy następujące akcje:

  • /:abort - wbudowana akcja, chodzi o zamknięcie okna
  • /text - zostanie stworzony element textarea
  • [/text/changed - chcmey otrzymywać powiadomienie, kiedy text zostanie zmieniony
  • /actions/file - menu plik
  • /actions/app - menu applikacji
  • /actions/file/new - kasuje zawartość /text
  • /actions/file/open - otwiera plik
  • /actions/file/save - zapisuje plik
  • /actions/app/config - otwiera okno konfiguracji
  • /actions/app/close - kończy aplikację

Dodatkowo akcji /actions/file/save i /actions/app/close będą specjalne, co jest podkreślone nadaniem im wagi 500. W naszej definicji klasy okna takie akcje będą miały dodatkowy aktywator - w formie przycisku pod menu.

Żeby zablokować tworzenie większej liczby okien dialogowych niż jedno, sprawdzamy wskaźnik na okno dialogowe.

Następnie tworzymy czasomierz, by co pięć sekund była wywoływana określona procedura. Procedura ta będzie sprawdzać czy zawartość widżetu textarea została zmieniona i jeżeli tak, to będzie zapisywać zawartość do pliku. Na końcu wywołujemy pętlę obsługi zdarzeń i oddajemy sterowanie do shell-a lub do UI.

W przypadku okna dialogowego tworzynmy jedną kategorię - filesystem - i jedno pole - timeout typu text. Możęmy dodatkowo określić typ pola poprzez wywołanie tao_data_unsigned_int. Nie robimy jednak tego, gdyż sprawdzamy typ podzcas pobierania danych funkcją tao_get_integer. W wywołaniu tym przekazujemy wskaźnik na liczbę całkowitą o nazwie error. Jeżeli nie wystąpił błąd, to error będzie równy 0.

Należy zwrócić uwagę na to, że po kliknięćiu ok lub zapisz, a dodatkowo przy wprowadzeniu liczby, kasujemy stary timer i tworzymy nowy. Na końcu wstawianie wartości i pobieranie z textarea. Tutaj z pomocą przychodzą wywołania tao_set_string i tao_get_string. Tao_get_string przyjmuje dodatkowo wskaźnik na error. Jeżeli error jest różny od zera, to znaczy, że wystąpił błąd.

W celu sprawdzenia czy użytkownik wybrał plik w dialogu wyboru pliku(obojętnie czy zapisu czy odczytu), posiłkujemy się zdarzeniem /actions/ok. Następnie możemy pobrać ścieżkę wybranego pliku ze ścieżki /file_name.

To już wszystko na dzisiaj.

Szanowna Użytkowniczko! Szanowny Użytkowniku!
×
Aby dalej móc dostarczać coraz lepsze materiały redakcyjne i udostępniać coraz lepsze usługi, potrzebujemy zgody na dopasowanie treści marketingowych do Twojego zachowania. Twoje dane są u nas bezpieczne, a zgodę możesz wycofać w każdej chwili na podstronie polityka prywatności.

Kliknij "PRZECHODZĘ DO SERWISU" lub na symbol "X" w górnym rogu tej planszy, jeżeli zgadzasz się na przetwarzanie przez Wirtualną Polskę i naszych Zaufanych Partnerów Twoich danych osobowych, zbieranych w ramach korzystania przez Ciebie z usług, portali i serwisów internetowych Wirtualnej Polski (w tym danych zapisywanych w plikach cookies) w celach marketingowych realizowanych na zlecenie naszych Zaufanych Partnerów. Jeśli nie zgadzasz się na przetwarzanie Twoich danych osobowych skorzystaj z ustawień w polityce prywatności. Zgoda jest dobrowolna i możesz ją w dowolnym momencie wycofać zmieniając ustawienia w polityce prywatności (w której znajdziesz odpowiedzi na wszystkie pytania związane z przetwarzaniem Twoich danych osobowych).

Od 25 maja 2018 roku obowiązuje Rozporządzenie Parlamentu Europejskiego i Rady (UE) 2016/679 (określane jako "RODO"). W związku z tym chcielibyśmy poinformować o przetwarzaniu Twoich danych oraz zasadach, na jakich odbywa się to po dniu 25 maja 2018 roku.

Kto będzie administratorem Twoich danych?

Administratorami Twoich danych będzie Wirtualna Polska Media Spółka Akcyjna z siedzibą w Warszawie, oraz pozostałe spółki z grupy Wirtualna Polska, jak również nasi Zaufani Partnerzy, z którymi stale współpracujemy. Szczegółowe informacje dotyczące administratorów znajdują się w polityce prywatności.

O jakich danych mówimy?

Chodzi o dane osobowe, które są zbierane w ramach korzystania przez Ciebie z naszych usług, portali i serwisów internetowych udostępnianych przez Wirtualną Polskę, w tym zapisywanych w plikach cookies, które są instalowane na naszych stronach przez Wirtualną Polskę oraz naszych Zaufanych Partnerów.

Dlaczego chcemy przetwarzać Twoje dane?

Przetwarzamy je dostarczać coraz lepsze materiały redakcyjne, dopasować ich tematykę do Twoich zainteresowań, tworzyć portale i serwisy internetowe, z których będziesz korzystać z przyjemnością, zapewniać większe bezpieczeństwo usług, udoskonalać nasze usługi i maksymalnie dopasować je do Twoich zainteresowań, pokazywać reklamy dopasowane do Twoich potrzeb. Szczegółowe informacje dotyczące celów przetwarzania Twoich danych znajdują się w polityce prywatności.

Komu możemy przekazać dane?

Twoje dane możemy przekazywać podmiotom przetwarzającym je na nasze zlecenie oraz podmiotom uprawnionym do uzyskania danych na podstawie obowiązującego prawa – oczywiście tylko, gdy wystąpią z żądaniem w oparciu o stosowną podstawę prawną.

Jakie masz prawa w stosunku do Twoich danych?

Masz prawo żądania dostępu, sprostowania, usunięcia lub ograniczenia przetwarzania danych. Możesz wycofać zgodę na przetwarzanie, zgłosić sprzeciw oraz skorzystać z innych praw wymienionych szczegółowo w polityce prywatności.

Jakie są podstawy prawne przetwarzania Twoich danych?

Podstawą prawną przetwarzania Twoich danych w celu świadczenia usług jest niezbędność do wykonania umów o ich świadczenie (tymi umowami są zazwyczaj regulaminy). Podstawą prawną przetwarzania danych w celu pomiarów statystycznych i marketingu własnego administratorów jest tzw. uzasadniony interes administratora. Przetwarzanie Twoich danych w celach marketingowych realizowanych przez Wirtualną Polskę na zlecenie Zaufanych Partnerów i bezpośrednio przez Zaufanych Partnerów będzie odbywać się na podstawie Twojej dobrowolnej zgody.