2012-03-23

Joomla - create a profile plugin with custom fields

This plugin is based on the code found here:
http://docs.joomla.org/Creating_a_profile_plugin


Like I mentioned in an earlier post, where I showed how to add custom fields to the profile plugin that is already included with Joomla, the joomla example is very useful, but doesn't really get into adding new fields.  What I recommend is comparing that code with my code to see what I changed.  Also you can refer to my old post for some guidance.  I would use a diff tool like Meld.  To install in Fedora 16 just type:


yum install meld
in a command line terminal.


These files need to be created inside of your Joomla 2.5.4 installation.  The paths given are relative to the root of the installation.  These will not be overwritten during updates, because these names and paths do not exist in the original, but I do keep some backups, just in case.


The below 5 files comprise the entire plugin. First, create them all in their appropriate places on the server. (Just click the links below to download the files).


Then just go to the Extension Manager: Discover tab in the Joomla Administrator panel in the back end and click the blue "Discover" button on the upper right.  If you've done everything right, Joomla should see it listed as "Profile 7".  Check the box next to it and then click the yellow "Install" button on the upper right.  It should be ready to go.  You now should be able to find it in Joomla, Plug-in Manager: Plug-ins, and enable it.  Be sure and disable any other profile plugins you may have running, including the stock Joomla Profile plugin, or there could be conflicts OR they will both be displayed on your register and profile edit pages!

/administrator/language/en-GB/en-GB.plg_user_profile7.ini
/administrator/language/en-GB/en-GB.plg_user_profile7.sys.ini

(I want to point out that I originally posted the wrong path for the last file above as:
 /plugins/user/profile/profiles/profile.xml
I was missing a "7" there.  Thanks to Patrick for pointing that out, and sorry for any trouble this may have caused to anyone who was trying this.)

Please note, that the last file listed above is "profile.xml", not profile7 like the others.  This is VERY important.  Be careful!  These locations are in the Joomla installation.  Create them all with gedit or your text editor of choice (or just download them, now that I've posted links) and place them in their places on your server using an FTP client (or however you can get them there).  I use FileZilla.  (Sorry, but I don't have time to give a tut on using FTP or any other method of writing files to your server, maybe some other time.)

