A number of focus handling improvements:
Left clicking on a window only focuses the window if not processed. wxControlContainer::SetFocus moved to wxControlContainerBase so that a container now focuses the first child even on wxGTK. wxAuiBook is now a container, need for correct navigation on wxGTK. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@48154 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// Name: wx/aui/auibook.h
|
// Name: wx/aui/auibook.h
|
||||||
// Purpose: wxaui: wx advanced user interface - notebook
|
// Purpose: wxaui: wx advanced user interface - notebook
|
||||||
// Author: Benjamin I. Williams
|
// Author: Benjamin I. Williams
|
||||||
@@ -576,7 +576,7 @@ public:
|
|||||||
virtual bool HasMultiplePages() const { return true; }
|
virtual bool HasMultiplePages() const { return true; }
|
||||||
|
|
||||||
// we don't want focus for ourselves
|
// we don't want focus for ourselves
|
||||||
virtual bool AcceptsFocus() const { return false; }
|
// virtual bool AcceptsFocus() const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -641,6 +641,9 @@ protected:
|
|||||||
DECLARE_CLASS(wxAuiNotebook)
|
DECLARE_CLASS(wxAuiNotebook)
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
WX_DECLARE_CONTROL_CONTAINER();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -42,7 +42,10 @@ public:
|
|||||||
// do accept focus initially, we'll stop doing it if/when any children
|
// do accept focus initially, we'll stop doing it if/when any children
|
||||||
// are added
|
// are added
|
||||||
m_acceptsFocus = true;
|
m_acceptsFocus = true;
|
||||||
|
m_inSetFocus = false;
|
||||||
|
m_winLastFocused = NULL;
|
||||||
}
|
}
|
||||||
|
virtual ~wxControlContainerBase() {}
|
||||||
|
|
||||||
void SetContainerWindow(wxWindow *winParent)
|
void SetContainerWindow(wxWindow *winParent)
|
||||||
{
|
{
|
||||||
@@ -51,6 +54,10 @@ public:
|
|||||||
m_winParent = winParent;
|
m_winParent = winParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// should be called from SetFocus(), returns false if we did nothing with
|
||||||
|
// the focus and the default processing should take place
|
||||||
|
bool DoSetFocus();
|
||||||
|
|
||||||
// should be called when we decide that we should [stop] accepting focus
|
// should be called when we decide that we should [stop] accepting focus
|
||||||
void SetCanFocus(bool acceptsFocus);
|
void SetCanFocus(bool acceptsFocus);
|
||||||
|
|
||||||
@@ -70,6 +77,9 @@ public:
|
|||||||
void UpdateCanFocus() { SetCanFocus(!HasAnyFocusableChildren()); }
|
void UpdateCanFocus() { SetCanFocus(!HasAnyFocusableChildren()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// set the focus to the child which had it the last time
|
||||||
|
virtual bool SetFocusToChild();
|
||||||
|
|
||||||
// return true if we have any children accepting focus
|
// return true if we have any children accepting focus
|
||||||
bool HasAnyFocusableChildren() const;
|
bool HasAnyFocusableChildren() const;
|
||||||
|
|
||||||
@@ -80,6 +90,13 @@ private:
|
|||||||
// value returned by AcceptsFocus(), should be changed using SetCanFocus()
|
// value returned by AcceptsFocus(), should be changed using SetCanFocus()
|
||||||
// only
|
// only
|
||||||
bool m_acceptsFocus;
|
bool m_acceptsFocus;
|
||||||
|
|
||||||
|
// a guard against infinite recursion
|
||||||
|
bool m_inSetFocus;
|
||||||
|
|
||||||
|
// the child which had the focus last time this panel was activated
|
||||||
|
wxWindow *m_winLastFocused;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// common part of WX_DECLARE_CONTROL_CONTAINER in the native and generic cases,
|
// common part of WX_DECLARE_CONTROL_CONTAINER in the native and generic cases,
|
||||||
@@ -90,6 +107,7 @@ public: \
|
|||||||
virtual bool AcceptsFocusRecursively() const; \
|
virtual bool AcceptsFocusRecursively() const; \
|
||||||
virtual void AddChild(wxWindowBase *child); \
|
virtual void AddChild(wxWindowBase *child); \
|
||||||
virtual void RemoveChild(wxWindowBase *child); \
|
virtual void RemoveChild(wxWindowBase *child); \
|
||||||
|
virtual void SetFocus(); \
|
||||||
void SetFocusIgnoringChildren(); \
|
void SetFocusIgnoringChildren(); \
|
||||||
void AcceptFocus(bool acceptFocus) \
|
void AcceptFocus(bool acceptFocus) \
|
||||||
{ \
|
{ \
|
||||||
@@ -118,6 +136,12 @@ protected: \
|
|||||||
return m_container.AcceptsFocusRecursively(); \
|
return m_container.AcceptsFocusRecursively(); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
void classname::SetFocus() \
|
||||||
|
{ \
|
||||||
|
if ( !m_container.DoSetFocus() ) \
|
||||||
|
basename::SetFocus(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
bool classname::AcceptsFocus() const \
|
bool classname::AcceptsFocus() const \
|
||||||
{ \
|
{ \
|
||||||
return m_container.AcceptsFocus(); \
|
return m_container.AcceptsFocus(); \
|
||||||
@@ -133,6 +157,9 @@ protected: \
|
|||||||
// this must be a real class as we forward-declare it elsewhere
|
// this must be a real class as we forward-declare it elsewhere
|
||||||
class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
|
class WXDLLEXPORT wxControlContainer : public wxControlContainerBase
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
// set the focus to the child which had it the last time
|
||||||
|
virtual bool SetFocusToChild();
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
|
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname)
|
||||||
@@ -174,30 +201,15 @@ public:
|
|||||||
void HandleOnFocus(wxFocusEvent& event);
|
void HandleOnFocus(wxFocusEvent& event);
|
||||||
void HandleOnWindowDestroy(wxWindowBase *child);
|
void HandleOnWindowDestroy(wxWindowBase *child);
|
||||||
|
|
||||||
// should be called from SetFocus(), returns false if we did nothing with
|
|
||||||
// the focus and the default processing should take place
|
|
||||||
bool DoSetFocus();
|
|
||||||
|
|
||||||
// called from OnChildFocus() handler, i.e. when one of our (grand)
|
// called from OnChildFocus() handler, i.e. when one of our (grand)
|
||||||
// children gets the focus
|
// children gets the focus
|
||||||
void SetLastFocus(wxWindow *win);
|
void SetLastFocus(wxWindow *win);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// set the focus to the child which had it the last time
|
|
||||||
bool SetFocusToChild();
|
|
||||||
|
|
||||||
// the child which had the focus last time this panel was activated
|
|
||||||
wxWindow *m_winLastFocused;
|
|
||||||
|
|
||||||
// a guard against infinite recursion
|
|
||||||
bool m_inSetFocus;
|
|
||||||
|
|
||||||
DECLARE_NO_COPY_CLASS(wxControlContainer)
|
DECLARE_NO_COPY_CLASS(wxControlContainer)
|
||||||
};
|
};
|
||||||
|
|
||||||
// this function is for wxWidgets internal use only
|
|
||||||
extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// macros which may be used by the classes wishing to implement TAB navigation
|
// macros which may be used by the classes wishing to implement TAB navigation
|
||||||
// among their children
|
// among their children
|
||||||
@@ -210,8 +222,7 @@ extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
|
|||||||
public: \
|
public: \
|
||||||
void OnNavigationKey(wxNavigationKeyEvent& event); \
|
void OnNavigationKey(wxNavigationKeyEvent& event); \
|
||||||
void OnFocus(wxFocusEvent& event); \
|
void OnFocus(wxFocusEvent& event); \
|
||||||
virtual void OnChildFocus(wxChildFocusEvent& event); \
|
virtual void OnChildFocus(wxChildFocusEvent& event)
|
||||||
virtual void SetFocus()
|
|
||||||
|
|
||||||
// implement the event table entries for wxControlContainer
|
// implement the event table entries for wxControlContainer
|
||||||
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
|
#define WX_EVENT_TABLE_CONTROL_CONTAINER(classname) \
|
||||||
@@ -237,12 +248,6 @@ public: \
|
|||||||
m_container.HandleOnNavigationKey(event); \
|
m_container.HandleOnNavigationKey(event); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
void classname::SetFocus() \
|
|
||||||
{ \
|
|
||||||
if ( !m_container.DoSetFocus() ) \
|
|
||||||
basename::SetFocus(); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
void classname::SetFocusIgnoringChildren() \
|
void classname::SetFocusIgnoringChildren() \
|
||||||
{ \
|
{ \
|
||||||
basename::SetFocus(); \
|
basename::SetFocus(); \
|
||||||
@@ -260,4 +265,7 @@ public: \
|
|||||||
|
|
||||||
#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
|
#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
|
// this function is for wxWidgets internal use only
|
||||||
|
extern bool wxSetFocusToChild(wxWindow *win, wxWindow **child);
|
||||||
|
|
||||||
#endif // _WX_CONTAINR_H_
|
#endif // _WX_CONTAINR_H_
|
||||||
|
@@ -2168,6 +2168,7 @@ wxAuiTabCtrl::wxAuiTabCtrl(wxWindow* parent,
|
|||||||
const wxSize& size,
|
const wxSize& size,
|
||||||
long style) : wxControl(parent, id, pos, size, style)
|
long style) : wxControl(parent, id, pos, size, style)
|
||||||
{
|
{
|
||||||
|
SetName(wxT("wxAuiTabCtrl"));
|
||||||
m_click_pt = wxDefaultPosition;
|
m_click_pt = wxDefaultPosition;
|
||||||
m_is_dragging = false;
|
m_is_dragging = false;
|
||||||
m_hover_button = NULL;
|
m_hover_button = NULL;
|
||||||
@@ -2712,8 +2713,12 @@ BEGIN_EVENT_TABLE(wxAuiNotebook, wxControl)
|
|||||||
wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP,
|
wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP,
|
||||||
wxAuiNotebook::OnTabRightUp)
|
wxAuiNotebook::OnTabRightUp)
|
||||||
EVT_NAVIGATION_KEY(wxAuiNotebook::OnNavigationKey)
|
EVT_NAVIGATION_KEY(wxAuiNotebook::OnNavigationKey)
|
||||||
|
|
||||||
|
WX_EVENT_TABLE_CONTROL_CONTAINER(wxAuiNotebook)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
WX_DELEGATE_TO_CONTROL_CONTAINER(wxAuiNotebook, wxControl)
|
||||||
|
|
||||||
wxAuiNotebook::wxAuiNotebook()
|
wxAuiNotebook::wxAuiNotebook()
|
||||||
{
|
{
|
||||||
m_curpage = -1;
|
m_curpage = -1;
|
||||||
@@ -2754,6 +2759,10 @@ bool wxAuiNotebook::Create(wxWindow* parent,
|
|||||||
// code called by all constructors
|
// code called by all constructors
|
||||||
void wxAuiNotebook::InitNotebook(long style)
|
void wxAuiNotebook::InitNotebook(long style)
|
||||||
{
|
{
|
||||||
|
WX_INIT_CONTROL_CONTAINER();
|
||||||
|
// SetCanFocus(false);
|
||||||
|
|
||||||
|
SetName(wxT("wxAuiNotebook"));
|
||||||
m_curpage = -1;
|
m_curpage = -1;
|
||||||
m_tab_id_counter = wxAuiBaseTabCtrlId;
|
m_tab_id_counter = wxAuiBaseTabCtrlId;
|
||||||
m_dummy_wnd = NULL;
|
m_dummy_wnd = NULL;
|
||||||
|
@@ -77,6 +77,52 @@ bool wxControlContainerBase::HasAnyFocusableChildren() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxControlContainerBase::DoSetFocus()
|
||||||
|
{
|
||||||
|
wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."),
|
||||||
|
m_winParent->GetHandle());
|
||||||
|
|
||||||
|
if (m_inSetFocus)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// when the panel gets the focus we move the focus to either the last
|
||||||
|
// window that had the focus or the first one that can get it unless the
|
||||||
|
// focus had been already set to some other child
|
||||||
|
|
||||||
|
wxWindow *win = wxWindow::FindFocus();
|
||||||
|
while ( win )
|
||||||
|
{
|
||||||
|
if ( win == m_winParent )
|
||||||
|
{
|
||||||
|
// our child already has focus, don't take it away from it
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( win->IsTopLevel() )
|
||||||
|
{
|
||||||
|
// don't look beyond the first top level parent - useless and
|
||||||
|
// unnecessary
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
win = win->GetParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// protect against infinite recursion:
|
||||||
|
m_inSetFocus = true;
|
||||||
|
|
||||||
|
bool ret = SetFocusToChild();
|
||||||
|
|
||||||
|
m_inSetFocus = false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxControlContainerBase::SetFocusToChild()
|
||||||
|
{
|
||||||
|
return wxSetFocusToChild(m_winParent, &m_winLastFocused);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
|
#ifndef wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@@ -86,7 +132,6 @@ bool wxControlContainerBase::HasAnyFocusableChildren() const
|
|||||||
wxControlContainer::wxControlContainer()
|
wxControlContainer::wxControlContainer()
|
||||||
{
|
{
|
||||||
m_winLastFocused = NULL;
|
m_winLastFocused = NULL;
|
||||||
m_inSetFocus = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxControlContainer::SetLastFocus(wxWindow *win)
|
void wxControlContainer::SetLastFocus(wxWindow *win)
|
||||||
@@ -552,47 +597,6 @@ void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child)
|
|||||||
// focus handling
|
// focus handling
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
bool wxControlContainer::DoSetFocus()
|
|
||||||
{
|
|
||||||
wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."),
|
|
||||||
m_winParent->GetHandle());
|
|
||||||
|
|
||||||
if (m_inSetFocus)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// when the panel gets the focus we move the focus to either the last
|
|
||||||
// window that had the focus or the first one that can get it unless the
|
|
||||||
// focus had been already set to some other child
|
|
||||||
|
|
||||||
wxWindow *win = wxWindow::FindFocus();
|
|
||||||
while ( win )
|
|
||||||
{
|
|
||||||
if ( win == m_winParent )
|
|
||||||
{
|
|
||||||
// our child already has focus, don't take it away from it
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( win->IsTopLevel() )
|
|
||||||
{
|
|
||||||
// don't look beyond the first top level parent - useless and
|
|
||||||
// unnecessary
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
win = win->GetParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
// protect against infinite recursion:
|
|
||||||
m_inSetFocus = true;
|
|
||||||
|
|
||||||
bool ret = SetFocusToChild();
|
|
||||||
|
|
||||||
m_inSetFocus = false;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
|
void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
|
||||||
{
|
{
|
||||||
wxLogTrace(TRACE_FOCUS, _T("OnFocus on wxPanel 0x%p, name: %s"),
|
wxLogTrace(TRACE_FOCUS, _T("OnFocus on wxPanel 0x%p, name: %s"),
|
||||||
@@ -604,11 +608,18 @@ void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
|
|||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
// wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
bool wxControlContainer::SetFocusToChild()
|
bool wxControlContainer::SetFocusToChild()
|
||||||
{
|
{
|
||||||
return wxSetFocusToChild(m_winParent, &m_winLastFocused);
|
return wxSetFocusToChild(m_winParent, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // !wxHAS_NATIVE_TAB_TRAVERSAL
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
|
// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
|
||||||
// wxMSW, this is why it is outside of wxControlContainer class
|
// wxMSW, this is why it is outside of wxControlContainer class
|
||||||
@@ -617,10 +628,10 @@ bool wxControlContainer::SetFocusToChild()
|
|||||||
bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
|
bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
|
||||||
{
|
{
|
||||||
wxCHECK_MSG( win, false, _T("wxSetFocusToChild(): invalid window") );
|
wxCHECK_MSG( win, false, _T("wxSetFocusToChild(): invalid window") );
|
||||||
wxCHECK_MSG( childLastFocused, false,
|
// wxCHECK_MSG( childLastFocused, false,
|
||||||
_T("wxSetFocusToChild(): NULL child poonter") );
|
// _T("wxSetFocusToChild(): NULL child poonter") );
|
||||||
|
|
||||||
if ( *childLastFocused )
|
if ( childLastFocused && *childLastFocused )
|
||||||
{
|
{
|
||||||
// It might happen that the window got reparented
|
// It might happen that the window got reparented
|
||||||
if ( (*childLastFocused)->GetParent() == win )
|
if ( (*childLastFocused)->GetParent() == win )
|
||||||
@@ -670,6 +681,7 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
|
|||||||
_T("SetFocusToChild() => first child (0x%p)."),
|
_T("SetFocusToChild() => first child (0x%p)."),
|
||||||
child->GetHandle());
|
child->GetHandle());
|
||||||
|
|
||||||
|
if (childLastFocused)
|
||||||
*childLastFocused = child;
|
*childLastFocused = child;
|
||||||
child->SetFocusFromKbd();
|
child->SetFocusFromKbd();
|
||||||
return true;
|
return true;
|
||||||
@@ -679,4 +691,3 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !wxHAS_NATIVE_TAB_TRAVERSAL
|
|
||||||
|
@@ -1440,11 +1440,6 @@ gtk_window_button_press_callback( GtkWidget *widget,
|
|||||||
|
|
||||||
g_lastButtonNumber = gdk_event->button;
|
g_lastButtonNumber = gdk_event->button;
|
||||||
|
|
||||||
if (win->m_wxwindow && (g_focusWindow != win) && win->IsFocusable())
|
|
||||||
{
|
|
||||||
gtk_widget_grab_focus( win->m_wxwindow );
|
|
||||||
}
|
|
||||||
|
|
||||||
// GDK sends surplus button down events
|
// GDK sends surplus button down events
|
||||||
// before a double click event. We
|
// before a double click event. We
|
||||||
// need to filter these out.
|
// need to filter these out.
|
||||||
@@ -1576,9 +1571,9 @@ gtk_window_button_press_callback( GtkWidget *widget,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
|
if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
|
||||||
(g_focusWindow != win) && win->IsFocusable())
|
(g_focusWindow != win) /* && win->IsFocusable() */)
|
||||||
{
|
{
|
||||||
gtk_widget_grab_focus( win->m_wxwindow );
|
win->SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_type == wxEVT_RIGHT_DOWN)
|
if (event_type == wxEVT_RIGHT_DOWN)
|
||||||
@@ -1870,8 +1865,10 @@ gtk_window_focus_out_callback( GtkWidget *widget,
|
|||||||
// Disable default focus handling for custom windows
|
// Disable default focus handling for custom windows
|
||||||
// since the default GTK+ handler issues a repaint
|
// since the default GTK+ handler issues a repaint
|
||||||
if ( has_wxwindow )
|
if ( has_wxwindow )
|
||||||
|
{
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// continue with normal processing
|
// continue with normal processing
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
Reference in New Issue
Block a user