diff --git a/src/clipboard/copy.c b/src/clipboard/copy.c index 5bd99f4..afef411 100644 --- a/src/clipboard/copy.c +++ b/src/clipboard/copy.c @@ -105,6 +105,14 @@ v3270_update_system_clipboard(widget); +/* +#ifdef DEBUG + gchar *columns = v3270_get_copy_as_table(terminal,"---"); + debug("Output:\n%s",columns); + g_free(columns); +#endif // DEBUG +*/ + } LIB3270_EXPORT void v3270_append_selection(GtkWidget *widget, gboolean cut) diff --git a/src/clipboard/selection.c b/src/clipboard/selection.c index 5db24c9..9a53640 100644 --- a/src/clipboard/selection.c +++ b/src/clipboard/selection.c @@ -48,16 +48,42 @@ static void clipboard_get(G_GNUC_UNUSED GtkClipboard *clipboard, GtkSelectionDa { v3270 * terminal = GTK_V3270(obj); + if(!terminal->selection.blocks) + { + return; + } + switch(target) { case CLIPBOARD_TYPE_TEXT: // Get clipboard contents as text - - if(terminal->selection.blocks) { - g_autofree gchar * converted = v3270_get_copy_as_text(terminal); - gtk_selection_data_set_text(selection,converted,-1); + gchar *text; + + if(terminal->selection.format == V3270_SELECT_TABLE) + { + text = v3270_get_copy_as_table(terminal,"\t"); + } + else + { + text = v3270_get_copy_as_text(terminal); + } + gtk_selection_data_set_text(selection,text,-1); + g_free(text); } + break; + case CLIPBOARD_TYPE_CSV: + { + g_autofree gchar *text = v3270_get_copy_as_table(terminal,";"); + debug("Selection:\n%s",text); + gtk_selection_data_set( + selection, + gdk_atom_intern_static_string("text/csv"), + 8, + (guchar *) text, + strlen(text) + ); + } break; default: @@ -117,17 +143,26 @@ void v3270_update_system_clipboard(GtkWidget *widget) } // Has clipboard data, inform system. +//#ifdef DEBUG +// GtkClipboard * clipboard = gtk_widget_get_clipboard(widget,GDK_SELECTION_PRIMARY); +//#else GtkClipboard * clipboard = gtk_widget_get_clipboard(widget,GDK_SELECTION_CLIPBOARD); +//#endif // DEBUG // Create target list // // Reference: https://cpp.hotexamples.com/examples/-/-/g_list_insert_sorted/cpp-g_list_insert_sorted-function-examples.html // - GtkTargetList * list = gtk_target_list_new(NULL, 0); + static const GtkTargetEntry internal_targets[] = { + { "text/csv", 0, CLIPBOARD_TYPE_CSV } + }; + + GtkTargetList * list = gtk_target_list_new(internal_targets, G_N_ELEMENTS(internal_targets)); GtkTargetEntry * targets; int n_targets; gtk_target_list_add_text_targets(list, CLIPBOARD_TYPE_TEXT); + targets = gtk_target_table_new_from_list(list, &n_targets); #ifdef DEBUG diff --git a/src/clipboard/table.c b/src/clipboard/table.c new file mode 100644 index 0000000..bc8f240 --- /dev/null +++ b/src/clipboard/table.c @@ -0,0 +1,176 @@ +/* + * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 + * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a + * aplicativos mainframe. Registro no INPI sob o nome G3270. + * + * Copyright (C) <2008> + * + * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob + * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela + * Free Software Foundation. + * + * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER + * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO + * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para + * obter mais detalhes. + * + * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este + * programa; se não, escreva para a Free Software Foundation, Inc., 51 Franklin + * St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Este programa está nomeado como - e possui - linhas de código. + * + * Contatos: + * + * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) + * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) + * + */ + + #include + #include + #include + + struct ColumnDescription { + unsigned int begin; + unsigned int width; + }; + +/*--[ Implement ]------------------------------------------------------------------------------------*/ + +/// @brief Check if column has data. +static gboolean hasDataOnColumn(v3270 * terminal, unsigned int col) +{ + GList * element = terminal->selection.blocks; + + while(element) + { + lib3270_selection * block = ((lib3270_selection *) element->data); + + if( (col >= block->bounds.col) && ( col < (block->bounds.col + block->bounds.width)) ) + { + unsigned int pos = col-block->bounds.col; + unsigned int row; + + for(row = 0; row < block->bounds.height; row++) + { + if(!isspace(block->contents[pos].chr)) + { + return TRUE; + } + pos += block->bounds.width; + } + + } + + element = g_list_next(element); + } + + return FALSE; +} + +/// @brief Get column list. +GList * getColumns(v3270 * terminal) +{ + unsigned int col = 0; + GList *rc = NULL; + + while(col < lib3270_get_width(terminal->host)) { + + // debug("col(%u): %s", col, hasDataOnColumn(terminal,col) ? "yes" : "no"); + + // Get first column. + while(!hasDataOnColumn(terminal,col)) { + if(col >= lib3270_get_width(terminal->host)) + return rc; + col++; + } + + // Alocate block, add it to list. + struct ColumnDescription * columndescription = g_new0(struct ColumnDescription,1); + columndescription->begin = col; + rc = g_list_append(rc,columndescription); + + // Get width. + while(hasDataOnColumn(terminal,col++)) { + columndescription->width++; + if(col >= lib3270_get_width(terminal->host)) + return rc; + } + } + + return rc; + +} + +/// @brief Get formatted contents as single text. +gchar * v3270_get_copy_as_table(v3270 * terminal, const gchar *delimiter) +{ + GString * string = g_string_new(""); + + GList * columns = getColumns(terminal); + + debug("columns=%p",columns); + +#ifdef DEBUG + { + GList * column = columns; + while(column) + { + struct ColumnDescription * columndescription = (struct ColumnDescription *) column->data; + + debug("Begin: %u Width: %u",columndescription->begin, columndescription->width); + + column = column->next; + } + } +#endif // DEBUG + + GList * element = terminal->selection.blocks; + unsigned int width = lib3270_get_width(terminal->host); + g_autofree gchar * line = g_malloc0(width+1); + GList * column; + + while(element) + { + lib3270_selection * block = ((lib3270_selection *) element->data); + + unsigned int row, col, src = 0; + + for(row=0; row < block->bounds.height; row++) + { + + // Build text line with selected data. + memset(line,' ',width); + for(col=0; colbounds.width; col++) + { + if(block->contents[src].flags & LIB3270_ATTR_SELECTED) + { + line[block->bounds.col+col] = block->contents[src].chr; + } + + src++; + } + + debug("[%s]",line); + + // Extract columns + for(column = columns; column; column = column->next) + { + struct ColumnDescription * columndescription = (struct ColumnDescription *) column->data; + g_string_append_len(string,line+columndescription->begin,columndescription->width); + if(column->next) + g_string_append(string,delimiter); + } + g_string_append(string,"\n"); + + } + + element = g_list_next(element); + } + + g_list_free_full(columns,g_free); + + g_autofree char * text = g_string_free(string,FALSE); + return g_convert(text, -1, "UTF-8", lib3270_get_display_charset(terminal->host), NULL, NULL, NULL); +} diff --git a/src/include/clipboard.h b/src/include/clipboard.h index 3c5dd1b..2b9d6e4 100644 --- a/src/include/clipboard.h +++ b/src/include/clipboard.h @@ -43,6 +43,7 @@ enum { CLIPBOARD_TYPE_TEXT, + CLIPBOARD_TYPE_CSV, }; G_GNUC_INTERNAL void v3270_update_system_clipboard(GtkWidget *widget); @@ -50,6 +51,7 @@ /// @brief Get formatted contents as single text. G_GNUC_INTERNAL gchar * v3270_get_copy_as_text(v3270 * terminal); + G_GNUC_INTERNAL gchar * v3270_get_copy_as_table(v3270 * terminal, const gchar *delimiter); #endif // V3270_CLIPBOARD_H_INCLUDED diff --git a/v3270.cbp b/v3270.cbp index b5227f3..c600b46 100644 --- a/v3270.cbp +++ b/v3270.cbp @@ -51,6 +51,9 @@ + + -- libgit2 0.21.2