/* WebDownloader for X-Window
* Copyright (C) 1999-2002 Koshelev Maxim
* This Program is free but not GPL!!! You can't modify it
* without agreement with author. You can't distribute modified
* program but you can distribute unmodified program.
*
* 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.
*/
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <pthread.h>
#include <string.h>
#include "../dlist.h"
#include "../locstr.h"
#include "../var.h"
#include "../ntlocale.h"
#include "list.h"
#include "colors.h"
#include "about.h"
#include "misc.h"
#include "themes.h"
using namespace d4x;
enum LOG_COLUMNS{
L_COL_TYPE,
L_COL_NUM,
L_COL_TIME,
L_COL_STRING,
L_COL_LAST
};
struct tLogWindow {
GtkWidget *window;
GtkTreeView *view;
GtkAdjustment *adj;
GtkWidget *button;
GtkWidget *toolbar;
GtkWidget *label;
tDownload *papa; // :))
tDownload *current;
float value;
tStringDialog *string;
tLogWindow();
~tLogWindow();
};
tLogWindow::tLogWindow() {
string=(tStringDialog *)NULL;
};
tLogWindow::~tLogWindow() {
if (string) delete string;
};
gint log_window_button(GtkWidget *button,int a);
void log_window_remember_geometry(GtkWidget *window, tLogWindow *temp){
if (window->window) {
int a[4];
gdk_window_get_root_origin(window->window,&a[0],&a[1]);
gdk_window_get_size(window->window,&a[2],&a[3]);
if (temp->papa && temp->papa->LOG)
temp->papa->LOG->store_geometry(a);
};
};
void log_window_destroy_by_log(void *a) {
tLog *log=(tLog *) a;
if (log==NULL) return;
tLogWindow *temp=(tLogWindow *)log->Window;
if (temp) {
log->Window=NULL;
log_window_remember_geometry(temp->window,temp);
temp->papa->CurrentLog=temp->papa->LOG;
gtk_widget_destroy(GTK_WIDGET(temp->window));
delete (temp);
};
};
int log_window_destroy(GtkWidget *window,GdkEvent *event, tLog *log) {
if (log) {
tLogWindow *temp=(tLogWindow *)log->Window;
if (temp) {
temp->papa->CurrentLog=NULL;
log->Window=NULL;
log_window_remember_geometry(window,temp);
gtk_widget_destroy(GTK_WIDGET(window));
delete (temp);
};
};
return TRUE;
};
void log_model_view_add_string(GtkTreeView *view,tLogString *str){
char useful[MAX_LEN+1];
struct tm msgtime;
localtime_r(&(str->time),&msgtime);
strftime(useful,MAX_LEN,"%T",&msgtime);
/* replace all nonprint symbols by space */
char *str_temp=copy_string(str->body);
str_non_print_replace(str_temp,' ');
GtkTreeIter iter;
GtkListStore *list_store=GTK_LIST_STORE(gtk_tree_view_get_model(view));
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter,
L_COL_NUM,str->temp,
L_COL_TIME,useful,
L_COL_STRING,str_temp,
-1);
delete[] str_temp;
const GdkColor *color,*back_color;
switch (str->type) {
case LOG_OK:{
gtk_list_store_set(list_store,&iter,L_COL_TYPE,CUR_THEME->get_pixbuf(LRT_OK),-1);
color=&BLACK;
back_color=&WHITE;
break;
};
case LOG_TO_SERVER: {
gtk_list_store_set(list_store,&iter,L_COL_TYPE,CUR_THEME->get_pixbuf(LRT_SEND),-1);
color=&CYAN;
back_color=&LCYAN;
break;
};
case LOG_FROM_SERVER: {
gtk_list_store_set(list_store,&iter,L_COL_TYPE,CUR_THEME->get_pixbuf(LRT_RECEIVE),-1);
color=&BLUE;
back_color=&LBLUE;
break;
};
case LOG_WARNING:{
gtk_list_store_set(list_store,&iter,L_COL_TYPE,CUR_THEME->get_pixbuf(LRT_WARNING),-1);
color=&GREEN;
back_color=&LGREEN;
break;
};
case LOG_ERROR: {
gtk_list_store_set(list_store,&iter,L_COL_TYPE,CUR_THEME->get_pixbuf(LRT_ERROR),-1);
color=&RED;
back_color=&LRED;
break;
};
default:
color=&BLACK;
back_color=&WHITE;
};
gtk_list_store_set(list_store,&iter,
L_COL_LAST,color,
L_COL_LAST+1,back_color,
-1);
};
void log_window_add_string(tLog *log,tLogString *str) {
tLogWindow *temp=(tLogWindow *)log->Window;
if (!temp) return;
log_model_view_add_string(temp->view,str);
};
static gint log_list_event_handler(GtkWidget *widget,GdkEventButton *event,tLogWindow *temp) {
if (temp && event && event->type==GDK_2BUTTON_PRESS &&
event->button==1 && temp->papa) {
GtkTreeSelection *sel=gtk_tree_view_get_selection(temp->view);
GtkTreeIter iter;
if (!gtk_tree_selection_get_selected(sel,NULL,&iter)) return FALSE;
if (temp->string==NULL) temp->string=new tStringDialog;
GValue val={0,};
GtkTreeModel *model=gtk_tree_view_get_model(temp->view);
gtk_tree_model_get_value(model,&iter,L_COL_NUM,&val);
int num=g_value_get_int(&val);
char data[MAX_LEN];
std::string rfile(hexed_string(temp->papa->info.file));
sprintf(data,_("Row number %i [log of %s]"),num,rfile.c_str());
g_value_unset(&val);
gtk_tree_model_get_value(model,&iter,L_COL_STRING,&val);
char *text=(char*)g_value_get_string(&val);
/*
int err_code=0;//GPOINTER_TO_INT(gtk_clist_get_row_data(GTK_CLIST(temp->clist),row));
char *error_name=NULL;
switch(err_code){
case LOG_ERROR:
error_name=_("Erorr!");
break;
case LOG_WARNING:
error_name=_("Warning!");
break;
case LOG_TO_SERVER:
error_name=_("Message to server");
break;
case LOG_FROM_SERVER:
error_name=_("Message from server");
break;
default:
case LOG_OK:
error_name=_("All ok");
break;
};
*/
temp->string->init(text,data,"");
g_value_unset(&val);
return TRUE;
};
return FALSE;
};
static void my_gtk_auto_scroll( GtkAdjustment *get,tLogWindow *temp){
if (get==NULL || temp==NULL) return;
if (temp->value==get->value && get->value<get->upper-get->page_size) {
get->value=get->upper-get->page_size;
temp->value=get->value;
g_signal_emit_by_name(G_OBJECT (get), "value_changed");
} else
temp->value=get->value;
}
gint log_window_button(GtkWidget *button,int a);
static gint log_window_event_handler(GtkWidget *window,GdkEvent *event,tLog *log){
if (event && event->type == GDK_KEY_PRESS) {
GdkEventKey *kevent=(GdkEventKey *)event;
tLogWindow *wnd=(tLogWindow *)log->Window;
if (!wnd->toolbar) return FALSE;
int num=-1;
if (kevent->state & GDK_CONTROL_MASK){
switch(kevent->keyval) {
case GDK_1:
num=0;
break;
case GDK_2:
num=1;
break;
case GDK_3:
num=2;
break;
case GDK_4:
num=3;
break;
case GDK_5:
num=4;
break;
case GDK_6:
num=5;
break;
case GDK_7:
num=6;
break;
case GDK_8:
num=7;
break;
case GDK_9:
num=8;
break;
case GDK_0:
num=9;
break;
};
};
gint max=gtk_toolbar_get_n_items(GTK_TOOLBAR(wnd->toolbar));
if (num>=0 && num<max-1 && wnd->toolbar){
GtkToolItem *item=gtk_toolbar_get_nth_item(GTK_TOOLBAR(wnd->toolbar),num);
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(item),TRUE);
};
if (kevent->keyval==GDK_Escape){
// g_signal_emit_by_name(G_OBJECT(window),"delete_event");
log_window_destroy_by_log(log);
return TRUE;
};
};
return FALSE;
};
void log_window_set_split_info(tDownload *what){
if (what && what->split && what->who && what->CurrentLog && what->CurrentLog->Window){
tLogWindow *temp=(tLogWindow *)what->CurrentLog->Window;
if (temp && temp->current && temp->label){
fsize_t loaded=0,begin=0,size=0;
if (temp->current->who)
loaded=temp->current->who->get_readed();
if (temp->current->split){
size=temp->current->split->LastByte;
begin=temp->current->split->FirstByte;
};
char text[100];
if (temp->current->thread_id)
sprintf(text," %Li-%Li (%Li)",begin,size,loaded);
else
sprintf(text," %Li-%Li (not active)",begin,size);
gtk_tool_button_set_label(GTK_TOOL_BUTTON(temp->label),text);
// gtk_label_set_text(GTK_LABEL(temp->label),text);
};
};
};
gint log_window_button(GtkWidget *button,int a){
tDownload *what=(tDownload *)g_object_get_data(G_OBJECT(button),"d4x_user_data");
tDownload *withlog=what;
while (withlog){
if (withlog->LOG->Window) break;
withlog=withlog->split->next_part;
};
if (what->split==NULL){
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(((tLogWindow *)(withlog->LOG->Window))->button),TRUE);
return FALSE;
};
if (withlog==NULL || withlog->LOG->Window==NULL)
return FALSE;
tDownload *forlog=what;
int b=a;
while (forlog){
a-=1;
if (a==0) break;
forlog=forlog->split->next_part;
};
if (forlog && forlog!=withlog && forlog->LOG!=NULL){
withlog->LOG->lock();
forlog->LOG->lock();
forlog->LOG->Window=withlog->LOG->Window;
withlog->LOG->Window=NULL;
withlog->LOG->unlock();
tLogWindow *temp=(tLogWindow *)(forlog->LOG->Window);
temp->current=forlog;
g_object_set_data(G_OBJECT(temp->window),"d4x_user_data",forlog->LOG);
gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(temp->view)));
forlog->LOG->print();
forlog->LOG->unlock();
what->LOG->last_log=b;
what->CurrentLog=forlog->LOG;
/* FIXME: signal_connect again???? */
g_signal_handlers_disconnect_matched(GTK_OBJECT(temp->window),
G_SIGNAL_MATCH_DATA,
0,0,NULL,NULL,
withlog->LOG);
g_signal_connect(G_OBJECT(temp->window),
"delete_event",
(GtkSignalFunc)log_window_destroy,
forlog->LOG);
g_signal_connect(G_OBJECT(temp->window), "key_press_event",
(GtkSignalFunc)log_window_event_handler, forlog->LOG);
g_signal_emit_by_name(G_OBJECT (temp->adj), "changed");
log_window_set_split_info(temp->papa);
};
if (forlog==NULL || forlog->LOG==NULL){
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(((tLogWindow *)(withlog->LOG->Window))->button),TRUE);
what->LOG->last_log=1;
};
return TRUE;
};
GtkTreeView *log_model_view_init(){
GtkListStore *list_store = gtk_list_store_new(L_COL_LAST+2,
GDK_TYPE_PIXBUF, //L_COL_TYPE,
G_TYPE_INT, //L_COL_NUM,
G_TYPE_STRING, //L_COL_TIME,
G_TYPE_STRING, //L_COL_STRING,
GDK_TYPE_COLOR, //L_COL_LAST;
GDK_TYPE_COLOR);
GtkTreeView *view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(list_store)));
GtkCellRenderer *renderer;
GtkTreeViewColumn *col;
renderer = gtk_cell_renderer_pixbuf_new();
col=gtk_tree_view_column_new_with_attributes ("Tittle",
renderer,
"pixbuf",0,
NULL);
gtk_tree_view_column_set_sizing(col,GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_column_set_resizable (col,FALSE);
gtk_tree_view_append_column(view,col);
gtk_tree_view_column_set_min_width (col,22);
gtk_tree_view_column_pack_start (col,renderer=gtk_cell_renderer_text_new(),false);
gtk_tree_view_column_add_attribute(col,renderer,"text",L_COL_NUM);
g_object_set(G_OBJECT(renderer),"xalign",1.0,0);
// gtk_tree_view_column_add_attribute(col,renderer,"background-gdk",L_COL_LAST+1);
// gtk_tree_view_column_add_attribute(col,renderer,"foreground-gdk",L_COL_LAST);
for (int i=L_COL_NUM+1;i<L_COL_LAST;i++){
renderer = gtk_cell_renderer_text_new();
if (CFG.FIXED_LOG_FONT)
g_object_set(G_OBJECT(renderer),"family","Fixed",0);
col=gtk_tree_view_column_new_with_attributes("Tittle",
renderer,
"text",i,
"foreground-gdk",L_COL_LAST,
"background-gdk",L_COL_LAST+1,
NULL);
gtk_tree_view_append_column(view,col);
gtk_tree_view_column_set_spacing(col,0);
};
gtk_tree_view_set_headers_visible(view,FALSE);
gtk_tree_view_set_reorderable(view,FALSE);
return(view);
};
void log_window_init(tDownload *what) {
if (what) {
if (what->LOG==NULL){
what->LOG=new tLog;
what->LOG->init(CFG.MAX_LOG_LENGTH);
what->LOG->ref_inc();
};
if (what->LOG->Window) {
tLogWindow *temp=(tLogWindow *)what->LOG->Window;
gtk_window_present(GTK_WINDOW(temp->window));
return;
}else{
if (what->split){
tDownload *next_part=what->split->next_part;
while (next_part){
if (next_part->LOG && next_part->LOG->Window){
tLogWindow *temp=(tLogWindow *)(next_part->LOG->Window);
gtk_window_present(GTK_WINDOW(temp->window));
return;
};
next_part=next_part->split->next_part;
};
};
};
what->LOG->lock();
tLogWindow *temp=new tLogWindow;
temp->papa=temp->current=what;
temp->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_wmclass(GTK_WINDOW(temp->window),
"D4X_Log","D4X");
int a[4];
what->LOG->get_geometry(a);
if (a[3]!=0 && a[2]!=0){
gtk_window_move(GTK_WINDOW(temp->window), a[0], a[1]);
gtk_window_set_default_size( GTK_WINDOW (temp->window), a[2], a[3]);
};
gtk_widget_set_size_request( GTK_WIDGET (temp->window), 400, 200);
char title[MAX_LEN];
title[0]=0;
strcat(title,_("Log: "));
std::string rfile(hexed_string(what->info.file));
strcat(title,rfile.c_str());
gtk_window_set_title(GTK_WINDOW (temp->window), title);
g_signal_connect(G_OBJECT(temp->window), "key_press_event",
(GtkSignalFunc)log_window_event_handler, what->LOG);
g_signal_connect(G_OBJECT(temp->window), "delete_event",
(GtkSignalFunc)log_window_destroy, what->LOG);
GtkListStore *list_store = gtk_list_store_new(L_COL_LAST+2,
GDK_TYPE_PIXBUF, //L_COL_TYPE,
G_TYPE_INT, //L_COL_NUM,
G_TYPE_STRING, //L_COL_TIME,
G_TYPE_STRING, //L_COL_STRING,
GDK_TYPE_COLOR, //L_COL_LAST;
GDK_TYPE_COLOR);
temp->view = log_model_view_init();
g_signal_connect(G_OBJECT(temp->view),"event",G_CALLBACK(log_list_event_handler),temp);
temp->adj = (GtkAdjustment *)gtk_adjustment_new (0.0, 0.0, 0.0, 0.1, 1.0, 1.0);
GtkWidget *swindow=gtk_scrolled_window_new((GtkAdjustment*)NULL,temp->adj);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(swindow),GTK_WIDGET(temp->view));
if (what->split){
GtkWidget *buttonsbar=temp->toolbar=gtk_toolbar_new();
gtk_toolbar_set_orientation(GTK_TOOLBAR(buttonsbar),GTK_ORIENTATION_HORIZONTAL);
gtk_toolbar_set_style(GTK_TOOLBAR(buttonsbar),GTK_TOOLBAR_TEXT);
GtkWidget *tmpbutton=NULL;
GSList *group=NULL;
for (int i=1;i<=what->split->NumOfParts;i++){
char data[MAX_LEN];
char tip[MAX_LEN];
g_snprintf(data,MAX_LEN," %i ",i);
g_snprintf(tip,MAX_LEN,"Ctrl+%i",i);
tmpbutton = GTK_WIDGET(gtk_radio_tool_button_new(group));
gtk_tool_button_set_label(GTK_TOOL_BUTTON(tmpbutton),data);
gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(tmpbutton),GTK_TOOLBAR(buttonsbar)->tooltips,tip,NULL);
gtk_toolbar_insert(GTK_TOOLBAR(buttonsbar),GTK_TOOL_ITEM(tmpbutton),-1);
g_signal_connect(G_OBJECT(tmpbutton),"clicked",G_CALLBACK(log_window_button),GINT_TO_POINTER(i));
group=gtk_radio_tool_button_get_group(GTK_RADIO_TOOL_BUTTON(tmpbutton));
if (what->LOG->last_log==i){
temp->button=tmpbutton;
};
g_object_set_data(G_OBJECT(tmpbutton),"d4x_user_data",what);
};
temp->label=GTK_WIDGET(gtk_tool_button_new(NULL,""));
gtk_toolbar_insert(GTK_TOOLBAR(buttonsbar),GTK_TOOL_ITEM(temp->label),-1);
// temp->label=gtk_label_new("");
// gtk_toolbar_append_widget(GTK_TOOLBAR (buttonsbar),temp->label,NULL,NULL);
GtkWidget *tmpvbox=gtk_vbox_new(FALSE,0);
gtk_box_pack_start(GTK_BOX(tmpvbox),buttonsbar,FALSE,FALSE,0);
gtk_box_pack_end(GTK_BOX(tmpvbox),swindow,TRUE,TRUE,0);
gtk_container_add(GTK_CONTAINER(temp->window),tmpvbox);
}else{
temp->toolbar=NULL;
temp->label=NULL;
gtk_container_add(GTK_CONTAINER(temp->window),swindow);
};
what->LOG->Window=temp;
g_object_set_data(G_OBJECT(temp->window),"d4x_user_data",what->LOG);
gtk_widget_show_all(temp->window);
what->LOG->print();
what->LOG->unlock(); // unlock by main thread?
what->CurrentLog=what->LOG;
g_signal_connect(G_OBJECT(temp->adj), "changed",G_CALLBACK(my_gtk_auto_scroll), temp);
temp->adj->value=temp->adj->upper-temp->adj->page_size;
temp->value=temp->adj->value;
g_signal_emit_by_name(G_OBJECT (temp->adj), "changed");
if (what->LOG->last_log>1 && what->split &&
what->LOG->last_log<=what->split->NumOfParts){
gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(temp->button),TRUE);
log_window_button(temp->button,
what->LOG->last_log);
}else{
what->LOG->last_log=1;
};
log_window_set_split_info(what);
};
};
void log_window_set_title(tDownload *what,char *title) {
if (what && what->CurrentLog && what->CurrentLog->Window) {
tLogWindow *temp=(tLogWindow *)what->CurrentLog->Window;
gtk_window_set_title(GTK_WINDOW (temp->window), title);
};
};
void del_first_from_log(tLog *what) {
tLogWindow *temp=(tLogWindow *)what->Window;
if (temp) {
GtkTreeIter iter;
GtkListStore *store=(GtkListStore *)gtk_tree_view_get_model(temp->view);
gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store),&iter);
gtk_list_store_remove(store,&iter);
};
};
GList *log_window_freeze(GList *list,tLog *what){
tLogWindow *temp=(tLogWindow *)what->Window;
if (temp){
what->freezed_flag=1;
GList *tlist=(GList *)g_malloc(sizeof(GList));
tlist->next=list;
tlist->data=what;
tlist->prev=NULL;
return(tlist);
};
return(list);
};
GList *log_window_unfreeze(GList *list){
tLog *what=(tLog *)list->data;
tLogWindow *temp=(tLogWindow *)what->Window;
GList *next=list->next;
g_free(list);
what->freezed_flag=0;
if (temp){
gtk_widget_queue_draw(GTK_WIDGET(temp->view));
};
return(next);
};
void log_print_to_view(tLog *log,GtkTreeView *view){
log->lock();
tLogString *prom=(tLogString *)(log->first());
while (prom) {
log_model_view_add_string(view,prom);
prom=(tLogString *)prom->prev;
};
log->unlock();
};
syntax highlighted by Code2HTML, v. 0.9.1