Page 1 of 1

wxIpCtrl

Posted: Tue Dec 14, 2010 8:23 am
by jfouche
Here is a class that allow to edit an IP V4 adress :

wxipctrl.h

Code: Select all

#ifndef WXIPCTRL_H_INCLUDED
#define WXIPCTRL_H_INCLUDED

#include <wx/wx.h>

DECLARE_EVENT_TYPE(wxEVT_IPCTRL_CHANGED, wxID_ANY);


// wxIpCtrl styles
#define wxIPCTRL_D_CLASS         1
#define wxIPCTRL_ALL_CLASSES	 2
#define wxIPCTRL_SUBNET_MASK     wxIPCTRL_ALL_CLASSES
#define wxIPCTRL_DEFAULT_STYLE   0


/**
 * \class wxIPCtrl
 */
class wxIpCtrl : public wxPanel
{
	long          m_ipStyle;
	wxArrayString m_defaultValue;

	wxBoxSizer* m_sizer;

	wxTextCtrl* m_editIP1;
	wxTextCtrl* m_editIP2;
	wxTextCtrl* m_editIP3;
	wxTextCtrl* m_editIP4;

	wxStaticText* m_dot1;
	wxStaticText* m_dot2;
	wxStaticText* m_dot3;

public:
	wxIpCtrl(wxWindow *parent, wxWindowID id = wxID_ANY, const wxString& ipaddr = wxT("192.168.1.12"), long style = wxIPCTRL_DEFAULT_STYLE);
	
	wxString GetValue() const;
	bool SetValue(const wxString& ipaddr);

	void SetStyle(long style) { m_ipStyle = style; }
	long GetStyle() { return m_ipStyle; }

	virtual bool Enable(bool enable = true);

protected:
	void CreateGui();
	wxTextCtrl* CreateTextCtrl();
	wxStaticText* CreateDot();

	bool CheckIp(const wxString& ipaddr, wxArrayString& ipParts) const;
	bool CheckRange(const wxString& value, unsigned long min, unsigned long max) const;
	void DoSetValue(const wxArrayString& ipParts);
	void DoSetDefaultValue();

	virtual void OnChar(wxKeyEvent& event);
	virtual void OnTextUpdated(wxCommandEvent& event);
};


#endif // WXIPCTRL_H_INCLUDED
wxipctrl.cpp

Code: Select all

#include "wxipctrl.h"
#include <wx/regex.h>
#include <wx/msgdlg.h>

DEFINE_EVENT_TYPE(wxEVT_IPCTRL_CHANGED);

static
bool in_range(unsigned long value, unsigned long min, unsigned long max)
{
	return min <= value && value <= max;
}

/**
 *
 */
wxIpCtrl::wxIpCtrl(wxWindow *parent, wxWindowID id, const wxString& ipaddr, long style)
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL)
, m_ipStyle(style)
{
	CreateGui();

	m_defaultValue.Add( wxT("192") );
	m_defaultValue.Add( wxT("168") );
	m_defaultValue.Add( wxT("1") );
	m_defaultValue.Add( wxT("12") );

	if (m_ipStyle & wxIPCTRL_D_CLASS) {
		m_defaultValue.Item(0) = wxT("224");
	}

	SetValue(ipaddr);

	Connect( wxEVT_CHAR, wxKeyEventHandler( wxIpCtrl::OnChar ) );
	m_editIP1->Connect( wxEVT_CHAR, wxKeyEventHandler( wxIpCtrl::OnChar ), NULL, this );
	m_editIP1->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxIpCtrl::OnTextUpdated ), NULL, this );
	m_editIP2->Connect( wxEVT_CHAR, wxKeyEventHandler( wxIpCtrl::OnChar ), NULL, this );
	m_editIP2->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxIpCtrl::OnTextUpdated ), NULL, this );
	m_editIP3->Connect( wxEVT_CHAR, wxKeyEventHandler( wxIpCtrl::OnChar ), NULL, this );
	m_editIP3->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxIpCtrl::OnTextUpdated ), NULL, this );
	m_editIP4->Connect( wxEVT_CHAR, wxKeyEventHandler( wxIpCtrl::OnChar ), NULL, this );
	m_editIP4->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( wxIpCtrl::OnTextUpdated ), NULL, this );
}

