Author: rpmcruz
Date: Tue Sep 30 17:20:31 2008
New Revision: 51706
URL: http://svn.opensuse.org/viewcvs/yast?rev=51706&view=rev
Log:
* src/ygtkbargraph.h/.c: replaced usage of deprecated GtkTooltips API
by GtkTooltip.
* src/ygtktooltip.h/.c: added YGtkTooltip widget that, unlike GtkTooltip,
can be used more liberally.
* src/yzyppwrapper.h/.c: added a couple of convinience Pool calls and
a stricter full_word_match parameter to the name query.
* src/YGPackageSelector.cc: compromise for bug 428162: show a tooltip
telling the user there is a pattern available for the keyword he is
looking for once, and depending on the current view.
Added:
trunk/gtk/src/ygtktooltip.c
trunk/gtk/src/ygtktooltip.h
Modified:
trunk/gtk/ChangeLog
trunk/gtk/src/Makefile.am
trunk/gtk/src/YGPackageSelector.cc
trunk/gtk/src/ygtkbargraph.c
trunk/gtk/src/ygtkbargraph.h
trunk/gtk/src/yzyppwrapper.cc
trunk/gtk/src/yzyppwrapper.h
Modified: trunk/gtk/ChangeLog
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/ChangeLog?rev=51706&r1=51705&r2=51706&view=diff
==============================================================================
--- trunk/gtk/ChangeLog (original)
+++ trunk/gtk/ChangeLog Tue Sep 30 17:20:31 2008
@@ -1,3 +1,18 @@
+2008-09-30 Ricardo Cruz
+
+ * src/ygtkbargraph.h/.c: replaced usage of deprecated GtkTooltips API
+ by GtkTooltip.
+
+ * src/ygtktooltip.h/.c: added YGtkTooltip widget that, unlike GtkTooltip,
+ can be used more liberally.
+
+ * src/yzyppwrapper.h/.c: added a couple of convinience Pool calls and
+ a stricter full_word_match parameter to the name query.
+
+ * src/YGPackageSelector.cc: compromise for bug 428162: show a tooltip
+ telling the user there is a pattern available for the keyword he is
+ looking for once, and depending on the current view.
+
2008-09-30 Katarina Machalkova
* version 2.17.1
Modified: trunk/gtk/src/Makefile.am
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/Makefile.am?rev=51706&r1=51705&r2=51706&view=diff
==============================================================================
--- trunk/gtk/src/Makefile.am (original)
+++ trunk/gtk/src/Makefile.am Tue Sep 30 17:20:31 2008
@@ -57,6 +57,7 @@
ygtkhandlebox.c \
ygtklinklabel.c \
ygtkprogressbar.c \
+ ygtktooltip.c \
ygtkrichtext.c \
yzyppwrapper.cc \
yzypptags.cc \
Modified: trunk/gtk/src/YGPackageSelector.cc
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/YGPackageSelector.cc?rev=51706&r1=51705&r2=51706&view=diff
==============================================================================
--- trunk/gtk/src/YGPackageSelector.cc (original)
+++ trunk/gtk/src/YGPackageSelector.cc Tue Sep 30 17:20:31 2008
@@ -20,6 +20,7 @@
#include "ygtktogglebutton.h"
#include "ygtkhtmlwrap.h"
#include "ygtkhandlebox.h"
+#include "ygtktooltip.h"
#include "ygtkzyppwrapper.h"
// utilities
@@ -1558,6 +1559,41 @@
}
query->addNames (name, ' ', use_name, use_summary, use_description,
use_filelist, use_authors);
+
+ // tip: the user may be searching for patterns
+ static bool shown_pattern_tip = false;
+ if (!m_updateMode && !shown_pattern_tip &&
+ gtk_combo_box_get_active (GTK_COMBO_BOX (m_type)) == 0 &&
+ (m_statuses->getActive() == StatusButtons::AVAILABLE ||
+ m_statuses->getActive() == StatusButtons::ALL)) {
+ Ypp::QueryPool::Query *query = new Ypp::QueryPool::Query();
+ query->addType (Ypp::Package::PATTERN_TYPE);
+ query->addNames (name, ' ', true, false, false, false, false, true);
+ query->setIsInstalled (false);
+ Ypp::QueryPool pool (query);
+ if (!pool.empty()) {
+ shown_pattern_tip = true;
+ //std::string first = pool.getName (pool.getFirst());
+ std::string text =
+ _("Patterns are available that can\n"
+ "assist you in the installment\nof");
+ text += " <i>" + std::string (name) + "</i> ";
+ text += _("related packages.");
+ GtkWidget *tooltip, *box, *label, *image;
+ tooltip = ygtk_tooltip_new();
+ label = gtk_label_new (text.c_str());
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO,
+ GTK_ICON_SIZE_BUTTON);
+ box = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (box), image, FALSE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+ gtk_widget_show_all (box);
+ gtk_container_add (GTK_CONTAINER (tooltip), box);
+ ygtk_tooltip_show_at_widget (YGTK_TOOLTIP (tooltip), m_type,
+ YGTK_POINTER_UP_LEFT);
+ }
+ }
}
switch (m_statuses->getActive())
Modified: trunk/gtk/src/ygtkbargraph.c
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/ygtkbargraph.c?rev=51706&r1=51705&r2=51706&view=diff
==============================================================================
--- trunk/gtk/src/ygtkbargraph.c (original)
+++ trunk/gtk/src/ygtkbargraph.c Tue Sep 30 17:20:31 2008
@@ -7,17 +7,13 @@
#include
#include "ygtkbargraph.h"
-#include
-#include
-#include
+#include
G_DEFINE_TYPE (YGtkBarGraph, ygtk_bar_graph, YGTK_TYPE_RATIO_HBOX)
static void ygtk_bar_graph_init (YGtkBarGraph *bar)
{
// ygtk_ratio_box_set_homogeneous (YGTK_RATIO_BOX (bar), TRUE);
-
- bar->m_tooltips = gtk_tooltips_new();
gtk_container_set_border_width (GTK_CONTAINER (bar), 12);
}
@@ -86,8 +82,8 @@
}
gtk_label_set_label (GTK_LABEL (label), label_text->str);
- // Tooltip with the label -- useful if the bar entry gets too small
- gtk_tooltips_set_tip (bar->m_tooltips, box, label_text->str, NULL);
+ // tooltip for the labels -- useful if the bar entry gets too small
+ gtk_widget_set_tooltip_text (box, label_text->str);
}
// Set proportion
Modified: trunk/gtk/src/ygtkbargraph.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/ygtkbargraph.h?rev=51706&r1=51705&r2=51706&view=diff
==============================================================================
--- trunk/gtk/src/ygtkbargraph.h (original)
+++ trunk/gtk/src/ygtkbargraph.h Tue Sep 30 17:20:31 2008
@@ -10,7 +10,6 @@
#define YGTK_BAR_GRAPH_H
#include "ygtkratiobox.h"
-#include
G_BEGIN_DECLS
#define YGTK_TYPE_BAR_GRAPH (ygtk_bar_graph_get_type ())
@@ -31,9 +30,6 @@
struct _YGtkBarGraph
{
YGtkRatioHBox parent;
-
- // private
- GtkTooltips *m_tooltips;
};
struct _YGtkBarGraphClass
Added: trunk/gtk/src/ygtktooltip.c
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/ygtktooltip.c?rev=51706&view=auto
==============================================================================
--- trunk/gtk/src/ygtktooltip.c (added)
+++ trunk/gtk/src/ygtktooltip.c Tue Sep 30 17:20:31 2008
@@ -0,0 +1,199 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkTooltip widget */
+// check the header file for information about this widget
+
+#include
+#include "ygtktooltip.h"
+#include
+
+#define TOOLTIP_TIMEOUT 10000
+#define POINTER_LENGTH 10
+
+G_DEFINE_TYPE (YGtkTooltip, ygtk_tooltip, GTK_TYPE_WINDOW)
+
+static void ygtk_tooltip_init (YGtkTooltip *tooltip)
+{
+ GtkWidget *widget = GTK_WIDGET (tooltip);
+ GtkWindow *window = GTK_WINDOW (tooltip);
+ // we may need to do this if _new() not used
+ //g_object_set (G_OBJECT (tooltip), "type", GTK_WINDOW_POPUP, NULL);
+ gtk_window_set_type_hint (window, GDK_WINDOW_TYPE_HINT_TOOLTIP);
+ gtk_widget_set_app_paintable (widget, TRUE);
+ gtk_window_set_resizable (window, FALSE);
+ gtk_widget_set_name (widget, "gtk-tooltip");
+}
+
+static void ygtk_tooltip_finalize (GObject *object)
+{
+ YGtkTooltip *tooltip = YGTK_TOOLTIP (object);
+ if (tooltip->timeout_id) {
+ g_source_remove (tooltip->timeout_id);
+ tooltip->timeout_id = 0;
+ }
+ G_OBJECT_CLASS (ygtk_tooltip_parent_class)->finalize (object);
+}
+
+static void get_border (YGtkTooltip *tooltip, gint *left_border, gint *right_border,
+ gint *up_border, gint *down_border)
+{
+ GtkWidget *widget = GTK_WIDGET (tooltip);
+ *left_border = *right_border = widget->style->xthickness;
+ *up_border = *down_border = widget->style->ythickness;
+ int len = POINTER_LENGTH + 2;
+ switch (tooltip->pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_LEFT:
+ *left_border += len;
+ break;
+ case YGTK_POINTER_UP_RIGHT:
+ *right_border += len;
+ break;
+ case YGTK_POINTER_DOWN_LEFT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ *down_border += len;
+ break;
+ }
+}
+
+static void ygtk_tooltip_size_request (GtkWidget *widget, GtkRequisition *requisition)
+{
+ GTK_WIDGET_CLASS (ygtk_tooltip_parent_class)->size_request (widget, requisition);
+ gint left_border, right_border, up_border, down_border;
+ get_border (YGTK_TOOLTIP (widget), &left_border, &right_border,
+ &up_border, &down_border);
+ requisition->width += left_border + right_border;
+ requisition->height += up_border + down_border;
+}
+
+static void ygtk_tooltip_size_allocate (GtkWidget *widget, GtkAllocation *alloc)
+{
+ GTK_WIDGET_CLASS (ygtk_tooltip_parent_class)->size_allocate (widget, alloc);
+ gint left_border, right_border, up_border, down_border;
+ get_border (YGTK_TOOLTIP (widget), &left_border, &right_border,
+ &up_border, &down_border);
+ GtkAllocation child_alloc = {
+ alloc->x + left_border, alloc->y + up_border,
+ alloc->width - (left_border+right_border),
+ alloc->height - (up_border+down_border)
+ };
+ gtk_widget_size_allocate (GTK_BIN (widget)->child, &child_alloc);
+}
+
+static gboolean ygtk_tooltip_expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+ gtk_paint_flat_box (widget->style, widget->window, GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT, NULL, widget, "tooltip", 0, 0, widget->allocation.width,
+ widget->allocation.height);
+ YGtkPointerType pointer = YGTK_TOOLTIP (widget)->pointer;
+ if (pointer) {
+ gint x = 0, y = 0, len_x = 0, len_y = 0;
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_LEFT:
+ case YGTK_POINTER_DOWN_LEFT:
+ x = 2;
+ len_x = POINTER_LENGTH;
+ break;
+ case YGTK_POINTER_UP_RIGHT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ x = widget->allocation.width - 2;
+ len_x = -POINTER_LENGTH;
+ break;
+ }
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_LEFT:
+ case YGTK_POINTER_UP_RIGHT:
+ y = 2;
+ len_y = POINTER_LENGTH;
+ break;
+ case YGTK_POINTER_DOWN_LEFT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ y = widget->allocation.height - 2;
+ len_y = -POINTER_LENGTH;
+ break;
+ }
+
+ GdkPoint points[3] = {
+ { x, y }, { x + len_x, y }, { x, y + len_y } };
+ gdk_draw_polygon (widget->window, *widget->style->dark_gc, TRUE, points, 3);
+ }
+ GTK_WIDGET_CLASS (ygtk_tooltip_parent_class)->expose_event (widget, event);
+ return FALSE;
+}
+
+static gboolean tooltip_timeout_cb (void *pdata)
+{
+ YGtkTooltip *tooltip = (YGtkTooltip *) pdata;
+ tooltip->timeout_id = 0;
+ gtk_widget_destroy (GTK_WIDGET (tooltip));
+ return FALSE;
+}
+
+void ygtk_tooltip_show_at (YGtkTooltip *tooltip, gint x, gint y, YGtkPointerType pointer)
+{
+ tooltip->pointer = pointer;
+ gtk_window_move (GTK_WINDOW (tooltip), x, y);
+ gtk_widget_show (GTK_WIDGET (tooltip));
+
+ tooltip->timeout_id = g_timeout_add (TOOLTIP_TIMEOUT, tooltip_timeout_cb, tooltip);
+}
+
+#define XMARGIN 8
+#define YMARGIN 2
+
+void ygtk_tooltip_show_at_widget (YGtkTooltip *tooltip, GtkWidget *widget,
+ YGtkPointerType pointer)
+{
+ gint x, y;
+ gdk_window_get_origin (widget->window, &x, &y);
+ x += widget->allocation.x; y += widget->allocation.y;
+ tooltip->pointer = pointer;
+ GtkRequisition tooltip_req;
+ gtk_widget_size_request (GTK_WIDGET (tooltip), &tooltip_req);
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_RIGHT:
+ case YGTK_POINTER_DOWN_RIGHT:
+ x -= (tooltip_req.width - widget->allocation.width) + XMARGIN;
+ break;
+ case YGTK_POINTER_UP_LEFT:
+ case YGTK_POINTER_DOWN_LEFT:
+ x += XMARGIN;
+ break;
+ }
+ switch (pointer) {
+ case YGTK_POINTER_NONE: break;
+ case YGTK_POINTER_UP_RIGHT:
+ case YGTK_POINTER_UP_LEFT:
+ y += widget->allocation.height + YMARGIN;
+ break;
+ case YGTK_POINTER_DOWN_RIGHT:
+ case YGTK_POINTER_DOWN_LEFT:
+ y -= tooltip_req.height + YMARGIN;
+ break;
+ }
+ ygtk_tooltip_show_at (tooltip, x, y, pointer);
+}
+
+GtkWidget *ygtk_tooltip_new (void)
+{
+ return g_object_new (YGTK_TYPE_TOOLTIP, "type", GTK_WINDOW_POPUP, NULL);
+}
+
+static void ygtk_tooltip_class_init (YGtkTooltipClass *klass)
+{
+ ygtk_tooltip_parent_class = g_type_class_peek_parent (klass);
+
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = ygtk_tooltip_finalize;
+
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS (klass);
+ widget_class->size_request = ygtk_tooltip_size_request;
+ widget_class->size_allocate = ygtk_tooltip_size_allocate;
+ widget_class->expose_event = ygtk_tooltip_expose_event;
+}
+
Added: trunk/gtk/src/ygtktooltip.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/ygtktooltip.h?rev=51706&view=auto
==============================================================================
--- trunk/gtk/src/ygtktooltip.h (added)
+++ trunk/gtk/src/ygtktooltip.h Tue Sep 30 17:20:31 2008
@@ -0,0 +1,54 @@
+/********************************************************************
+ * YaST2-GTK - http://en.opensuse.org/YaST2-GTK *
+ ********************************************************************/
+
+/* YGtkTooltip, unlike GtkTooltip, can be used independently of a widget.
+ Also displays an arrow since it's meant to descript some element.
+*/
+
+#ifndef YGTK_TOOLTIP_H
+#define YGTK_TOOLTIP_H
+
+#include
+G_BEGIN_DECLS
+
+#define YGTK_TYPE_TOOLTIP (ygtk_tooltip_get_type ())
+#define YGTK_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ YGTK_TYPE_TOOLTIP, YGtkTooltip))
+#define YGTK_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ YGTK_TYPE_TOOLTIP, YGtkTooltipClass))
+#define YGTK_IS_TOOLTIP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ YGTK_TYPE_TOOLTIP))
+#define YGTK_IS_TOOLTIP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ YGTK_TYPE_TOOLTIP))
+#define YGTK_TOOLTIP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ YGTK_TYPE_TOOLTIP, YGtkTooltipClass))
+
+typedef enum { YGTK_POINTER_NONE, YGTK_POINTER_UP_LEFT, YGTK_POINTER_UP_RIGHT,
+ YGTK_POINTER_DOWN_LEFT, YGTK_POINTER_DOWN_RIGHT } YGtkPointerType;
+
+typedef struct YGtkTooltip
+{
+ GtkWindow parent;
+ // private:
+ YGtkPointerType pointer;
+ guint timeout_id;
+} YGtkTooltip;
+
+typedef struct YGtkTooltipClass
+{
+ GtkWindowClass parent_class;
+} YGtkTooltipClass;
+
+GtkWidget *ygtk_tooltip_new (void);
+GType ygtk_tooltip_get_type (void) G_GNUC_CONST;
+
+// will display the tooltip and destroy it after a few seconds
+// note: no need to free the thing yourself
+void ygtk_tooltip_show_at (YGtkTooltip *tooltip, gint x, gint y, YGtkPointerType pointer);
+void ygtk_tooltip_show_at_widget (YGtkTooltip *tooltip, GtkWidget *widget,
+ YGtkPointerType pointer);
+
+G_END_DECLS
+#endif /*YGTK_TOOLTIP_H*/
+
Modified: trunk/gtk/src/yzyppwrapper.cc
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/yzyppwrapper.cc?rev=51706&r1=51705&r2=51706&view=diff
==============================================================================
--- trunk/gtk/src/yzyppwrapper.cc (original)
+++ trunk/gtk/src/yzyppwrapper.cc Tue Sep 30 17:20:31 2008
@@ -1172,8 +1172,8 @@
Keys Ypp::Package::Type types;
Keys std::string names;
- unsigned int use_name : 1, use_summary : 1, use_description : 1, use_filelist : 1,
- use_authors : 1;
+ int use_name : 1, use_summary : 1, use_description : 1, use_filelist : 1,
+ use_authors : 1, full_word_match : 1;
Keys categories, categories2;
Keys collections;
Keys repositories;
@@ -1191,6 +1191,27 @@
bool match (Package *package)
{
+ struct inner {
+ static bool strstr (const char *str1, const char *str2,
+ bool case_sensitive, bool full_word_match)
+ {
+ const char *i;
+ if (case_sensitive)
+ i = ::strstr (str1, str2);
+ else
+ i = ::strcasestr (str1, str2);
+ if (full_word_match && i) { // check boundries
+ if (i != str1 && isalpha (i[-1]))
+ return false;
+ int len = strlen (str2);
+ if (i [len] && isalpha (i [len]))
+ return false;
+ return true;
+ }
+ return i;
+ }
+ };
+
bool match = true;
if (match && types.defined)
match = types.is (package->type());
@@ -1216,15 +1237,20 @@
const char *key = it->c_str();
bool str_match = false;
if (use_name)
- str_match = strcasestr (package->name().c_str(), key);
+ str_match = inner::strstr (package->name().c_str(), key,
+ false, full_word_match);
if (!str_match && use_summary)
- str_match = strcasestr (package->summary().c_str(), key);
+ str_match = inner::strstr (package->summary().c_str(), key,
+ false, full_word_match);
if (!str_match && use_description)
- str_match = strcasestr (package->description (false).c_str(), key);
+ str_match = inner::strstr (package->description (false).c_str(), key,
+ false, full_word_match);
if (!str_match && use_filelist)
- str_match = strcasestr (package->filelist (false).c_str(), key);
+ str_match = inner::strstr (package->filelist (false).c_str(), key,
+ false, full_word_match);
if (!str_match && use_authors)
- str_match = strcasestr (package->authors (false).c_str(), key);
+ str_match = inner::strstr (package->authors (false).c_str(), key,
+ false, full_word_match);
if (!str_match) {
match = false;
break;
@@ -1300,7 +1326,8 @@
void Ypp::QueryPool::Query::addType (Ypp::Package::Type value)
{ impl->types.add (value); }
void Ypp::QueryPool::Query::addNames (std::string value, char separator, bool use_name,
- bool use_summary, bool use_description, bool use_filelist, bool use_authors)
+ bool use_summary, bool use_description, bool use_filelist, bool use_authors,
+ bool full_word_match)
{
if (separator) {
const gchar delimiter[2] = { separator, '\0' };
@@ -1316,6 +1343,7 @@
impl->use_description = use_description;
impl->use_filelist = use_filelist;
impl->use_authors = use_authors;
+ impl->full_word_match = full_word_match;
}
void Ypp::QueryPool::Query::addCategory (Ypp::Node *value)
{ impl->categories.add (value); }
@@ -1387,6 +1415,14 @@
void Ypp::Pool::setListener (Ypp::Pool::Listener *listener)
{ impl->listener = listener; }
+int Ypp::Pool::size()
+{
+ int size = 0;
+ for (Iter iter = getFirst(); iter; iter = getNext (iter))
+ size++;
+ return size;
+}
+
Ypp::Pool::Iter Ypp::Pool::fromPath (const Ypp::Pool::Path &path)
{
Iter iter = 0;
Modified: trunk/gtk/src/yzyppwrapper.h
URL: http://svn.opensuse.org/viewcvs/yast/trunk/gtk/src/yzyppwrapper.h?rev=51706&r1=51705&r2=51706&view=diff
==============================================================================
--- trunk/gtk/src/yzyppwrapper.h (original)
+++ trunk/gtk/src/yzyppwrapper.h Tue Sep 30 17:20:31 2008
@@ -110,6 +110,8 @@
virtual Iter getParent (Iter it) = 0;
virtual Iter getChild (Iter it) = 0;
virtual bool isPlainList() const = 0;
+ bool empty() { return !getFirst(); }
+ int size();
typedef std::list <int> Path;
Iter fromPath (const Path &path);
@@ -140,7 +142,8 @@
void addType (Package::Type type);
void addNames (std::string name, char separator = 0, bool use_name = true,
bool use_summary = true, bool use_description = false,
- bool use_filelist = false, bool use_authors = false);
+ bool use_filelist = false, bool use_authors = false,
+ bool full_word_match = false);
void addCategory (Ypp::Node *category);
void addCategory2 (Ypp::Node *category);
void addCollection (const Ypp::Package *package);
--
To unsubscribe, e-mail: yast-commit+unsubscribe@opensuse.org
For additional commands, e-mail: yast-commit+help@opensuse.org