+ // removing the first event handler is equivalent to "popping" the stack
+ PopEventHandler(false);
+ return true;
+ }
+
+ // NOTE: the wxWindow event handler list is always terminated with "this" handler
+ wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
+ while ( handlerCur != this && handlerCur )
+ {
+ wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
+
+ if ( handlerCur == handlerToRemove )
+ {
+ handlerCur->Unlink();
+
+ wxASSERT_MSG( handlerCur != GetEventHandler(),
+ "the case Remove == Pop should was already handled" );
+ return true;
+ }
+
+ handlerCur = handlerNext;
+ }
+
+ wxFAIL_MSG( wxT("where has the event handler gone?") );
+
+ return false;
+}
+
+bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
+{
+ // SafelyProcessEvent() will handle exceptions nicely
+ return GetEventHandler()->SafelyProcessEvent(event);
+}
+
+// ----------------------------------------------------------------------------
+// colours, fonts &c
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::InheritAttributes()
+{
+ const wxWindowBase * const parent = GetParent();
+ if ( !parent )
+ return;
+
+ // we only inherit attributes which had been explicitly set for the parent
+ // which ensures that this only happens if the user really wants it and
+ // not by default which wouldn't make any sense in modern GUIs where the
+ // controls don't all use the same fonts (nor colours)
+ if ( parent->m_inheritFont && !m_hasFont )
+ SetFont(parent->GetFont());
+
+ // in addition, there is a possibility to explicitly forbid inheriting
+ // colours at each class level by overriding ShouldInheritColours()
+ if ( ShouldInheritColours() )
+ {
+ if ( parent->m_inheritFgCol && !m_hasFgCol )
+ SetForegroundColour(parent->GetForegroundColour());
+
+ // inheriting (solid) background colour is wrong as it totally breaks
+ // any kind of themed backgrounds
+ //
+ // instead, the controls should use the same background as their parent
+ // (ideally by not drawing it at all)
+#if 0
+ if ( parent->m_inheritBgCol && !m_hasBgCol )
+ SetBackgroundColour(parent->GetBackgroundColour());
+#endif // 0
+ }
+}
+
+/* static */ wxVisualAttributes
+wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+{
+ // it is important to return valid values for all attributes from here,
+ // GetXXX() below rely on this
+ wxVisualAttributes attrs;
+ attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+ attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+
+ // On Smartphone/PocketPC, wxSYS_COLOUR_WINDOW is a better reflection of
+ // the usual background colour than wxSYS_COLOUR_BTNFACE.
+ // It's a pity that wxSYS_COLOUR_WINDOW isn't always a suitable background
+ // colour on other platforms.
+
+#if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__))
+ attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+#else
+ attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
+#endif
+ return attrs;
+}
+
+wxColour wxWindowBase::GetBackgroundColour() const
+{
+ if ( !m_backgroundColour.IsOk() )
+ {
+ wxASSERT_MSG( !m_hasBgCol, wxT("we have invalid explicit bg colour?") );
+
+ // get our default background colour
+ wxColour colBg = GetDefaultAttributes().colBg;
+
+ // we must return some valid colour to avoid redoing this every time
+ // and also to avoid surprising the applications written for older
+ // wxWidgets versions where GetBackgroundColour() always returned
+ // something -- so give them something even if it doesn't make sense
+ // for this window (e.g. it has a themed background)
+ if ( !colBg.IsOk() )
+ colBg = GetClassDefaultAttributes().colBg;
+
+ return colBg;
+ }
+ else
+ return m_backgroundColour;
+}
+
+wxColour wxWindowBase::GetForegroundColour() const
+{
+ // logic is the same as above
+ if ( !m_hasFgCol && !m_foregroundColour.IsOk() )
+ {
+ wxColour colFg = GetDefaultAttributes().colFg;
+
+ if ( !colFg.IsOk() )
+ colFg = GetClassDefaultAttributes().colFg;
+
+ return colFg;
+ }
+ else
+ return m_foregroundColour;
+}
+
+bool wxWindowBase::SetBackgroundStyle(wxBackgroundStyle style)
+{
+ // The checks below shouldn't be triggered if we're not really changing the
+ // style.
+ if ( style == m_backgroundStyle )
+ return true;
+
+ // Transparent background style can be only set before creation because of
+ // wxGTK limitation.
+ wxCHECK_MSG( (style != wxBG_STYLE_TRANSPARENT) || !GetHandle(),
+ false,
+ "wxBG_STYLE_TRANSPARENT style can only be set before "
+ "Create()-ing the window." );
+
+ // And once it is set, wxBG_STYLE_TRANSPARENT can't be unset.
+ wxCHECK_MSG( (m_backgroundStyle != wxBG_STYLE_TRANSPARENT) ||
+ (style == wxBG_STYLE_TRANSPARENT),
+ false,
+ "wxBG_STYLE_TRANSPARENT can't be unset once it was set." );
+
+ m_backgroundStyle = style;
+
+ return true;
+}
+
+bool wxWindowBase::IsTransparentBackgroundSupported(wxString *reason) const
+{
+ if ( reason )
+ *reason = _("This platform does not support background transparency.");
+
+ return false;
+}
+
+bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
+{
+ if ( colour == m_backgroundColour )
+ return false;
+
+ m_hasBgCol = colour.IsOk();
+
+ m_inheritBgCol = m_hasBgCol;
+ m_backgroundColour = colour;
+ SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.IsOk() );
+ return true;
+}
+
+bool wxWindowBase::SetForegroundColour( const wxColour &colour )
+{
+ if (colour == m_foregroundColour )
+ return false;
+
+ m_hasFgCol = colour.IsOk();
+ m_inheritFgCol = m_hasFgCol;
+ m_foregroundColour = colour;
+ SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.IsOk() );
+ return true;
+}
+
+bool wxWindowBase::SetCursor(const wxCursor& cursor)
+{
+ // setting an invalid cursor is ok, it means that we don't have any special
+ // cursor
+ if ( m_cursor.IsSameAs(cursor) )
+ {
+ // no change
+ return false;
+ }
+
+ m_cursor = cursor;
+
+ return true;
+}
+
+wxFont wxWindowBase::GetFont() const
+{
+ // logic is the same as in GetBackgroundColour()
+ if ( !m_font.IsOk() )
+ {
+ wxASSERT_MSG( !m_hasFont, wxT("we have invalid explicit font?") );
+
+ wxFont font = GetDefaultAttributes().font;
+ if ( !font.IsOk() )
+ font = GetClassDefaultAttributes().font;
+
+ return font;
+ }
+ else
+ return m_font;
+}
+
+bool wxWindowBase::SetFont(const wxFont& font)
+{
+ if ( font == m_font )
+ {
+ // no change
+ return false;
+ }
+
+ m_font = font;
+ m_hasFont = font.IsOk();
+ m_inheritFont = m_hasFont;
+
+ InvalidateBestSize();
+
+ return true;
+}
+
+#if wxUSE_PALETTE
+
+void wxWindowBase::SetPalette(const wxPalette& pal)
+{
+ m_hasCustomPalette = true;
+ m_palette = pal;
+
+ // VZ: can anyone explain me what do we do here?
+ wxWindowDC d((wxWindow *) this);
+ d.SetPalette(pal);
+}
+
+wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const
+{
+ wxWindow *win = (wxWindow *)this;
+ while ( win && !win->HasCustomPalette() )
+ {
+ win = win->GetParent();
+ }
+
+ return win;
+}
+
+#endif // wxUSE_PALETTE
+
+#if wxUSE_CARET
+void wxWindowBase::SetCaret(wxCaret *caret)
+{
+ if ( m_caret )
+ {
+ delete m_caret;
+ }
+
+ m_caret = caret;
+
+ if ( m_caret )
+ {
+ wxASSERT_MSG( m_caret->GetWindow() == this,
+ wxT("caret should be created associated to this window") );
+ }
+}
+#endif // wxUSE_CARET
+
+#if wxUSE_VALIDATORS
+// ----------------------------------------------------------------------------
+// validators
+// ----------------------------------------------------------------------------
+
+void wxWindowBase::SetValidator(const wxValidator& validator)
+{
+ if ( m_windowValidator )
+ delete m_windowValidator;
+
+ m_windowValidator = (wxValidator *)validator.Clone();
+
+ if ( m_windowValidator )
+ m_windowValidator->SetWindow(this);
+}
+#endif // wxUSE_VALIDATORS
+
+// ----------------------------------------------------------------------------
+// update region stuff
+// ----------------------------------------------------------------------------
+
+wxRect wxWindowBase::GetUpdateClientRect() const
+{
+ wxRegion rgnUpdate = GetUpdateRegion();
+ rgnUpdate.Intersect(GetClientRect());
+ wxRect rectUpdate = rgnUpdate.GetBox();
+ wxPoint ptOrigin = GetClientAreaOrigin();
+ rectUpdate.x -= ptOrigin.x;
+ rectUpdate.y -= ptOrigin.y;
+
+ return rectUpdate;
+}
+
+bool wxWindowBase::DoIsExposed(int x, int y) const
+{
+ return m_updateRegion.Contains(x, y) != wxOutRegion;
+}
+
+bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const
+{
+ return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
+}
+
+void wxWindowBase::ClearBackground()
+{
+ // wxGTK uses its own version, no need to add never used code
+#ifndef __WXGTK__
+ wxClientDC dc((wxWindow *)this);
+ wxBrush brush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID);
+ dc.SetBackground(brush);
+ dc.Clear();
+#endif // __WXGTK__
+}
+
+// ----------------------------------------------------------------------------
+// find child window by id or name
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::FindWindow(long id) const
+{
+ if ( id == m_windowId )
+ return (wxWindow *)this;
+
+ wxWindowBase *res = NULL;
+ wxWindowList::compatibility_iterator node;
+ for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
+ {
+ wxWindowBase *child = node->GetData();
+ res = child->FindWindow( id );
+ }
+
+ return (wxWindow *)res;
+}
+
+wxWindow *wxWindowBase::FindWindow(const wxString& name) const
+{
+ if ( name == m_windowName )
+ return (wxWindow *)this;
+
+ wxWindowBase *res = NULL;
+ wxWindowList::compatibility_iterator node;
+ for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
+ {
+ wxWindow *child = node->GetData();
+ res = child->FindWindow(name);
+ }
+
+ return (wxWindow *)res;
+}
+
+
+// find any window by id or name or label: If parent is non-NULL, look through
+// children for a label or title matching the specified string. If NULL, look
+// through all top-level windows.
+//
+// to avoid duplicating code we reuse the same helper function but with
+// different comparators
+
+typedef bool (*wxFindWindowCmp)(const wxWindow *win,
+ const wxString& label, long id);
+
+static
+bool wxFindWindowCmpLabels(const wxWindow *win, const wxString& label,
+ long WXUNUSED(id))
+{
+ return win->GetLabel() == label;
+}
+
+static
+bool wxFindWindowCmpNames(const wxWindow *win, const wxString& label,
+ long WXUNUSED(id))
+{
+ return win->GetName() == label;
+}
+
+static
+bool wxFindWindowCmpIds(const wxWindow *win, const wxString& WXUNUSED(label),
+ long id)
+{
+ return win->GetId() == id;
+}
+
+// recursive helper for the FindWindowByXXX() functions
+static
+wxWindow *wxFindWindowRecursively(const wxWindow *parent,
+ const wxString& label,
+ long id,
+ wxFindWindowCmp cmp)
+{
+ if ( parent )
+ {
+ // see if this is the one we're looking for
+ if ( (*cmp)(parent, label, id) )
+ return (wxWindow *)parent;
+
+ // It wasn't, so check all its children
+ for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ // recursively check each child
+ wxWindow *win = (wxWindow *)node->GetData();
+ wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp);
+ if (retwin)
+ return retwin;
+ }
+ }
+
+ // Not found
+ return NULL;
+}
+
+// helper for FindWindowByXXX()
+static
+wxWindow *wxFindWindowHelper(const wxWindow *parent,
+ const wxString& label,
+ long id,
+ wxFindWindowCmp cmp)
+{
+ if ( parent )
+ {
+ // just check parent and all its children
+ return wxFindWindowRecursively(parent, label, id, cmp);
+ }
+
+ // start at very top of wx's windows
+ for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ // recursively check each window & its children
+ wxWindow *win = node->GetData();
+ wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp);
+ if (retwin)
+ return retwin;
+ }
+
+ return NULL;
+}
+
+/* static */
+wxWindow *
+wxWindowBase::FindWindowByLabel(const wxString& title, const wxWindow *parent)
+{
+ return wxFindWindowHelper(parent, title, 0, wxFindWindowCmpLabels);
+}
+
+/* static */
+wxWindow *
+wxWindowBase::FindWindowByName(const wxString& title, const wxWindow *parent)
+{
+ wxWindow *win = wxFindWindowHelper(parent, title, 0, wxFindWindowCmpNames);
+
+ if ( !win )
+ {
+ // fall back to the label
+ win = FindWindowByLabel(title, parent);
+ }
+
+ return win;
+}
+
+/* static */
+wxWindow *
+wxWindowBase::FindWindowById( long id, const wxWindow* parent )
+{
+ return wxFindWindowHelper(parent, wxEmptyString, id, wxFindWindowCmpIds);
+}
+
+// ----------------------------------------------------------------------------
+// dialog oriented functions
+// ----------------------------------------------------------------------------
+
+#if WXWIN_COMPATIBILITY_2_8
+void wxWindowBase::MakeModal(bool modal)
+{
+ // Disable all other windows
+ if ( IsTopLevel() )
+ {
+ wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
+ while (node)
+ {
+ wxWindow *win = node->GetData();
+ if (win != this)
+ win->Enable(!modal);
+
+ node = node->GetNext();
+ }
+ }
+}
+#endif // WXWIN_COMPATIBILITY_2_8
+
+#if wxUSE_VALIDATORS
+
+namespace
+{
+
+// This class encapsulates possibly recursive iteration on window children done
+// by Validate() and TransferData{To,From}Window() and allows to avoid code
+// duplication in all three functions.
+class ValidationTraverserBase
+{
+public:
+ wxEXPLICIT ValidationTraverserBase(wxWindowBase* win)
+ : m_win(static_cast<wxWindow*>(win))
+ {
+ }
+
+ // Traverse all the direct children calling OnDo() on them and also all
+ // grandchildren if wxWS_EX_VALIDATE_RECURSIVELY is used, calling
+ // OnRecurse() for them.
+ bool DoForAllChildren()
+ {
+ const bool recurse = m_win->HasExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
+
+ wxWindowList& children = m_win->GetChildren();
+ for ( wxWindowList::iterator i = children.begin();
+ i != children.end();
+ ++i )
+ {
+ wxWindow* const child = static_cast<wxWindow*>(*i);
+ wxValidator* const validator = child->GetValidator();
+ if ( validator && !OnDo(validator) )
+ {
+ return false;
+ }
+
+ // Notice that validation should never recurse into top level
+ // children, e.g. some other dialog which might happen to be
+ // currently shown.
+ if ( recurse && !child->IsTopLevel() && !OnRecurse(child) )
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+protected:
+ // Called for each child, validator is guaranteed to be non-NULL.
+ virtual bool OnDo(wxValidator* validator) = 0;
+
+ // Called for each child if we need to recurse into its children.
+ virtual bool OnRecurse(wxWindow* child) = 0;
+
+
+ // The window whose children we're traversing.
+ wxWindow* const m_win;
+
+ wxDECLARE_NO_COPY_CLASS(ValidationTraverserBase);
+};
+
+} // anonymous namespace
+
+#endif // wxUSE_VALIDATORS
+
+bool wxWindowBase::Validate()
+{
+#if wxUSE_VALIDATORS
+ class ValidateTraverser : public ValidationTraverserBase
+ {
+ public:
+ wxEXPLICIT ValidateTraverser(wxWindowBase* win)
+ : ValidationTraverserBase(win)
+ {
+ }
+
+ virtual bool OnDo(wxValidator* validator)
+ {
+ return validator->Validate(m_win);
+ }
+
+ virtual bool OnRecurse(wxWindow* child)
+ {
+ return child->Validate();
+ }
+ };
+
+ return ValidateTraverser(this).DoForAllChildren();
+#else // !wxUSE_VALIDATORS
+ return true;
+#endif // wxUSE_VALIDATORS/!wxUSE_VALIDATORS
+}
+
+bool wxWindowBase::TransferDataToWindow()
+{
+#if wxUSE_VALIDATORS
+ class DataToWindowTraverser : public ValidationTraverserBase
+ {
+ public:
+ wxEXPLICIT DataToWindowTraverser(wxWindowBase* win)
+ : ValidationTraverserBase(win)
+ {
+ }
+
+ virtual bool OnDo(wxValidator* validator)
+ {
+ if ( !validator->TransferToWindow() )
+ {
+ wxLogWarning(_("Could not transfer data to window"));
+#if wxUSE_LOG
+ wxLog::FlushActive();
+#endif // wxUSE_LOG
+
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual bool OnRecurse(wxWindow* child)
+ {
+ return child->TransferDataToWindow();
+ }
+ };
+
+ return DataToWindowTraverser(this).DoForAllChildren();
+#else // !wxUSE_VALIDATORS
+ return true;
+#endif // wxUSE_VALIDATORS/!wxUSE_VALIDATORS
+}
+
+bool wxWindowBase::TransferDataFromWindow()
+{
+#if wxUSE_VALIDATORS
+ class DataFromWindowTraverser : public ValidationTraverserBase
+ {
+ public:
+ DataFromWindowTraverser(wxWindowBase* win)
+ : ValidationTraverserBase(win)
+ {
+ }
+
+ virtual bool OnDo(wxValidator* validator)
+ {
+ return validator->TransferFromWindow();
+ }
+
+ virtual bool OnRecurse(wxWindow* child)
+ {
+ return child->TransferDataFromWindow();
+ }
+ };
+
+ return DataFromWindowTraverser(this).DoForAllChildren();
+#else // !wxUSE_VALIDATORS
+ return true;
+#endif // wxUSE_VALIDATORS/!wxUSE_VALIDATORS
+}
+
+void wxWindowBase::InitDialog()
+{
+ wxInitDialogEvent event(GetId());
+ event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent(event);
+}
+
+// ----------------------------------------------------------------------------
+// context-sensitive help support
+// ----------------------------------------------------------------------------
+
+#if wxUSE_HELP
+
+// associate this help text with this window
+void wxWindowBase::SetHelpText(const wxString& text)
+{
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ helpProvider->AddHelp(this, text);
+ }
+}
+
+#if WXWIN_COMPATIBILITY_2_8
+// associate this help text with all windows with the same id as this
+// one
+void wxWindowBase::SetHelpTextForId(const wxString& text)
+{
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ helpProvider->AddHelp(GetId(), text);
+ }
+}
+#endif // WXWIN_COMPATIBILITY_2_8
+
+// get the help string associated with this window (may be empty)
+// default implementation forwards calls to the help provider
+wxString
+wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt),
+ wxHelpEvent::Origin WXUNUSED(origin)) const
+{
+ wxString text;
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ text = helpProvider->GetHelp(this);
+ }
+
+ return text;
+}
+
+// show help for this window
+void wxWindowBase::OnHelp(wxHelpEvent& event)
+{
+ wxHelpProvider *helpProvider = wxHelpProvider::Get();
+ if ( helpProvider )
+ {
+ wxPoint pos = event.GetPosition();
+ const wxHelpEvent::Origin origin = event.GetOrigin();
+ if ( origin == wxHelpEvent::Origin_Keyboard )
+ {
+ // if the help event was generated from keyboard it shouldn't
+ // appear at the mouse position (which is still the only position
+ // associated with help event) if the mouse is far away, although
+ // we still do use the mouse position if it's over the window
+ // because we suppose the user looks approximately at the mouse
+ // already and so it would be more convenient than showing tooltip
+ // at some arbitrary position which can be quite far from it
+ const wxRect rectClient = GetClientRect();
+ if ( !rectClient.Contains(ScreenToClient(pos)) )
+ {
+ // position help slightly under and to the right of this window
+ pos = ClientToScreen(wxPoint(
+ 2*GetCharWidth(),
+ rectClient.height + GetCharHeight()
+ ));
+ }
+ }
+
+ if ( helpProvider->ShowHelpAtPoint(this, pos, origin) )
+ {
+ // skip the event.Skip() below
+ return;
+ }
+ }
+
+ event.Skip();
+}
+
+#endif // wxUSE_HELP
+
+// ----------------------------------------------------------------------------
+// tooltips
+// ----------------------------------------------------------------------------
+
+#if wxUSE_TOOLTIPS
+
+wxString wxWindowBase::GetToolTipText() const
+{
+ return m_tooltip ? m_tooltip->GetTip() : wxString();
+}
+
+void wxWindowBase::SetToolTip( const wxString &tip )
+{
+ // don't create the new tooltip if we already have one
+ if ( m_tooltip )
+ {
+ m_tooltip->SetTip( tip );
+ }
+ else
+ {
+ SetToolTip( new wxToolTip( tip ) );
+ }
+
+ // setting empty tooltip text does not remove the tooltip any more - use
+ // SetToolTip(NULL) for this
+}
+
+void wxWindowBase::DoSetToolTip(wxToolTip *tooltip)
+{
+ if ( m_tooltip != tooltip )
+ {
+ if ( m_tooltip )
+ delete m_tooltip;
+
+ m_tooltip = tooltip;
+ }
+}
+
+bool wxWindowBase::CopyToolTip(wxToolTip *tip)
+{
+ SetToolTip(tip ? new wxToolTip(tip->GetTip()) : NULL);
+
+ return tip != NULL;
+}
+
+#endif // wxUSE_TOOLTIPS
+
+// ----------------------------------------------------------------------------
+// constraints and sizers
+// ----------------------------------------------------------------------------
+
+#if wxUSE_CONSTRAINTS
+
+void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints )
+{
+ if ( m_constraints )
+ {
+ UnsetConstraints(m_constraints);
+ delete m_constraints;
+ }
+ m_constraints = constraints;
+ if ( m_constraints )
+ {
+ // Make sure other windows know they're part of a 'meaningful relationship'
+ if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) )