/**
 *
 */
void wxIpCtrl::CreateGui()
{
	SetBackgroundColour(*wxWHITE);

	m_sizer = new wxBoxSizer(wxHORIZONTAL);
	
	m_editIP1 = CreateTextCtrl();
	m_dot1    = CreateDot();
	m_editIP2 = CreateTextCtrl();
	m_dot2    = CreateDot();
	m_editIP3 = CreateTextCtrl();
	m_dot3    = CreateDot();
	m_editIP4 = CreateTextCtrl();
	
	SetSizer(m_sizer);
	Layout();
	m_sizer->Fit(this);
}

/**
 *
 */
wxTextCtrl* wxIpCtrl::CreateTextCtrl()
{
	wxTextCtrl* txtCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(40, 15), wxTE_CENTRE|wxNO_BORDER);
	txtCtrl->SetMaxLength(3);
	m_sizer->Add(txtCtrl, 0, wxALIGN_BOTTOM|wxTOP, 5);
	return txtCtrl;
}

/**
 *
 */
wxStaticText* wxIpCtrl::CreateDot()
{
	wxStaticText* staticTxt = new wxStaticText( this, wxID_ANY, _("."), wxDefaultPosition, wxDefaultSize, 0 );
	staticTxt->Wrap( -1 );
	m_sizer->Add(staticTxt, 0, wxALIGN_BOTTOM, 5);
	return staticTxt;
}

/**
 *
 */
bool wxIpCtrl::Enable(bool enable)
{
	wxColour bkColour = enable ? wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW) : wxSystemSettings::GetColour(wxSYS_COLOUR_MENU);
	SetBackgroundColour(bkColour);
	m_editIP1->SetBackgroundColour(bkColour);
	m_editIP2->SetBackgroundColour(bkColour);
	m_editIP3->SetBackgroundColour(bkColour);
	m_editIP4->SetBackgroundColour(bkColour);
	m_dot1->SetBackgroundColour(bkColour);
	m_dot2->SetBackgroundColour(bkColour);
	m_dot3->SetBackgroundColour(bkColour);
	m_editIP1->SetEditable(enable);
	m_editIP2->SetEditable(enable);
	m_editIP3->SetEditable(enable);
	m_editIP4->SetEditable(enable);
	Refresh();
	return true;
}

/**
 *
 */
wxString wxIpCtrl::GetValue() const
{
	return  m_editIP1->GetValue() + wxT(".") + m_editIP2->GetValue() + wxT(".") + m_editIP3->GetValue() + wxT(".") + m_editIP4->GetValue();
}

/**
 *
 */
bool wxIpCtrl::SetValue(const wxString& ipaddr)
{
	wxArrayString ipParts;
	if (CheckIp(ipaddr, ipParts) == false) {
		DoSetDefaultValue();
		return false;
	}
	DoSetValue(ipParts);
	return true;
}

/**
 *
 */
bool wxIpCtrl::CheckIp(const wxString& ipaddr, wxArrayString& ipParts) const
{
	wxRegEx strregex(wxT("([0-9]{1,3})([.])([0-9]{1,3})([.])([0-9]{1,3})([.])([0-9]{1,3})"));
	if (!strregex.Matches(ipaddr)) {
		return false;
	}

	ipParts.clear();
	ipParts.Add( strregex.GetMatch(ipaddr, 1) );
	ipParts.Add( strregex.GetMatch(ipaddr, 3) );
	ipParts.Add( strregex.GetMatch(ipaddr, 5) );
	ipParts.Add( strregex.GetMatch(ipaddr, 7) );
	
	unsigned long ip1, ip2, ip3, ip4;
	ipParts[0].ToULong(&ip1);
	ipParts[1].ToULong(&ip2);
	ipParts[2].ToULong(&ip3);
	ipParts[3].ToULong(&ip4);

	if (m_ipStyle & wxIPCTRL_D_CLASS) {
		if (!in_range(ip1, 224, 239)) {
			return false;
		}
	}
	else if (m_ipStyle & wxIPCTRL_ALL_CLASSES) {
		if (!in_range(ip1, 0, 255)) {
			return false;
		}
	}
	else {
		if (!in_range(ip1, 1, 223)) {
			return false;
		}
	}

	if ( !in_range(ip2, 0, 255) || !in_range(ip3, 0, 255) || !in_range(ip4, 0, 255) ) {
		return false;
	}
	return true;
}

