Nothing
##' @include GWidget.R
NULL
##' Toolkit constructor
##'
##' @export
##' @rdname gWidgets2RGtk2-undocumented
##' @method .gtable guiWidgetsToolkitRGtk2
## @export .gtable guiWidgetsToolkitRGtk2
.gtable.guiWidgetsToolkitRGtk2 <- function(toolkit,
items,
multiple = FALSE,
chosen.col = 1,
icon.col = NULL,
tooltip.col=NULL,
handler = NULL, action = NULL,
container = NULL, ... ) {
GTable$new(toolkit,
items=items,
multiple=multiple,
chosen.col=chosen.col,
icon.col = icon.col,
tooltip.col = tooltip.col,
handler=handler,
action=action,
container=container ,...)
}
## helper to make treeview columns based on type of data
## Need S3 methods defined outside of reference class method, not sure why
make_treeview_column <- function(x, col_no, self) UseMethod("make_treeview_column")
make_treeview_column.default <- function(x, col_no, self) {
## Return a tree view column instance to render x, located in 0-based col in model
cellrenderer <- gtkCellRendererText()
view_col <- gtkTreeViewColumnNew()
view_col$setResizable(TRUE)
view_col$PackStart(cellrenderer, TRUE)
view_col$AddAttribute(cellrenderer, "text", col_no)
## we override built in label
event_box <- gtkEventBox()
event_box$SetVisibleWindow(FALSE)
label <- gtkLabel()
## event_box$addEvents('all-events-mask')
event_box$add(label)
event_box$setAboveChild(TRUE) # gets events to box
view_col$setWidget(event_box)
view_col
}
## need to format value for Dates
make_treeview_column.Date <- function(x, col_no, self) {
## Return a tree view column instance to render x, located in 0-based col in model
cellrenderer <- gtkCellRendererText()
view_col <- gtkTreeViewColumnNew()
view_col$setResizable(TRUE)
view_col$PackStart(cellrenderer, TRUE)
view_col$AddAttribute(cellrenderer, "text", col_no)
view_col$setCellDataFunc(cellrenderer, function(vc, cr, model, iter, ...) {
## set cell value by formatting
col <- self$find_col_no(vc)
row <- as.numeric(model$getPath(iter)$toString()) + 1L
model <- self$get_model()
val <- model[row, col]
cr["text"] <- format(val)
})
## we override built in label
event_box <- gtkEventBox()
event_box$SetVisibleWindow(FALSE)
label <- gtkLabel()
## event_box$addEvents('all-events-mask')
event_box$add(label)
event_box$setAboveChild(TRUE) # gets events to box
view_col$setWidget(event_box)
view_col
}
make_treeview_column.POSIXt <- make_treeview_column.Date
##' Class for gtable widget
##'
##' This GTable class for RGtk2 implements a few additional reference
##' methods: \code{hide_names} to hide the header names;
##' \code{remove_popup_menu} to remove the popup menu;
##' \code{add_popup} to add a popup menu
##' @rdname gWidgets2RGtk2-package
GTable <- setRefClass("GTable",
contains="GWidget",
fields=list(
items="ANY",
chosen_col="integer",
icon_col="IntegerOrNULL",
tooltip_col="IntegerOrNULL"
),
methods=list(
initialize=function(toolkit=NULL,
items=NULL,
multiple = FALSE,
chosen.col = 1,
icon.col = NULL,
tooltip.col=NULL,
handler = NULL, action = NULL,
container = NULL, ... ) {
widget <<- gtkTreeViewNew()
block <<- gtkScrolledWindowNew()
block$setPolicy("GTK_POLICY_AUTOMATIC","GTK_POLICY_AUTOMATIC")
block$add(widget)
if(multiple)
set_selection_mode("multiple")
if(missing(items) || length(items) > 1)
widget$SetRulesHint(TRUE)
widget$SetEnableSearch(TRUE)
widget$setSearchColumn(1 + is.null(icon.col) - 1L)
## we want column index, not name
if(is.character(icon.col))
icon.col <- match(icon.col, names(items))
if(is.numeric(icon.col))
icon.col <- as.integer(icon.col)
if(is.character(tooltip.col))
tooltip.col <- as.integer(match(tooltip.col, names(items)))
if(is.numeric(tooltip.col))
tooltip.col <- as.integer(tooltip.col)
initFields(chosen_col=as.integer(chosen.col),
icon_col = icon.col,
tooltip_col=tooltip.col,
change_signal="changed",
default_expand=TRUE,
default_fill=TRUE,
toolkit=toolkit # needed here for gmenu call later
)
set_items(items)
add_to_parent(container, .self, ...)
## hack in click events here
click_decorator <- function(FUN) {
force(FUN)
f <- function(self, w, e, ...) {
if(e$getButton() == 1) {
if(as.numeric(e$getType()) == GdkEventType['button-press']) {
self$notify_observers(signal="button-press-event")
}
if(as.numeric(e$getType()) == GdkEventType['2button-press']) {
self$notify_observers(signal="2button-press-event")
}
}
FALSE
}
f
}
connect_to_toolkit_signal("button-press-event", click_decorator)
handler_id <<- add_handler_changed(handler, action)
callSuper(toolkit)
},
clear_columns=function() {
"Clear out old treeview columns in preparation of new"
sapply(rev(widget$getColumns()), widget$removeColumn)
},
make_columns=function() {
"Make new columns, watching out for icons, tooltips, visible"
if(!is.null(icon_col)) {
widget$InsertColumn(make_icon_column(),0L)
}
if(!is.null(tooltip_col)) {
## use column tooltip_col - 1L for a tooltip
x <- seq_along(items);
if(!is.null(tooltip_col)) {
widget$setTooltipColumn(tooltip_col - 1L)
}
}
## now add columns, one by one
DF <- get_model()
sapply(get_valid_columns(), function(col) {
treeview_col <- make_treeview_column(DF[,col], col - 1L, .self)
widget$insertColumn(treeview_col, pos = -1) # at end
})
add_popup()
},
make_icon_column=function() {
"Make column for icons"
cellrenderer <- gtkCellRendererPixbufNew()
view.col <- gtkTreeViewColumnNew()
view.col$PackStart(cellrenderer, TRUE)
view.col$AddAttribute(cellrenderer, "stock-id", icon_col - 1L)
event_box <- gtkEventBox() # need this for consistency
label <- gtkLabel()
event_box$add(label)
view.col$setWidget(event_box)
view.col
},
default_popup_menu=function(col_index) {
"Provide default popup menu (passed to gmenu(..., popup=TRUE))"
actions <- list(sort_increasing=
gaction("Sort (increasing)", handler=function(h, ...) {
DF <- get_model()
ind <- order(DF[,col_index], decreasing=FALSE)
DF$setFrame(DF[][ind,])
}),
sort_decreasing=
gaction("Sort (decreasing)", handler=function(h, ...) {
DF <- get_model()
ind <- order(DF[,col_index], decreasing=TRUE)
DF$setFrame(DF[][ind,])
}),
gseparator(),
gaction("Rename column", handler=function(h,...) {
cur_nms <- get_names()
out <- ginput("Rename column", text=cur_nms[col_index], parent=widget)
if(nchar(out)) {
cur_nms[col_index] <- out
set_names(cur_nms)
}
})
)
actions
},
add_popup_menu=function(menulist) {
f <- function(...) menulist
add_popup(f)
},
## perhaps needs optimization, loops over all columns so n^2 stuff here.
find_col_no = function(view.col) {
ind <- which(sapply(widget$getColumns(), function(i) identical(i, view.col)))
ind - !is.null(icon_col)
},
add_popup=function(menu_fun=NULL) {
"Add a popup menu to the columns. Function should generate list of actions, ..."
if(is.null(menu_fun))
menu_fun <- .self$default_popup_menu
sapply(get_view_columns(), function(view.col) {
view.col$setClickable(TRUE)
col_no <- find_col_no(view.col)
popup <- gmenu(menu_fun(col_no), popup=TRUE, toolkit=toolkit)
event_box <- view.col$getWidget()
## This is a *real* hack, as the following doesn't
## work when I use event_box. NOt sure why
## not, seems like the right combination of
## arguments is given
btn <- event_box$getParent()$getParent()$getParent()
id <- gSignalConnect(btn, "button-press-event", f=function(w, e, ...) {
if(e$button == 1 && e$type == GdkEventType['button-press']) {
popup$widget$popup(button=e$button, activate.time=e$time)
}
FALSE
})
btn$setData("popup_id", id)
})
},
remove_popup_menu=function() {
"remove popup menu from column headers"
sapply(get_view_columns(), function(view.col) {
view.col$setClickable(FALSE)
btn <- view.col$getWidget()$getParent()$getParent()$getParent()
if(!is.null(id <- btn$getData("popup_id")))
gSignalHandlerDisconnect(btn, id)
})
},
set_selection_mode=function(mode=c("none","single","browse", "multiple", "extended")) {
"Helper: Set the selection mode"
sel_model <- widget$getSelection()
sel_model$setMode(GtkSelectionMode[match.arg(mode)])
},
not_these=function() {
"Helper: Remove these indices due to icon_col, ..."
x <- unlist(list(icon_col, tooltip_col))
if(is.null(x))
x <- integer(0)
x
},
get_valid_columns=function() {
"Helper: get column indices less those for icons, tooltips, visible"
DF <- get_model()
if(!is(DF, "RGtkDataFrame"))
return(NULL)
j <- seq_len(dim(DF)[2] - 1L) # last col is ..visible
setdiff(j, not_these())
},
get_view_columns=function() {
"Helper: get non-icon columns to iterate over"
columns <- widget$getColumns()
if(!is.null(icon_col))
columns <- columns[-1]
columns
},
get_selected=function() {
"Get selected indices or numeric(0)"
sel_model <- widget$getSelection()
x <- sapply(sel_model$getSelectedRows()$retval, gtkTreePathToString)
if(is.null(x))
return(integer(0))
x <- as.numeric(x) + 1L # hide, deleted
x
},
set_selected=function(ind) {
"Set selected rows by index"
old_ind <- get_selected()
sel_model = widget$getSelection()
block_handlers()
sel_model$unselectAll()
lapply(ind, function(i) sel_model$selectPath(gtkTreePathNewFromString(i)))
unblock_handlers()
if ((length(ind) != length(old_ind)) ||
any(ind != old_ind))
invoke_change_handler()
},
get_model=function() {
"Helper: get rGtkDataFrame model, which is filtered"
m <- widget$getModel()
if(is(m, "GtkTreeModelFilter"))
m$getModel() # get past filter
else
NULL
},
## implement basic methods
get_value=function(drop=TRUE, ...) {
"Get selected values by value (or character(0))"
idx <- get_selected()
idx <- which(get_visible())[idx]
vals <- get_items(drop=FALSE)[idx, , drop=FALSE]
if(getWithDefault(drop, TRUE))
vals[, chosen_col, drop=TRUE]
else
vals
},
set_value=function(value, ...) {
"Set selected values by vector matching chosen.col, unless an integer"
block_handlers()
vals <- get_items(drop=TRUE)
if(is.numeric(value) && !is.numeric(vals))
ind <- value
else
ind <- match(value, vals)
ind <- ind[!is.na(ind)]
if(length(ind) == 0)
return() ## no match
set_index(ind)
unblock_handlers()
},
get_index = function(...) {
"Get index of selected rows or integer(0)"
idx <- get_selected()
idx <- which(get_visible())[idx]
},
set_index = function(value,...) {
"set selected values in value. integer(0) or 0L clears selection"
if(length(value) == 0 || value < 1)
widget$getSelection()$unselectAll() # clear selection if not >= 1
else {
## selected wants actual for filtered
value <- match(value, which(get_visible()))
value <- value[!is.na(value)]
set_selected(as.integer(value) - 1L)
}
},
get_items = function(i, j, ..., drop=TRUE) {
DF <- get_model()[]
if(!is.data.frame(DF) && is.list(DF))
DF <- as.data.frame(DF, stringsAsFactors=FALSE)
DF <- DF[, get_valid_columns(), drop=FALSE]
names(DF) <- get_names()
## we possibly drop out some stuff
DF[i,j, drop=getWithDefault(drop, TRUE)]
},
set_items = function(value, i, j, ...) {
block_handlers()
on.exit(unblock_handlers())
if(missing(i) && missing(j)) {
## set a new data frame model
## we shove in ..visible for the last column q
if(!is(value, "data.frame")) {
if (is.vector(value))
value <- data.frame(Values=value, stringsAsFactors=FALSE)
else if(is.matrix(value))
value <- data.frame(value, stringsAsFactors=FALSE)
}
## icons
if(!is.null(icon_col))
value[[icon_col]] <- getStockIconByName(value[[icon_col]])
## visible column
items <<- cbind(value, ..visible=rep(TRUE, nrow(value)))
model <- rGtkDataFrame(items)
filter <- model$filter()
filter$setVisibleColumn(ncol(items) -1L) # last column
clear_columns()
widget$setModel(filter)
make_columns()
set_names(names(value)[get_valid_columns()])
} else {
df_model <- get_model()
df_model[i,j] <- value ## hope case matches
}
},
set_focus = function(value) {
"If we can focus, do so, then raise"
if(value) {
widget$grabFocus()
widget$getWindow()$raise()
}
},
## data store methods
get_length=function() {
get_dim()[2]
},
get_dim=function() {
"Return dim of view (not data frame which may have extra information)"
c(rows=dim(get_model())[1], columns=length(get_valid_columns()))
},
get_names=function() {
sapply(get_view_columns(), function(col) {
label <- col$getWidget()$getChild()
label$getLabel()
})
},
set_names =function(value) {
## check length
m <- get_dim()[2]
if(length(value) != m)
return()
f <- function(col, nm) {
label <- col$getWidget()$getChild()
label$setLabel(nm)
}
mapply(f, get_view_columns(), value)
},
get_visible=function() {
## return last column in DF
DF <- get_model()
DF[, ncol(DF), drop=TRUE]
},
set_visible=function(value, ...) {
DF <- get_model()
value <- rep(value, length.out=nrow(DF))
DF[,ncol(DF)] <- value
},
set_size=function(value, ...) {
"set size also has possibility of column widths"
if(is.list(value)) {
col_widths <- value$column.widths
value$column.widths <- NULL
set_column_widths(col_widths)
value <- c(width=value$width, height=value$height) # make vector, not list
}
callSuper(value, ...)
},
set_column_widths=function(value) {
if(length(value) == get_dim()[2]) {
cols <-get_view_columns()
mapply(gtkTreeViewColumnSetMinWidth, cols, value)
}
},
## Handlers
add_handler_changed=function(handler, action=NULL, ...) {
add_handler("row-activated", handler, action, ...)
},
add_handler_selection_changed=function(handler, action=NULL, ...) {
## selection changed
if(is_handler(handler)) {
o <- gWidgets2:::observer(.self, handler, action)
invisible(add_observer(o, change_signal))
gSignalConnect(widget$getSelection(), "changed", function(self, ...) {
self$notify_observers(signal=change_signal, ...)
}, data=.self, user.data.first=TRUE)
}
},
add_handler_clicked=function(handler, action, ...) {
if(!is_handler(handler))
return()
o <- gWidgets2:::observer(.self, handler, action)
invisible(add_observer(o, "button-press-event"))
},
add_handler_double_clicked=function(handler, action, ...) {
## There is an oddity here. When using row-activated it does as desired unless
## we also have addHandlerChanged called in which case this is always called. So
## we bypass and do button and mouse events as they arise
## add_handler("row-activated", handler, action=action, ...)
if(!is_handler(handler))
return()
o <- gWidgets2:::observer(.self, handler, action)
invisible(add_observer(o, "2button-press-event"))
},
##
hide_names=function(value) {
"adjust visibility of header"
widget$setHeadersVisible(!as.logical(value))
}
))
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.