Here are the files.  I tried to highlight in blue the differences between my plugin and the standard plugin, I may have missed highlighting a "7" on a "Profile 7" here or there - they are peppered throughout all 5 files and finding and creating these inside the original code was the biggest challenge of the entire project.  (You see I couldn't just leave it with the name "profile" because then it would be overwritten every time you update, just like the standard plugin.) I will post both the content and links for download:
( NOTE:  I would LOVE to have these files posted in a prettier format.  If you happen to know a way to post frames inside of blogger or know anything that would make these look better, please let me know!)

en-GB.plg_user_profile7.ini (click for download)
-------------------------------------------------------------------------------------------------------------------

; Joomla! Project
; Copyright (C) 2005 - 2012 Open Source Matters. All rights reserved.
; License http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_USER_PROFILE7_XML_DESCRIPTION="User Profile 7 Plug-in"
PLG_USER_PROFILE7="User - Profile 7"
PLG_USER_PROFILE7_SLIDER_LABEL="User Profile 7"
PLG_USER_PROFILE7_FIELD_ABOUT_ME_DESC="Choose an option for the field About Me."
PLG_USER_PROFILE7_FIELD_ABOUT_ME_LABEL="About Me:"
PLG_USER_PROFILE7_FIELD_ADDRESS1_DESC="Choose an option for the field Address1"
PLG_USER_PROFILE7_FIELD_ADDRESS1_LABEL="Address 1:"
PLG_USER_PROFILE7_FIELD_ADDRESS2_DESC="Choose an option for the field Address2"
PLG_USER_PROFILE7_FIELD_ADDRESS2_LABEL="Address 2:"
PLG_USER_PROFILE7_FIELD_CITY_DESC="Choose an option for the field City"
PLG_USER_PROFILE7_FIELD_CITY_LABEL="City:"
PLG_USER_PROFILE7_FIELD_COUNTRY_DESC="Choose an option for the field Country"
PLG_USER_PROFILE7_FIELD_COUNTRY_LABEL="Country:"
PLG_USER_PROFILE7_FIELD_COUNTRY_MESSAGE="Country Required"
PLG_USER_PROFILE7_FIELD_DOB_DESC="Choose an option for the field Date of Birth"
PLG_USER_PROFILE7_FIELD_DOB_LABEL="Date of Birth:"
PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_DESC="Choose an option for the field Favourite Book"
PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_LABEL="Favourite Book:"
PLG_USER_PROFILE7_FIELD_NAME_PROFILE_REQUIRE_USER="User profile fields for Profile 7 edit form"
PLG_USER_PROFILE7_FIELD_NAME_REGISTER_REQUIRE_USER="User profile fields for registration and administrator user Profile 7 forms"
PLG_USER_PROFILE7_FIELD_PHONE_DESC="Choose an option for the field Phone"
PLG_USER_PROFILE7_FIELD_PHONE_LABEL="Phone:"
PLG_USER_PROFILE7_FIELD_POSTAL_CODE_DESC="Choose an option for the field Postal Code"
PLG_USER_PROFILE7_FIELD_POSTAL_CODE_LABEL="Postal / ZIP Code:"
PLG_USER_PROFILE7_FIELD_POSTAL_CODE_MESSAGE="Postal Code Required"
PLG_USER_PROFILE7_FIELD_REGION_DESC="Choose an option for the field Region"
PLG_USER_PROFILE7_FIELD_REGION_LABEL="Region:"
PLG_USER_PROFILE7_FIELD_TOS_DESC="Agree to terms of service"
PLG_USER_PROFILE7_FIELD_TOS_LABEL="Terms of Service"
PLG_USER_PROFILE7_FIELD_WEB_SITE_DESC="Choose an option for the field Web Site"
PLG_USER_PROFILE7_FIELD_WEB_SITE_LABEL="Web site:"
PLG_USER_PROFILE7_OPTION_AGREE="Agree"
PLG_USER_PROFILE7_OPTION_YES="YES"
PLG_USER_PROFILE7_FIELD_SUBSCRIBE_DESC="Subscribe to get emails about updates"
PLG_USER_PROFILE7_FIELD_SUBSCRIBE_LABEL="Receive Update Emails"
-------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------
; Joomla! Project
; Copyright (C) 2005 - 2012 Open Source Matters. All rights reserved.
; License http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL, see LICENSE.php
; Note : All ini files need to be saved as UTF-8

PLG_USER_PROFILE7="User - Profile 7"
PLG_USER_PROFILE7_XML_DESCRIPTION="User Profile 7 Plug-in"
-------------------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------------------------

/**
 * @copyright Copyright (C) 2005 - 2012 Open Source Matters, Inc. All rights reserved.
 * @license GNU General Public License version 2 or later; see LICENSE.txt
 */

defined('JPATH_BASE') or die;

jimport('joomla.utilities.date');

jimport('joomla.user.helper');


jimport('joomla.user.user');


jimport('joomla.utilities.arrayhelper');


/**
 * An example custom profile plugin.
 *
 * @package Joomla.Plugin
 * @subpackage User.profile
 * @version 1.6
 */
class plgUserProfile7 extends JPlugin
{
/**
* Constructor
*
* @access      protected
* @param       object  $subject The object to observe
* @param       array   $config  An array that holds the plugin configuration
* @since       1.5
*/
public function __construct(& $subject, $config)
{
parent::__construct($subject, $config);
$this->loadLanguage();
}

/**
* @param string $context The context for the data
* @param int $data The user id
* @param object
*
* @return boolean
* @since 1.6
*/
function onContentPrepareData($context, $data)
{
// Check we are manipulating a valid form.
if (!in_array($context, array('com_users.profile', 'com_users.user', 'com_users.registration', 'com_admin.profile'))) {
return true;
}

if (is_object($data))
{
$userId = isset($data->id) ? $data->id : 0;

if (!isset($data->profile) and $userId > 0) {

// Load the profile data from the database.
$db = JFactory::getDbo();
$db->setQuery(
'SELECT profile_key, profile_value FROM #__user_profiles' .
' WHERE user_id = '.(int) $userId." AND profile_key LIKE 'profile7.%'" .
' ORDER BY ordering'
);
$results = $db->loadRowList();

// Check for a database error.
if ($db->getErrorNum())
{
$this->_subject->setError($db->getErrorMsg());
return false;
}

// Merge the profile data.
$data->profile7 = array();

foreach ($results as $v)
{
$k = str_replace('profile7.', '', $v[0]);
$data->profile7[$k] = json_decode($v[1], true);
if ($data->profile7[$k] === null)
{
$data->profile7[$k] = $v[1];
}
}
}

if (!JHtml::isRegistered('users.url')) {
JHtml::register('users.url', array(__CLASS__, 'url'));
}
if (!JHtml::isRegistered('users.calendar')) {
JHtml::register('users.calendar', array(__CLASS__, 'calendar'));
}
if (!JHtml::isRegistered('users.tos')) {
JHtml::register('users.tos', array(__CLASS__, 'tos'));
}
if (!JHtml::isRegistered('users.subscribe')) {
JHtml::register('users.subscribe', array(__CLASS__, 'subscribe'));
}
}

return true;
}

public static function url($value) { if (empty($value)) { return JHtml::_('users.value', $value); } else { $value = htmlspecialchars($value); if(substr ($value, 0, 4) == "http") { return '<a href="'.$value.'">'.$value.'</a>'; } else { return '<a href="http://'.$value.'">'.$value.'</a>'; } } }

public static function calendar($value)
{
if (empty($value)) {
return JHtml::_('users.value', $value);
} else {
return JHtml::_('date', $value, null, null);
}
}

public static function tos($value)
{
if ($value) {
return JText::_('JYES');
}
else {
return JText::_('JNO');
}
}

public static function subscribe($value)
{
if ($value) {
return JText::_('JYES');
}
else {
return JText::_('JNO');
}
}

/**
* @param JForm $form The form to be altered.
* @param array $data The associated data for the form.
*
* @return boolean
* @since 1.6
*/
function onContentPrepareForm($form, $data)
{

if (!($form instanceof JForm))
{
$this->_subject->setError('JERROR_NOT_A_FORM');
return false;
}

// Check we are manipulating a valid form.
$name = $form->getName();
if (!in_array($name, array('com_admin.profile', 'com_users.user', 'com_users.profile', 'com_users.registration'))) {
return true;
}

// Add the registration fields to the form.
JForm::addFormPath(dirname(__FILE__).'/profiles');
$form->loadFile('profile', false);

$fields = array(
'address1',
'address2',
'city',
'region',
'country',
'postal_code',
'phone',
'website',
'favoritebook',
'aboutme',
'tos',
'dob',
'subscribe',
);

foreach ($fields as $field) {
// Case using the users manager in admin
if ($name == 'com_users.user') {
// Remove the field if it is disabled in registration and profile
if ($this->params->get('register-require_' . $field, 1) == 0 &&
$this->params->get('profile-require_' . $field, 1) == 0) {
$form->removeField($field, 'profile7');
}
}
// Case registration
elseif ($name == 'com_users.registration') {
// Toggle whether the field is required.
if ($this->params->get('register-require_' . $field, 1) > 0) {
$form->setFieldAttribute($field, 'required', ($this->params->get('register-require_' . $field) == 2) ? 'required' : '', 'profile7');
}
else {
$form->removeField($field, 'profile7');
}
}
// Case profile in site or admin
elseif ($name == 'com_users.profile' || $name == 'com_admin.profile') {
// Toggle whether the field is required.
if ($this->params->get('profile-require_' . $field, 1) > 0) {
$form->setFieldAttribute($field, 'required', ($this->params->get('profile-require_' . $field) == 2) ? 'required' : '', 'profile7');
}
else {
$form->removeField($field, 'profile7');
}
}
}

return true;
}

function onUserAfterSave($data, $isNew, $result, $error)
{
$userId = JArrayHelper::getValue($data, 'id', 0, 'int');
//
//BEGIN CUSTOM CODE
//
//put this inside the onUserAfterSave function in profile7.php
// This code will check if the user clicked the radio button for email
// updates by checking the 'subscribe' boolean in the data
// then assign the user to that group (group 9) if true
$groupID = 9; //9 is the value for the subscriber group in the ACL
//DEBUG code that forces if statement to come up true:
//$subscribeFlag = 1;
if ($userId && (isset($data['profile7']['subscribe'])))
{
$subscribeFlag = ($data['profile7']['subscribe']);
if (!($subscribeFlag == 0)) 
{
try
{
JUserHelper::addUserToGroup($userId, $groupID);
}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}
else
{
try
{
JUserHelper::removeUserFromGroup($userId, $groupID);
}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}
}
//END CUSTOM CODE
//
if ($userId && $result && isset($data['profile7']) && (count($data['profile7'])))
{
try
{
//Sanitize the date
if (!empty($data['profile7']['dob'])) {
$date = new JDate($data['profile7']['dob']);
$data['profile7']['dob'] = $date->format('Y-m-d');
}

$db = JFactory::getDbo();
$db->setQuery(
'DELETE FROM #__user_profiles WHERE user_id = '.$userId .
" AND profile_key LIKE 'profile7.%'"
);

if (!$db->query()) {
throw new Exception($db->getErrorMsg());
}

$tuples = array();
$order = 1;

foreach ($data['profile7'] as $k => $v)
{
$tuples[] = '('.$userId.', '.$db->quote('profile7.'.$k).', '.$db->quote(json_encode($v)).', '.$order++.')';
}

$db->setQuery('INSERT INTO #__user_profiles VALUES '.implode(', ', $tuples));

if (!$db->query()) {
throw new Exception($db->getErrorMsg());
}

}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}

return true;
}

/**
* Remove all user profile information for the given user ID
*
* Method is called after user data is deleted from the database
*
* @param array $user Holds the user data
* @param boolean $success True if user was succesfully stored in the database
* @param string $msg Message
*/
function onUserAfterDelete($user, $success, $msg)
{
if (!$success) {
return false;
}

$userId = JArrayHelper::getValue($user, 'id', 0, 'int');

if ($userId)
{
try
{
$db = JFactory::getDbo();
$db->setQuery(
'DELETE FROM #__user_profiles WHERE user_id = '.$userId .
" AND profile_key LIKE 'profile.%'"
);

if (!$db->query()) {
throw new Exception($db->getErrorMsg());
}
}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}

return true;
}
}
----------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="user">
<name>plg_user_profile7</name>
<author>Joomla! Project</author>
<creationDate>January 2008</creationDate>
<copyright>(C) 2005 - 2012 Open Source Matters. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>2.5.0</version>
<description>PLG_USER_PROFILE7_XML_DESCRIPTION</description>

<files>
<filename plugin="profile7">profile7.php</filename>
<filename>index.html</filename>
<folder>profiles</folder>
</files>
<languages>
<language tag="en-GB">en-GB.plg_user_profile7.ini</language>
<language tag="en-GB">en-GB.plg_user_profile7.sys.ini</language>
</languages>
<config>
<fields name="params">

<fieldset name="basic">
<field name="register-require-user" type="spacer" class="text"
label="PLG_USER_PROFILE7_FIELD_NAME_REGISTER_REQUIRE_USER"
/>

<field name="register-require_address1" type="list"

description="PLG_USER_PROFILE7_FIELD_ADDRESS1_DESC"
label="PLG_USER_PROFILE7_FIELD_ADDRESS1_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="register-require_address2" type="list"

description="PLG_USER_PROFILE7_FIELD_ADDRESS2_DESC"
label="PLG_USER_PROFILE7_FIELD_ADDRESS2_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="register-require_city" type="list"

description="PLG_USER_PROFILE7_FIELD_CITY_DESC"
label="PLG_USER_PROFILE7_FIELD_CITY_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="register-require_region" type="list"

description="PLG_USER_PROFILE7_FIELD_REGION_DESC"
label="PLG_USER_PROFILE7_FIELD_REGION_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="register-require_country" type="list"

description="PLG_USER_PROFILE7_FIELD_COUNTRY_DESC"
label="PLG_USER_PROFILE7_FIELD_COUNTRY_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="register-require_postal_code" type="list"

description="PLG_USER_PROFILE7_FIELD_POSTAL_CODE_DESC"
label="PLG_USER_PROFILE7_FIELD_POSTAL_CODE_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="register-require_phone" type="list"

description="PLG_USER_PROFILE7_FIELD_PHONE_DESC"
label="PLG_USER_PROFILE7_FIELD_PHONE_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="register-require_website" type="list"

description="PLG_USER_PROFILE7_FIELD_WEB_SITE_DESC"
label="PLG_USER_PROFILE7_FIELD_WEB_SITE_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field name="register-require_favoritebook"
type="list"

label="PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_LABEL"
description="PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_DESC"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field
name="register-require_aboutme"
type="list"

label="PLG_USER_PROFILE7_FIELD_ABOUT_ME_LABEL"
description="PLG_USER_PROFILE7_FIELD_ABOUT_ME_DESC"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field
name="register-require_tos"
type="list"

label="PLG_USER_PROFILE7_FIELD_TOS_LABEL"
description="PLG_USER_PROFILE7_FIELD_TOS_DESC"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field
name="register-require_subscribe"
type="list"

label="PLG_USER_PROFILE7_FIELD_SUBSCRIBE_LABEL"
description="PLG_USER_PROFILE7_FIELD_SUBSCRIBE_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field
name="register-require_dob"
type="list"

label="PLG_USER_PROFILE7_FIELD_DOB_LABEL"
description="PLG_USER_PROFILE7_FIELD_DOB_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="spacer1" type="spacer"
hr="true"
/>
<field name="profile-require-user" type="spacer" class="text"
label="PLG_USER_PROFILE7_FIELD_NAME_PROFILE_REQUIRE_USER"
/>

<field name="profile-require_address1" type="list"

description="PLG_USER_PROFILE7_FIELD_ADDRESS1_DESC"
label="PLG_USER_PROFILE7_FIELD_ADDRESS1_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="profile-require_address2" type="list"

description="PLG_USER_PROFILE7_FIELD_ADDRESS2_DESC"
label="PLG_USER_PROFILE7_FIELD_ADDRESS2_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="profile-require_city" type="list"

description="PLG_USER_PROFILE7_FIELD_CITY_DESC"
label="PLG_USER_PROFILE7_FIELD_CITY_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="profile-require_region" type="list"

description="PLG_USER_PROFILE7_FIELD_REGION_DESC"
label="PLG_USER_PROFILE7_FIELD_REGION_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="profile-require_country" type="list"

description="PLG_USER_PROFILE7_FIELD_COUNTRY_DESC"
label="PLG_USER_PROFILE7_FIELD_COUNTRY_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="profile-require_postal_code" type="list"

description="PLG_USER_PROFILE7_FIELD_POSTAL_CODE_DESC"
label="PLG_USER_PROFILE7_FIELD_POSTAL_CODE_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="profile-require_phone" type="list"

description="PLG_USER_PROFILE7_FIELD_PHONE_DESC"
label="PLG_USER_PROFILE7_FIELD_PHONE_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field name="profile-require_website" type="list"

description="PLG_USER_PROFILE7_FIELD_WEB_SITE_DESC"
label="PLG_USER_PROFILE7_FIELD_WEB_SITE_LABEL"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field name="profile-require_favoritebook"
type="list"

label="PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_LABEL"
description="PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

<field
name="profile-require_aboutme"
type="list"

label="PLG_USER_PROFILE7_FIELD_ABOUT_ME_LABEL"
description="PLG_USER_PROFILE7_FIELD_ABOUT_ME_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field
name="profile-require_tos"
type="list"

label="PLG_USER_PROFILE7_FIELD_TOS_LABEL"
description="PLG_USER_PROFILE7_FIELD_TOS_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field
name="profile-require_dob"
type="list"

label="PLG_USER_PROFILE7_FIELD_DOB_LABEL"
description="PLG_USER_PROFILE7_FIELD_DOB_DESC"
>
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
<field
name="profile-require_subscribe"
type="list"

label="PLG_USER_PROFILE7_FIELD_SUBSCRIBE_LABEL"
description="PLG_USER_PROFILE7_FIELD_SUBSCRIBE_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>
</fieldset>

</fields>
</config>
</extension>

--------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<form>
<fields name="profile7">
<fieldset name="profile7"
label="PLG_USER_PROFILE7_SLIDER_LABEL"
>
<field
name="address1"
type="text"
id="address1"
description="PLG_USER_PROFILE7_FIELD_ADDRESS1_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_ADDRESS1_LABEL"
message="PLG_USER_PROFILE7_FIELD_ADDRESS1_MESSAGE"
size="30"
/>

<field
name="address2"
type="text"
id="address2"
description="PLG_USER_PROFILE7_FIELD_ADDRESS2_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_ADDRESS2_LABEL"
message="PLG_USER_PROFILE7_FIELD_ADDRESS1_MESSAGE"
size="30"
/>

<field
name="city"
type="text"
id="city"
description="PLG_USER_PROFILE7_FIELD_CITY_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_CITY_LABEL"
message="PLG_USER_PROFILE7_FIELD_CITY_MESSAGE"
size="30"
/>

<field
name="region"
type="text"
id="region"
description="PLG_USER_PROFILE7_FIELD_REGION_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_REGION_LABEL"
message="PLG_USER_PROFILE7_FIELD_REGION_MESSAGE"
size="30"
/>

<field
name="country"
type="text"
id="country"
description="PLG_USER_PROFILE7_FIELD_COUNTRY_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_COUNTRY_LABEL"
message="PLG_USER_PROFILE7_FIELD_COUNTRY_MESSAGE"
size="30"
/>

<field
name="postal_code"
type="text"
id="postal_code"
description="PLG_USER_PROFILE7_FIELD_POSTAL_CODE_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_POSTAL_CODE_LABEL"
message="PLG_USER_PROFILE7_FIELD_POSTAL_CODE_MESSAGE"
size="30"
/>

<field
name="phone"
type="tel"
id="phone"
description="PLG_USER_PROFILE7_FIELD_PHONE_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_PHONE_LABEL"
message="PLG_USER_PROFILE7_FIELD_PHONE_MESSAGE"
size="30"
/>

<field
name="website"
type="url"
id="website"
description="PLG_USER_PROFILE7_FIELD_WEB_SITE_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_WEB_SITE_LABEL"
message="PLG_USER_PROFILE7_FIELD_WEB_SITE_MESSAGE"
size="30"
/>
<field
name="favoritebook"
type="text"
description="PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_DESC"
filter="string"
label="PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_LABEL"
message="PLG_USER_PROFILE7_FIELD_FAVORITE_BOOK_MESSAGE"
size="30"
/>
<field
name="aboutme"
type="textarea"
description="PLG_USER_PROFILE7_FIELD_ABOUT_ME_DESC"
label="PLG_USER_PROFILE7_FIELD_ABOUT_ME_LABEL"
message="PLG_USER_PROFILE7_FIELD_ABOUT_ME_MESSAGE"
cols="30"
rows="5"
filter="safehtml"
/>
<field
name="subscribe"
type="radio"
default="0"
label="PLG_USER_PROFILE7_FIELD_SUBSCRIBE_LABEL"
description="PLG_USER_PROFILE7_FIELD_SUBSCRIBE_DESC">
<option value="0">PLG_USER_PROFILE7_OPTION_NO</option>
<option value="1">PLG_USER_PROFILE7_OPTION_YES</option>
</field>
<field
name="tos"
type="radio"
label="PLG_USER_PROFILE7_FIELD_TOS_LABEL"
description="PLG_USER_PROFILE7_FIELD_TOS_DESC">
<option value="1">PLG_USER_PROFILE7_OPTION_AGREE</option>
</field>

<field
name="dob"
type="calendar"
label="PLG_USER_PROFILE7_FIELD_DOB_LABEL"
description="PLG_USER_PROFILE7_FIELD_DOB_DESC">
</field>
</fieldset>
</fields>
</form>

------------------------------------------------------------------------------------------------------------

2012-03-20

Quixotic Quetzal should be Ubuntu version name 12.10

I believe the new Ubuntu release this October (12.10) should be called Quixotic Quetzal.

Credit for coming up with it goes to this guy, whose post I saw when I searched for "Questing Quetzal".  Since, questing is sort of a sub-set of being quixotic, I'm going with that instead!  I think it especially fits because this will not be an LTS and so it will be forgotten like a lost fool soon enough.
They'll probably just go with Quick Quahog.
Quicker Quokka (love this one too)
Quintessential Quagga
Quashed Quadrate
Queefing Quillpig (rofl)
Quadriphonic Quadricorn
Quality Quoll
Quaking Quail
Qualmish Quadrisectus
Quaffing Quiqui

2012-03-19

Post HTML code on Blogger

If you try to post examples of HTML code on Blogger, your post will break and you'll get a warning and everything will be ruined.

Don't be sad!  Use this little form I found.  It's right on the web.  Thanks Kevin Smith!  (I like your movies too.)


Just drop your code in there.  Hit "encode".  Then paste it into the "Compose" editor on Blogger.  Don't put it directly in the HTML editor or it will be even more broken.

Cheers!

2012-03-18

gnutella setup with firewall configuration and port forwarding Fedora 16


Just wanted to jot some notes down about setting up gnutella to go through the standard firewall on Fedora 16.

I was getting this little annoying message from an ugly red icon on the lower right bar of Gnutella:

You appear to be firewalled both TCP wise and UDP-wise...

The message is actually much longer than that, but that should do for search engine purposes, so that folks might find this little tut.

Let's change that message to read this:
People can connect to you using both TCP and UDP.  Push should work and you will be able to receive out-of-band results for your queries.
With a happy little yellow smiley face wearing sun-glasses...

{WARNING:  This method involves changing your connection to the internet through router settings and firewall changes.  You MUST have administrator privileges to execute this method.  I highly recommend either having a thorough knowledge of how to reconfigure your internet connection should something go wrong OR having another computer handy to look up trouble shooting information on the internet to FIX what got broke, should you make a mistake.  Obviously, you will NOT have the ability to look up help on this computer once you screw up your internet connection .  (NO, I do not recommend just using a phone, there would be far too much stuff to look up; it would take eons that way.)  Please proceed with caution, I've literally spent a week fixing a network at my parents that I screwed up many years ago, because I made just a mistake or two.  Learn from my mistake.}

I've got a Netgear router.  The method is very similar in LinkSys, Belkin, D-Link or any router I've ever worked with.  I logged into the router by typing 192.168.1.1 into the url field in Chrome.  This, I find, works for most router configurations.  You need to know your login and password, of course.  If you don't, then try admin/admin or password/password or admin/password.  Often routers are setup with one of those combinations as the default.  Also, if you can't figure out the password, you should be able to reset the router to default settings and THEN use one of those.  Look up the router through the manufacturer to find this default login.  Sometimes, depending on your isp, resetting your router could leave the router non-functional without contacting the isp and running some procedure, but, because I always choose the do-it-yourself method of installation, I have never had that problem.

Go to the Port Forwarding/Port Triggering tab/menu.
On Netgear, I chose, "add custom service".
I named the service "gnutella", just so I would know what it was.
Chose service type TCP/UDP.
Choose a start port between 49152-65534 (these are the recommended ranges)  I usually go with 55555 or 50505 or something really easy to remember like that.  It's up to you.
Make the end port the same.  In my case, also 55555.
For Server IP address I entered 192.186.1.70
Leave the first three digits the same.  The last one "70" in this case, is the only one you generally want to fiddle with.
When assigning static IP's I stay below 100, and I stay above 20.  DHCP (when the router dynamically assigns an IP to all the machines attached to it WHEN it discovers them) seems to always start with single digit numbers.  Going up from 1 as it finds new devices that wish to connect.

Now go to your Network Connections.  Either just click on the icon in the upper right and then click Network Settings, or go to Acitivities/Applications/Network Connections.
I'm wired, but it's pretty much the same for wireless.
Click "Configure..."
Select the IPv4 tab.
Click the "Add" button on the right.
Enter the Server IP address you chose above (192.168.1.70 in my case)
Netmask: 255.255.255.0
Gateway: 192.168.1.1
DNS servers: 8.8.8.8, 4.4.4.4 (the Google servers)
That should do it.  Now you have a static IP for that machine.  For THIS method you need it for the port forwarding to work.

Now that we've got the port forwarded, time to tell gnutella what it is:

Open gnutella.
Choose File/Preferences.
Under the "Network" tab at "Listen Port" enter 55555 ( or whatever you chose above ).
Network Protocol: IPv4 and IPv6.  Check box "Enable UDP" and "Enable DHT"
I went ahead and checked the box for Public hostname and entered a name, but this is somewhat irrelevant.
Leave the rest alone.
Now, the Fedora 16 part:
In the far upper left click on Activites and then choose Applications.  Find Firewall and open that.  You will be asked for your administrator password, so better know that.
Go to "Other Ports".
Click "Add" button on the right.
Select "User Defined".
Enter the port you chose (55555)
Select TCP.
Choose "Add" button again.
Select "User Defined">
Enter the port you chose (55555) yes the same one.
Select UDP.
Click Apply at the top.
That should do it!

Now I see a nice little smiley face at the bottom right of gnutella.

2012-03-15

Joomla 2.5 Add Field to Register Form

I highly recommend that you create a backup of your site before tampering with these files in the Joomla core!

In fact, I recommend that you go to my later post and add fields to your user forms the right way:  By creating an entirely separate user profile plugin.
Don't worry, I already did all the heavy lifting...


::WARNING::
Unfortunately, the method described below will be overwritten every time you update Joomla.  Apologies to anyone who used it without knowing this; I am learning as I go. Good news is that I went ahead and created an entire plugin (based on Joomla's stock profile plugin) called "Profile 7" to handle all this.  It will not be overwritten on updates.  I posted the whole thing on a later blog post.  So go there and use that.  I'm leaving this post up for reference and because it describes the process, which is important if you want to make your own custom fields.

UPDATE: APRIL 12, 2012:  The code below is tested for Joomla 2.5.4.
If you are using 2.5.3 or earlier version of Joomla and/or the profile plugin included with those versions, the "edit profile" page will not show any added fields.    In fact, it actually doesn't even show all of the fields that are included.  The register page does show the fields and the back end shows the fields.  It is only the edit profile page where they are not shown. One really messed up fact is that you can set a field to required on the administration panel and it will not show on the edit profile page, but when a user hits the submit button they will get an error telling them that field is required!  Thankfully, the Joomla team fixed this in 2.5.4.  You may run into issues if you try to implement this code in an earlier version.  I recommend you go ahead and backup your site and update!  Ok, back to the goods...

=======================================================================

This article from Joomla.org's official documentation was helpful, but it didn't tell this noob everything he needed to know.  All I needed to do was add a button, not create a whole new profile plugin.  However, the profile plugin that is included with Joomla has very similar code to the one in the article, so it was a nice frame of reference.  You will need FileZilla and full access to the administrator files on the server to make these changes.

The following are the files that will need changing:

/administrator/language/en-GB/en-GB.plg_user_profile.ini
/administrator/language/en-GB/en-GB.plg_user_profile.sys.ini
/plugins/user/profile/profile.xml
/plugins/user/profile/profile.php
/plugins/user/profile/profiles/profile.xml

Specifically, what I will be describing is adding a set of radio buttons to the register and profile edit forms so the user can choose to sign up for email updates.  Since Joomla 2.5 has a User Manager that allows you to create groups and sub-groups and manage them as well as mass send an email to any said group, I was able to make the profile plugin "talk to" Joomla and tell it to assign the user to a "subscriber" group which I create in the User Manager.

The first thing to do is to go into the Joomla User Manager.  Select the User Groups tab.  Select "New".
Enter the group title "subscriber".  Click the drop down arrow and select "registered" to make the new subscriber group a direct sub-group of "registered".  Now go to Users/Groups through the drop down menu.  Here you will see all of the groups listed in a hierarchical tree structure.  Find the new "subscriber" group.  In the last column on the right will be it's ID number.  In my case this number is 9.  BEWARE:  This is important, because this number is actually used in the code below to assign the user to the subscriber group.  If your group has a different number, then you will need to change this in the code below! 

The toughest part of this, for me, was tracking down those .ini files.  I had no idea that they would be filed under the administrator/language folder, but it makes perfect sense, because the files that we are changing there contain strings with labels, names and/or descriptions.  This allows support for multiple languages should this be necessary.

So I fired up FileZilla and pulled up the files for editing.

To the /plugins/user/profile/profile.xml right beneath the "dob" code I added:


<field
name="register-require_subscribe"
type="list"


label="PLG_USER_PROFILE_FIELD_SUBSCRIBE_LABEL"
description="PLG_USER_PROFILE_FIELD_SUBSCRIBE_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

That will add something like this on the register page on the front end:


It is also referenced to create the field in the registration configuration form in the administrator back end.

To the /plugins/user/profile/profile.xml right beneath the "dob" code I added:

<field
name="profile-require_subscribe"
type="list"


label="PLG_USER_PROFILE_FIELD_SUBSCRIBE_LABEL"
description="PLG_USER_PROFILE_FIELD_SUBSCRIBE_DESC">
<option value="2">JOPTION_REQUIRED</option>
<option value="1">JOPTION_OPTIONAL</option>
<option value="0">JDISABLED</option>
</field>

Which creates this on the "edit profile" page on the front end:


It is also referenced to create the field in the profile configuration form in the administrator back end.

To the /plugins/user/profile/profiles/profile.xml I added (again right below the "tos" code):


<field name="subscribe" type="radio" default="0" label="PLG_USER_PROFILE_FIELD_SUBSCRIBE_LABEL" description="PLG_USER_PROFILE_FIELD_SUBSCRIBE_DESC"> <option value="0">PLG_USER_PROFILE_OPTION_NO</option> <option value="1">PLG_USER_PROFILE_OPTION_YES</option> </field>

Which will help (along with the rest of the code) to give you this...

...when users simply view their profiles.

For the /plugins/user/profile/profile.php file, find this bit of code:

// Add the registration fields to the form.
JForm::addFormPath(dirname(__FILE__).'/profiles');
$form->loadFile('profile', false);

$fields = array(
'address1',
'address2',
'city',
'region',
'country',
'postal_code',
'phone',
'website',
'favoritebook',
'aboutme',
'tos',
'dob',
'subscribe',
);

When you find it, it won't have "'subscribe'," at the bottom.  Add it.

To the bottom of the /administrator/language/en-GB/en-GB.plg_user_profile.ini file I added:

PLG_USER_PROFILE_FIELD_SUBSCRIBE_DESC="Subscribe to get emails about updates"
PLG_USER_PROFILE_FIELD_SUBSCRIBE_LABEL="Receive Update Emails"
PLG_USER_PROFILE_OPTION_YES="YES"

The /administrator/language/en-GB/en-GB.plg_user_profile.sys.ini actually doesn't need any changes.  (unless you want to rename it in Swahili or something).

Now I just need to figure out how to USE that "YES" selection.  What I want to do is make it so that when someone selects "YES" they are actually assigning themselves a member of the "Subscriber" group, an Assigned User Group that I created in the User Manager: User Groups tab in the Joomla Administration back end.  This way I will be able to send emails to that group in bulk whenever there is an update - easy peazy.  Since it IS possible for the users to go from "Public" to "Registered" I'm hoping this is also possible.  It would save a lot of hassle to have this automated.
===================

Added the "subscribe" version of the code below to the profile.php file

if (!JHtml::isRegistered('users.url')) {
JHtml::register('users.url', array(__CLASS__, 'url'));
}
if (!JHtml::isRegistered('users.calendar')) {
JHtml::register('users.calendar', array(__CLASS__, 'calendar'));
}
if (!JHtml::isRegistered('users.tos')) {
JHtml::register('users.tos', array(__CLASS__, 'tos'));
}
if (!JHtml::isRegistered('users.subscribe')) {
JHtml::register('users.subscribe', array(__CLASS__, 'subscribe'));
}

Also added this public static function later in the profile.php file (showing the tos version for example and for position information):

public static function tos($value)
{
if ($value) {
return JText::_('JYES');
}
else {
return JText::_('JNO');
}
}
public static function subscribe($value)
{
if ($value) {
return JText::_('JYES');
}
else {
return JText::_('JNO');
}
}

-------------------
Okay I've cobbled together this code from reading through forums all over the interwebs.  Time to see if it works...

//import the following at the top of profile.php
jimport( 'joomla.user.helper' );


jimport( 'joomla.user.user');


jimport( 'joomla.utilities.arrayhelper' );

-------------
put this inside the onUserAfterSave function in profile.php
Please note that the $groupID variable is set to 9 in the code below, but this could vary.  Check Users/Groups page in the Joomla Administrator to find the right value.
-------------

function onUserAfterSave($data, $isNew, $result, $error)
{
$userId = JArrayHelper::getValue($data, 'id', 0, 'int');
//
//BEGIN CUSTOM CODE
//
//put this inside the onUserAfterSave function in profile.php
// This code will check if the user clicked the radio button for email
// updates by checking the 'subscribe' boolean in the data
// then assign the user to that group (group 9) if true
$groupID = 9; //9 is the value for the subscriber group in the ACL
//DEBUG code that forces if statement to come up true:
//$subscribeFlag = 1;
if ($userId && (isset($data['profile']['subscribe'])))
{
$subscribeFlag = ($data['profile']['subscribe']);
if (!($subscribeFlag == 0)) 
{
try
{
JUserHelper::addUserToGroup($userId, $groupID);
}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}
else
{
try
{
JUserHelper::removeUserFromGroup($userId, $groupID);
}
catch (JException $e)
{
$this->_subject->setError($e->getMessage());
return false;
}
}
}
//END CUSTOM CODE
//

.......
(Note:  Originally I posted this code without the ability to select "no".  The removeUserFromGroup method of  the JUserHelper helps to accomplish this.)

Now, go to the Plugin Manager in Joomla open up User Profile and look under the Basic Options on the right.  Make sure Receive Update Emails is set to Required.

That should do it!  Now go to the register page on your site and register a pretend person.  Make sure you check the "Receive Update Emails" button!

Go to the User Manager in the Joomla Administration Back End, you should now see the new user you create has an additional group under the User Groups column:  Subscriber.

Later on, you can go to Mass Mail Users, in the User Menu, and simply select Subscriber and away goes the News Letter.  Good times.

I highly recommend making and keeping (in a safe memorable place) backups of all of the files to be altered in this process.

Here is a final copy of the entire profile.php file, complete with alterations:
profile.php


2012-03-13

Android Home Key disable / enable App Part 1


UPDATE:
I've decided to create an alternative "launcher" to solve this Home Key problem.  I am working on the code now.  The method I described here DOES disable the Home Key, but it does not allow you to enable it once again.  Being new to android, it seems fishy, and I'm guessing it is not good practice.  The method I am currently working on is more fitted to my needs anyway.  The launcher will take the place of the home screen and when someone hits the home key they will be asked to choose whether to use the standard launcher or my custom launcher.  At that point they will also be asked if they want to set that as the default.  Then the home key won't work inside my launcher and I will override the Back button to bring up a password screen, if they want to log out.  Once you get into a project you learn stuff and the whole project direction changes!



Home Key Lock/UnLock App:
---------------------------
DISCLAIMER:  I am currently trying to figure out how to get Blogger to accept my little html code snippets. It keeps giving me warnings and breaking the formatting. I will erase this message, of course, once I figure it out. 

 Okay a little project here.  Create a very simple app for Froyo 2.2 that will be able to toggle the functionality of the Home Key on and off, and some other things.  This is a very early exploratory exercise leading up to creating an educational app for Android pads.  I need for the children to be required to finish with a learning task before they will be given the opportunity to play their favorite games as a reward.  Meanwhile, they need to be locked into the learning game, so I need the Home key and Back key to be disabled.  That's the large goal.  Below is the simplified version broken into steps.

I'm using some code I got from this tutorial as a template:
http://hackaday.com/2010/07/19/android-development-101-part-2improved-hello-world/

I named it HelloWorldImproved.

Here is a list of the goals and some steps I need to take:

Find a way to lock out the Home and Back buttons altogether.  All entries will be made on the screen.  Some sort of override.

Add (GUI touchscreen) button that will close this app and open another.

Create a copy of the altered app.

In the copy app, change the function of the button so that it leads back to the original app.

Add a button on the app that releases the lock on the back button and home button and returns the funcionality of closing the app.  Actually, make this toggle that function and, when clicked, make it throw up a toast that says "Home Key Disabled" or "Home Key Enabled" depending.

Add a flag to the program that will not allow the change app button to work.

Add a button that flips the flag and releases the lock on the change app button.

Add a button that closes the app.  (This is merely to create code to close the app internally, rather then relying on the standard function of the Back key)

---------------

Okay, so first I made a copy of the whole HelloWorldImproved app that I created in the tutorial.  This left the primary activity named HelloWorldActivity which I didn't like, but after I figured out that it wouldn't be easy to change that, I just left it for now.

Then I made some changes so that I could add a second button.  At first I just wanted a button that did the same thing, but had different text on it ( and of course a separate id in the activity).
Step 1:
I opened the strings.xml (under res/values) and added this line:
<string name="press4app2">Press for App 2</string>

I put that line right under the Press Me! line.
Saved strings.xml

Step 2:
Opened up main.xml (under res/layout).  I copied the entire Button element and pasted the copy right below it.  I changed it so that it looked like this:
<Button
        android:id="@+id/switch1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/press4app2"
/>
As you can see, all I changed was the id (this is essentially the variable name or handle I can use over in the Java) and the text.  Now it refers to the string name that I created over in the strings.xml above, press4app2.

Step 3:
Then I opened up the main Java file, HelloWorldActivity.java.  I copied the entire OnClickListener mAddListener section.  The one with the comment "//Create an anonymous implementation of OnClickListener" at the top.  Be careful to get the one curly brace at the bottom.

I replaced mAddListener with mAddListener2 and I left everything else alone (for now), being that my first goal is merely to create a duplicate button that works.

Step 4:
Then back at the top of the HelloWorldActivity.java file...
We need to actually create the button.  So copy the four lines of code starting with "//Capture our button from layout"

  // Capture our button from layout
  Button button = (Button)findViewById(R.id.go);
  // Register the onClick listener with the implementation above
  button.setOnClickListener(mAddListener);

and paste them directly below themselves.  Now make them look like this:

  // Capture the switch button from layout
  Button switch1 = (Button)findViewById(R.id.switch1);
  // Register the onClick listener with switch1
  switch1.setOnClickListener(mAddListener2);

Changes?  Changed the comments to tell the truth.  Changed "Button button" to "Button swich1".  Changed "(R.id.button)" to "(R.id.switch1).  Changed button.setOnClickListener to switch1.setOnClickListener and changed that last parameter to mAddListener2 instead of mAddListener.

Step 5: (check for errors, make sure all is saved)
Make sure you save all of the files we changed:  main.xml, strings.xml and HelloWorldActivity.java.  Now run app and you will have two buttons that create toasts using the text you enter in the text field!  Woo hoo, it worked.

Now to create a button that will toggle the home key back on ( or back off again if hit twice )

Step 1:
edited the strings.xml file
Added this to the bottom of the file:
<string name="toggle_home">Toggle HomeKey ON-OFF</string>

Step 2:
Edited the main.xml file.  Added this under the last button:
<Button 
        android:id="@+id/toggleHome"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/toggle_home"
/>
Step 3:
Copied the OnClickListener and changed to mAddListener3

 // Create an anonymous implementation of OnClickListener
    private OnClickListener mAddListener3 = new OnClickListener()
    {
    public void onClick(View v)
    {
    long id = 0;
    // do something when the button is clicked
    try
    {
    helloName = (EditText)findViewById(R.id.helloName);
   
    Context context = getApplicationContext();
    CharSequence text = "Hello " + helloName.getText() + "!";
    int duration = Toast.LENGTH_LONG;
   
    Toast toast = Toast.makeText(context, text, duration);
    toast.show();
    }
    catch (Exception ex)
    {
    Context context = getApplicationContext();
    CharSequence text = ex.toString() + "ID = " + id;
    int duration = Toast.LENGTH_LONG;
   
    Toast toast = Toast.makeText(context, text, duration);
    toast.show();
    }
 
   
    }
    };

Step 4:
Edit Jave file and add onClickListener for the new button:
// Capture the toggleHome button from layout
        Button toggleHome = (Button)findViewById(R.id.toggleHome);
        // Register the onClick listener with switch1
        toggleHome.setOnClickListener(mAddListener3);

Step 5:  Check work, save, and see if it works.  (After that we will change what it doees to toggling that homeKey on/off)

Okay, that works.  Now to figure out how to give it the functionality I want.  I found this code laying around the interwebs...
-----------------------------------------------------
@Override
public void onAttachedToWindow()
{
   Log.i("TESTE", "onAttachedToWindow");
   this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
   super.onAttachedToWindow();
}

public boolean onKeyDown(int keyCode, KeyEvent event) {
   if (keyCode == KeyEvent.KEYCODE_HOME) {
       Log.i("TESTE", "BOTAO HOME");
       return true;
   }
   return super.onKeyDown(keyCode, event);  
}
------------------------
Let's see what I can do with it.

The first thing I did was to implement that code and shut down the Home Key, without yet worrying about creating a button to turn it on and off.  I needed to import some things to make his code work.  Namely:

import android.util.Log;
import java.lang.Object;
import android.view.WindowManager;
import android.view.KeyEvent;
import android.view.ViewGroup.LayoutParams;

I added all of those to the top of the HelloWorldActivity.java file, where you always find lots of imports.
How did I know what to import?  I didn't!  lol!

I went over to the Android SDK site, http://developer.android.com/sdk/index.html, and I opened the "Reference" tab at the top.  This will take you to http://developer.android.com/reference/packages.html

In the upper right is a search engine for the whole reference section.  My friend!

For each of the variables in the code I was adapting I looked up something relevant and kept reading until I found our what package(s) I needed to import.  I actually did a little google searching too when I came up empty, until I figured it all out.  Believe it or not, I got lucky this time and it only took about 15 minutes to track down the appropriate packages.

I keep doing this enough and I just might learn something...

So, with all those imported, all of my little red X's disappeared and I ran it.  It worked!  At least inside the Android Virtual Device, the Home key is no longer functional.

Next, I need to find a way to turn that code on or off.  I'm thinking I'll create a flag, a boolean that will determine if the code is executed or not.  Then I'll make the button toggle that flag on and off.

UPDATE:
I've decided to create an alternative "launcher" to solve this Home Key problem.  I am working on the code now.  The method I described here DOES disable the Home Key, but it does not allow you to enable it once again.  Being new to android, it seems fishy, and I'm guessing it is not good practice.  The method I am currently working on is more fitted to my needs anyway.  The launcher will take the place of the home screen and when someone hits the home key they will be asked to choose whether to use the standard launcher or my custom launcher.  At that point they will also be asked if they want to set that as the default.  Then the home key won't work inside my launcher and I will override the Back button to bring up a password screen, if they want to log out.  Once you get into a project you learn stuff and the whole project direction changes!