/**
 *
 */
void wxIpCtrl::DoSetValue(const wxArrayString& ipParts)
{
	assert(ipParts.size() == 4);

	m_editIP1->ChangeValue(ipParts[0]);
	m_editIP2->ChangeValue(ipParts[1]);
	m_editIP3->ChangeValue(ipParts[2]);
	m_editIP4->ChangeValue(ipParts[3]);
}

/**
 *
 */
void wxIpCtrl::DoSetDefaultValue()
{
	m_editIP1->ChangeValue(m_defaultValue[0]);
	m_editIP2->ChangeValue(m_defaultValue[1]);
	m_editIP3->ChangeValue(m_defaultValue[2]);
	m_editIP4->ChangeValue(m_defaultValue[3]);
}

/**
 *
 */
void wxIpCtrl::OnChar(wxKeyEvent& event)
{
	const wxObject* evtObject = event.GetEventObject();

	//if ((m_ipStyle & wxIPCTRL_D_CLASS) && (evtObject == m_editIP1) ) {
	//	// Do not allow to change the ip 1 (which must be 224)
	//	return;
	//}

	const int keyCode = event.GetKeyCode();

	if (keyCode >= '0' && keyCode <= '9') {
		event.Skip();
		return;
	}

	if (keyCode == '.') {
		// deal with '.'
		if (evtObject == m_editIP1 && m_editIP1->GetStringSelection().Length() != m_editIP1->GetValue().Length()) {
				m_editIP2->SetFocus();
				m_editIP2->SetSelection(-1, -1);
		}
		else if (evtObject == m_editIP2 && m_editIP2->GetStringSelection().Length() != m_editIP2->GetValue().Length()) {
				m_editIP3->SetFocus();
				m_editIP3->SetSelection(-1, -1);
		}
		else if (evtObject == m_editIP3 && m_editIP3->GetStringSelection().Length() != m_editIP3->GetValue().Length()) {
				m_editIP4->SetFocus();
				m_editIP4->SetSelection(-1, -1);
		}
	}
	else if (keyCode == WXK_BACK) {
		if (evtObject == m_editIP2 && m_editIP2->GetValue().IsEmpty()) {
			m_editIP1->SetFocus();
			m_editIP1->SetInsertionPointEnd();
		}
		else if (evtObject == m_editIP3 && m_editIP3->GetValue().IsEmpty()) {
			m_editIP2->SetFocus();
			m_editIP2->SetInsertionPointEnd();
		}
		else if (evtObject == m_editIP4 && m_editIP4->GetValue().IsEmpty()) {
			m_editIP3->SetFocus();
			m_editIP3->SetInsertionPointEnd();
		}
		event.Skip();
	}
	else if (keyCode == WXK_LEFT || keyCode == WXK_UP) {
		if (evtObject == m_editIP2 && m_editIP2->GetInsertionPoint() == 0) {
			m_editIP1->SetFocus();
			m_editIP1->SetInsertionPointEnd();
		}
		else if (evtObject == m_editIP3 && m_editIP3->GetInsertionPoint() == 0) {
			m_editIP2->SetFocus();
			m_editIP2->SetInsertionPointEnd();
		}
		else if (evtObject == m_editIP4 && m_editIP4->GetInsertionPoint() == 0) {
			m_editIP3->SetFocus();
			m_editIP3->SetInsertionPointEnd();
		}
		event.Skip();
	}
	else if (keyCode == WXK_RIGHT || keyCode == WXK_DOWN)	{
		if (evtObject == m_editIP1 && m_editIP1->GetInsertionPoint() == m_editIP1->GetLastPosition()) {
			m_editIP2->SetFocus();
			m_editIP2->SetInsertionPoint(0);
		}
		else if (evtObject == m_editIP2 && m_editIP2->GetInsertionPoint() == m_editIP2->GetLastPosition()) {
			m_editIP3->SetFocus();
			m_editIP3->SetInsertionPoint(0);
		}
		else if (evtObject == m_editIP3 && m_editIP3->GetInsertionPoint() == m_editIP3->GetLastPosition()) {
			m_editIP4->SetFocus();
			m_editIP4->SetInsertionPoint(0);
		}
		event.Skip();
	}
	else if (keyCode == WXK_TAB || keyCode == WXK_DELETE || keyCode == WXK_END || keyCode == WXK_HOME ) {
		event.Skip();
	}
}

