<?php
    
/**
     * IPv4 Entry widget
     *
     * IPEntry performs some checks to see if userinput is valid and implements the
     * get_text() and set_text() methods found in regular GtkEntry widgets for
     * compatibility and ease of use.
     *
     * Small warning note: Needs to be fitted within a GtkAlignment because it will
     * take up all available space otherwise.
     *
     * @author Robert van der Linde <robert@linde002.nl>
     * @version 1.1
     */
    
class IPv4Entry extends GtkFrame
    
{
        
/**
         * Contains the four GtkEntry fields.
         *
         * @var array
         */
        
protected $aEntries = array();
        
        
/**
         * The GtkEntry currently selected
         *
         * @var int
         */
        
protected $iCurrentEntry = 0;
        
        
/**
         * Creates a IPEntry widget
         *
         */
        
public function __construct()
        {
            
parent::__construct();
            
            
/**
             * The container for all the GtkEntries
             */
            
$oHBox = new GtkHBox();
            
            
/**
             * Create four GtkEntry fields
             */
            
for ($x=0; $x<4; $x++)
            {
                
$this->aEntries[$x] = new GtkEntry();
                
                
/**
                 * Align the text in the middle of the GtkEntry. Looks pretty
                 */
                
$this->aEntries[$x]->set_property('xalign', 0.5);
                
$this->aEntries[$x]->set_property('has-frame', 0);
                
$this->aEntries[$x]->set_size_request(30, -1);
                
                
/**
                 * I know we skip fields after max 3 characters but if a user keeps
                 * the button pressed there is a possibility that he can continue inputting
                 * numbers. Let's not allow this.
                 */
                
$this->aEntries[$x]->set_max_length(3);
                
                
/**
                 * Default to 0
                 */
                
$this->aEntries[$x]->set_text('0');
                
                
/**
                 * Connect the callback signals used to perform input checking
                 */
                
$this->aEntries[$x]->connect('key-press-event', array($this, 'onButtonDown'), $x);
                
$this->aEntries[$x]->connect('key-release-event', array($this, 'onButtonUp'), $x);
                
                
$oHBox->pack_start($this->aEntries[$x], 0);
                
                
/**
                 * If this is the last entry field don't add the dot.
                 */
                
if($x != 3)
                    
$oHBox->pack_start(new GtkLabel('.'), 0);
            }
            
            
/**
             * Pack it all in a pretty eventbox so we can set the general background color.
             */
            
$oEventBox = new GtkEventBox();
            
$oEventBox->add($oHBox);
            
$oEventBox->modify_bg(Gtk::STATE_NORMAL, GdkColor::parse("#ffffff"));
            
$this->add($oEventBox);
            
$this->set_shadow_type(Gtk::SHADOW_ETCHED_OUT);
        }
        
        
/**
         * Called when a user starts inputting a character. If that character is a dot
         * we jump to the next entry field and suppress the dot.
         *
         * @param GtkEntry $oEntry
         * @param GdkEvent $oEvent
         * @param int $iEntryid
         * @return boolean
         */
        
public function onButtonDown(GtkEntry $oEntry, GdkEvent $oEvent, $iEntryid)
        {
            if(
chr($oEvent->keyval) == '.')
            {
                
$sTxt = $oEntry->get_text();
                if(
$iEntryid != 3)
                    
$this->aEntries[$iEntryid+1]->grab_focus();
                
/**
                 * @deprecated Stopped tabbing to the first field as users found this
                 * to be unexpected behaviour (frightened small children)
                 * else
                 *   $this->aEntries[0]->grab_focus();
                 */
                
                
return true;
            }
            elseif(!
ereg('^[0-9]+$', chr($oEvent->keyval)))
                return
true;
            else
                return
false;
        }
        
        
/**
         * Called when a user finishes inputting a character. If the character is
         * the third digit or by inputting the character makes the value higher then 25
         * jump to the next inputfield.
         *
         * @since 1.0
         * If this inputfield is selected by way of using TAB or dot we do not check the
         * value of the input fields. This is a workaround to stop the widget from entering
         * a possible infiniteloop when all input fields are > 25
         *
         * @param GtkEntry $oEntry
         * @param GdkEvent $oEvent
         * @param int $iEntryid
         */
        
public function onButtonUp(GtkEntry $oEntry, GdkEvent $oEvent, $iEntryid)
        {
            if(
$oEvent->keyval != Gdk::KEY_Tab && chr($oEvent->keyval) != '.')
            {
                if(
strlen(trim($oEntry->get_text())) == 3 || trim($oEntry->get_text()) > 25)
                {
                    if(
$iEntryid != 3)
                        
$this->aEntries[$iEntryid+1]->grab_focus();
                }
                
                
/**
                 * If the inputfield has a value higher then 255 reset it to 255
                 */
                
if(trim($oEntry->get_text()) > 255)
                    
$oEntry->set_text('255');
            }
        }
        
        
/**
         * Implementation of the GtkEntry::set_text() function for usability.
         * Checks if the string is a valid ip address (does it's best to create
         * one if it received an invalid string)
         *
         * When it fails to do so defaults to 0.0.0.0
         *
         * @param string $sIP
         */
        
public function set_text($sIP)
        {
            
$aIPSections = explode('.', long2ip(ip2long($sIP)));
            for(
$x=0; $x<4; $x++)
                
$this->aEntries[$x]->set_text($aIPSections[$x]);
        }
        
        
/**
         * Implementation of the GtkEntry::get_text() function for usability.
         * Returns a concatenation of the GtkEntry fields and dots.
         *
         * @return string
         */
        
public function get_text()
        {
            
$sIP = '';
            for(
$x=0; $x<4; $x++)
            {
                
$sIP .= trim($this->aEntries[$x]->get_text());
                if(
$x != 3)
                    
$sIP .= ".";
            }
            
            return
$sIP;
        }
    }
?>