/**
 *
 */
void wxIpCtrl::OnTextUpdated(wxCommandEvent& event)
{
	const wxString str = event.GetString();
	if (str.Length() == 0) {
		event.Skip();
		return;
	}
	
	bool bSendEvtChanged = false;
	const wxObject* evtObject = event.GetEventObject();
	if (evtObject == m_editIP1) {
		if (m_ipStyle & wxIPCTRL_ALL_CLASSES ||
			m_ipStyle & wxIPCTRL_D_CLASS ) {
			if (CheckRange(str, 0, 255)) {
				if (str.Length() == 3) {
					m_editIP2->SetFocus();
					m_editIP2->SetSelection(-1, -1);
				}
				bSendEvtChanged = true;
			}
			else {
				m_editIP1->SetValue(wxT("0"));
				m_editIP1->SetFocus();
				m_editIP1->SetSelection(-1, -1);
			}
		}
		else {
			if (CheckRange(str, 1, 223)) {
				if (str.Length() == 3) {
					m_editIP2->SetFocus();
					m_editIP2->SetSelection(-1, -1);
				}
				bSendEvtChanged = true;
			}
			else {
				m_editIP1->SetValue(wxT("1"));
				m_editIP1->SetFocus();
				m_editIP1->SetSelection(-1, -1);
			}
		}
	}
	else if (evtObject == m_editIP2) {
		if (CheckRange(str, 0, 255)) {
			if (str.Length() == 3) {
				m_editIP3->SetFocus();
				m_editIP3->SetSelection(-1, -1);
			}
			bSendEvtChanged = true;
		}
		else {
			m_editIP2->SetValue(wxT("0"));
			m_editIP2->SetFocus();
			m_editIP2->SetSelection(-1, -1);
		}
	}
	else if (evtObject == m_editIP3) {
		if (CheckRange(str, 0, 255)) {
			if (str.Length() == 3) {
				m_editIP4->SetFocus();
				m_editIP4->SetSelection(-1, -1);
			}
			bSendEvtChanged = true;
		}
		else {
			m_editIP3->SetValue(wxT("0"));
			m_editIP3->SetFocus();
			m_editIP3->SetSelection(-1, -1);
		}
	}
	else if (evtObject == m_editIP4) {
		if (CheckRange(str, 0, 255)) {
			// do nothing
			bSendEvtChanged = true;
		}
		else {
			m_editIP4->SetValue(wxT("0"));
			m_editIP4->SetFocus();
			m_editIP4->SetSelection(-1, -1);
		}
	}

	if (bSendEvtChanged) {
		wxCommandEvent evtChanged(wxEVT_IPCTRL_CHANGED, GetId());
		evtChanged.SetString(GetValue());
		evtChanged.SetEventObject(this);
		AddPendingEvent(evtChanged);
	}

	event.Skip();
}

/**
 *
 */
bool wxIpCtrl::CheckRange(const wxString& value, unsigned long min, unsigned long max) const
{
	unsigned long v = 0;
	value.ToULong(&v, 10);

	bool inRange = in_range(v, min, max);
	if (!inRange) {
		wxString msg = wxString::Format(_("Invalid value : %s"), value.c_str());
		::wxMessageBox(msg, _("Invalid value"), wxOK | wxICON_EXCLAMATION, NULL);
	}
	return inRange;
}
Any comments are welcome