Linux Format 168 On Sale Today - Linux vs Windows 8: The verdict

LXF


Microsoft has been alienating its users by making pointless user interface changes, dropping support for its instant messenger app and not providing software that will play a DVD.

We can either: a) Point and laugh like Nelson the bully from The Simpsons; or b) show the poor, huddled masses of Windows users that there is a better way. Or, if you don't use Windows and don't know anybody who does, you can simply marvel at how much better off you are because you use Linux, and congratulate yourself on your sound judgement.

Also in the magazine! There's coding a-plenty, with an introduction to Ruby, a beginner's tutorial on Scratch and the latest installment of our Django series. You can assuage your fears over UEFI, wrange KDE 4 to your personal preference with our missing manual, write your own command-line tool, discover the best photo editor for Linux and find out why free software developers should learn from the Bible.

Plus - on the awesome DVD: Mint 14 KDE, Fuduntu, GhostBSD, Netrunner + tons more!

All this and more, in Linux Format 168 – the super-middleweight issue!

For a complete issue overview, and subscriber PDFs, take a look at our archives: http://www.linuxformat.com/archives?issue=168

Digital Editions: Linux Format is now available on Android and Chrome with Google Play Magazines, from just £3.99 per issue. It's also available on both Apple's iPhone/iPad/Touch and Android devices through Zinio. You can also purchase individual copies from the Ubuntu Software Centre.

You should follow us on Identi.ca or Twitter


Your comments

Windows rejection

My daughter bought a new Dell with Windows 8 (because Dell do not offer a Linux alternative on many models). It took just two days for her to beg for Linux, and she is much happier with an interface where you can actually find what you want, where you can create links to applications or to documents that stay where you put them, etc.

Have you see how many "Classic Windows" tutorials there are for Windows 8?! Everyone wants the List All Applications button and the Start Menu back.

I am also enjoying the way that each incarnation of Microsoft Office is a better and better advertisement for Libre Office.

Pointless changes...

"Microsoft has been alienating its users by making pointless user interface changes" Yeah, they're copying Ubuntu...

"Ubuntu has been alienating

"Ubuntu has been alienating its users by making pointless user interface changes" Yeah, they're copying windows 7...

"Fedora has been alienating its users by making pointless user interface changes" Yeah, next they're copying Mint...

Win8 / Unity / Gnome Do

We have a couple of Win8 installs in the lab at work. I find they're very much like Unity, e.g. a graphically overblown, full screen gnome-do.

Year of linux on the desktop !

FROM FORBES:

Acer Selling More Google Chromebooks Than Windows 8 Laptops ?

Acer CEO JT Wang was quoted as pleading with Microsoft to “think twice” and insisting that the Surface RT would “create a huge negative impact for the ecosystem and other brands may take a negative reaction.” Yesterday, the drama escalated when Acer President Jim Wong told Bloomberg that the Taipei-based PC maker is having more success with Google‘s Chrome OS than Windows 8.

Acer’s $199 C7 has accounted for between 5 to 10 percent of the company’s U.S. shipments. Though Wong didn’t provide sales statistics for devices like Acer’s Aspire One, which runs Windows 8, one has to assume they’ve been anything but brisk. “The whole market didn’t come back to growth after the Windows 8 launch, that’s a simple way to judge if it is successful or not,” Wong explained.

I have been using Linux now

I have been using Linux now since 2000 and wouldn't go back for anything. Windows just keeps getting worse. Been using Linux Mint for 6 months now and love it.

Its not Windows 8…

Its not Windows 8 which brings new people to Linux. WinXP will do that. Because non-tech people want uncluttered desktops and not windows 8.

It winXP not win8, think about it!

after 35 years now i am freed and in heaven!

i am computer specialist since 1975.
i know computer from 25 sides, even the move of the electrons in the chips over there nano-junctions.
i wrote 30 years programs in lisp, pascal, fortran, plm86, visual basic, C, delphi, kylix, basic, java, php, assembler, etc etc etc
structured programs of 25000 lines errorfree code.
every line find back in 1 minute!
i was happy with atari etc, the m68000 16 bits systems, much better as the intel 8 bits stuff for 15 years duration!
and the pc was 13000 gulden and the atari only 2000 ! with build in midi, used by arteficial intelligence projects at universities etc etc etc.
then came big blue and with there money they destroyed the nice computer world. last 10 years i 2 times tried to go on linux. it failed. now the third time, after windows virusses every half year, i did it the third time and succeeded (with Xubuntu). what a paradise it is! installing a server, LAMP: easy: a 1 button press. 1 password. i cannot beleave this. exit windows. till my dead i will be happy. !!!! i am freed of the devil!!!!

Linux vs. Windows 8

Another EXCELLENT issue guys and gals! Kudos to the crew in at LXF Towers, with special thanks for the article on UEFI!

Consider me a VERY happy (long-term) reader and recurring subscriber. Keep'em coming and I'll keep buying them.

Brilliant!

Tux86.org

The Linux Virus......

After having my ENTIRE digital life destroyed by one of the millions of viruses and trojans that exist in the Windows World. I made the switch to Linux at the "Fedora 15" mark. I can say that after being a Linux user for that amount of time, I have never ben happier! I no longer have to fight with my machine on a dailoy basis to accomplish the things I need to get doen, both for work and for play. The fact that my OS and other apps cost me nothing is even better! (Although I "donate" regularly to the LibreOffice.....Fedora....CEntOS....and LinuxMint projects!...because these folks give so much of themselves for my benefit!) I have already "turned" my brother....my Mum....my older sister...my cousin..my son..and his mother...he sister...and my co-worker to Linux (various distros!) and they have all praised it's ease of use, it's simple-yet-powerful premise, and it's liberating effect on their computing lives! I think it's like some sort of "virus" in that once you show it to someone, and they use it once or twice, they become "infected" with the Linux Bug. As far as I'm concerned, I am PROUD and HAPPY to be infected! I intend on infecting as MANY people as I CAN!...

Cheers!

Power To The Penguin!!!

EGO II

Python, PyGTK and SQLite

Someone asked in LXF 168 Letters about using Pythn, SQLite and GTK. This is a Python script I wrote about 4 years ago to organize my CDs database. I'm a self taught programmer so I'm sure there are mistakes and inefficiencies, but it seems to work for me. I hope this is helpful
#You will need the following information about your CDs for the database:
# Artist First Name, Artitst Last Name, CD Title, CD Genre (Rock, Classical Jazz, etc), Record Label, CD Number, Year Published, Comment
# The field names for these are: fname, lname, cdtitle, cdgenre, cdlabel, cdnumber, cdyear, cdcomment
# It uses PyGTK which I think has been superceded by GObject, but I have yet to convert the program to this new format since it still seems to work at the moment.
# I don't have time to write a full tutorial on it, but I hope the comments I've made will be instructive.
# Run it with python cdsdb '/path/to/db/file'
# See LXF 167-169 for an introduction to Python

# First create a database and add some data (my script has a hissy-fit if there is no data). In sqlite3 insert the following SQL lines (hey, it's the 40th anniversary of the LP, so it seems only fitting...):

BEGIN TRANSACTION;
CREATE TABLE cds (cdid INTEGER PRIMARY KEY AUTOINCREMENT, fname TEXT, lname TEXT, cdtitle TEXT, cdgenre TEXT, cdnumber TEXT, cdyear INTEGER, cdlabel TEXT, cdcomment TEXT);
INSERT INTO "cds" VALUES(80,'None','Pink Floyd','Dark Side Of The Moon','Rock','cdp 7 46001 2',1973,'Capitol','');
CREATE TABLE songs (cdid INTEGER, songid INTEGER PRIMARY KEY AUTOINCREMENT, song TEXT, FOREIGN KEY(cdid) REFERENCES cds(cdid));
INSERT INTO "songs" VALUES(80,793,'Speak To Me');
INSERT INTO "songs" VALUES(80,794,'Breathe In The Air');
INSERT INTO "songs" VALUES(80,795,'On The Run');
INSERT INTO "songs" VALUES(80,796,'Time');
INSERT INTO "songs" VALUES(80,797,'The Great Gig In The Sky');
INSERT INTO "songs" VALUES(80,798,'Money');
INSERT INTO "songs" VALUES(80,799,'Us And Them');
INSERT INTO "songs" VALUES(80,800,'Any Colour You Like');
INSERT INTO "songs" VALUES(80,801,'Brain Damage');
INSERT INTO "songs" VALUES(80,802,'Eclipse');
COMMIT;

#The form should look something like this:
#
# +--------------------------------------------------------------------+
# | First Name | Song1 |
# | Last Name | Song2 |
# | Title | Song3 |
# | Genre | Song4 |
# | Label | Song5 |
# | Number | Song6 |
# | Year | Song7 |
# | Comment | Song8 |
# |--------------------------------------------------------------------+
# | QueryString QryBtn AllBtn AddBtn UpdateBtn ListBtn <Btn >Btn |
# +--------------------------------------------------------------------+

# To run it in Bash: python '/path/to/script' '/path/to/dbfile'

# Here is the script. Run with python '/path/to/script/' '/path/to/dbfile':

#!/usr/bin/env python
# NaviNotesDB.py
# Version 2.2
########
# setup
## import some module requirements
import gtk
import gtksourceview2
from os import path, unlink
import subprocess
import sqlite3
import time
import pango
import pygtk
##############################################################################
class cdsdb:
## delete the window and close the db connection when window's X button is pressed
def delete_event(self,widget,event,date=None):
return False # destroy window

def destroy(self,widget,date=None):
self.conn.close()
self.connection.close()
gtk.main_quit()

def __init__(self, dbfile):
# setup database
## connect opens the db file for reading and writing and create a cursor (think of it as a db record pointer). Then create a temporary table called tempRecList (used for storing the primary keys of the records to be displayed)
self.connection = sqlite3.connect(dbfile)
self.conn = self.connection.cursor()
self.conn.execute("CREATE TEMPORARY TABLE tempRecList(RLid INT);")
# setup window
## the next few lines create a GTK window, set it's title, gives it a white background, a border and sets the window size. The last 2 lines in the section can be thought of as attaching the subroutines defined above to the X button on the window.
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title('CDs')
self.window.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('white'))
self.window.set_border_width(2)
self.window.set_default_size(950,300) # width, height
self.window.connect("delete_event",self.delete_event)
self.window.connect("destroy", self.destroy)
# setup table
## this creates a 'grid layout' for placing graphical elements onto the window and then places it into the window.
self.table = gtk.Table(9, 20, False) # rows, columns, table cells NOT same size
self.window.add(self.table)
# First Name Entry
## this creates a label, aligns the text on the left and in the centre of the 'cell' and places it into the table.
self.label1 = gtk.Label('First Name ')
self.label1.set_alignment(0.0, 0.5)
self.table.attach(self.label1, 0, 1, 0, 1)# leftCoordinate, rightCordinate, topCoordinate, bottomCoordinate)
## an Entry box allows the user to enter data. The modify_font line allows the text in the entry to be formatted in sans 12
self.fname = gtk.Entry()
self.fname.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.fname, 1, 9, 0, 1)
# Last Name Entry
self.label2 = gtk.Label('Last Name ')
self.label2.set_alignment(0.0, 0.5)
self.table.attach(self.label2, 0, 1, 1, 2)
self.lname = gtk.Entry()
self.lname.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.lname, 1, 9, 1, 2)
# CD Title Entry
self.label3 = gtk.Label('CD Title ')
self.label3.set_alignment(0.0, 0.5)
self.table.attach(self.label3, 0, 1, 2, 3)
self.cdtitle = gtk.Entry()
self.cdtitle.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.cdtitle, 1, 9, 2, 3)
# Genre Entry
self.label3 = gtk.Label('Genre ')
self.label3.set_alignment(0.0, 0.5)
self.table.attach(self.label3, 0, 1, 3, 4)
self.cdgenre = gtk.Entry()
self.cdgenre.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.cdgenre, 1, 9, 3, 4)
# Label Entry
self.label4 = gtk.Label('Label ')
self.label4.set_alignment(0.0, 0.5)
self.table.attach(self.label4, 0, 1, 4, 5)
self.cdlabel = gtk.Entry()
self.cdlabel.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.cdlabel, 1, 9, 4, 5)
# Number Entry
self.label5 = gtk.Label('Number ')
self.label5.set_alignment(0.0, 0.5)
self.table.attach(self.label5, 0, 1, 5, 6)
self.cdnumber = gtk.Entry()
self.cdnumber.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.cdnumber, 1, 9, 5, 6)
# Year Entry
self.label6 = gtk.Label('Year ')
self.label6.set_alignment(0.0, 0.5)
self.table.attach(self.label6, 0, 1, 6, 7)
self.cdyear = gtk.Entry()
self.cdyear.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.cdyear, 1, 9, 6, 7)
# Comment Entry
self.label1 = gtk.Label('Comment ')
self.label1.set_alignment(0.0, 0.5)
self.table.attach(self.label1, 0, 1, 7, 8)
self.cdcomment = gtk.Entry()
self.cdcomment.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.cdcomment, 1, 9, 7, 8)
# Query Entry
## this entry has its background and text colour changed, first defining a colour to use and then using it on the entry. It also has its length limited to 50 characters.
self.qentry = gtk.Entry()
txtcolour=gtk.gdk.color_parse('#000000')
ebasecolour=gtk.gdk.color_parse('#add8e6')
self.qentry.modify_text(gtk.STATE_NORMAL,txtcolour)
self.qentry.modify_base(gtk.STATE_NORMAL,ebasecolour)
self.qentry.set_max_length(50)
self.qentry.modify_font(pango.FontDescription('sans 12'))
self.table.attach(self.qentry, 0, 2, 8, 9)
# Query Button - question the database
## Buttons allow routines to be run when clicked! After defining a button (similar to labels and entries), you connect the routine to the button.
self.button1 = gtk.Button(' Query ')
self.button1.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#add8e6'))
self.button1.connect('clicked',self.queryDB)
self.table.attach(self.button1, 2, 3, 8, 9)
# All Button - show all records
self.button2 = gtk.Button(' All ')
self.button2.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('skyblue2'))
self.button2.connect('clicked',self.loadAll)
self.table.attach(self.button2, 3, 4, 8, 9)
# Add Button - add the data displayed in the form as a new record in the database
self.button6 = gtk.Button(' Add ')
self.button6.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('green'))
self.button6.connect('clicked',self.addEntry)
self.table.attach(self.button6, 4, 5, 8, 9)
# Update Button - update the current record
self.button7 = gtk.Button('Update')
self.button7.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('yellow'))
self.button7.connect('clicked',self.updateEntry)
self.table.attach(self.button7, 5, 6, 8, 9)
# List Button - show a new window with a list of the CDs
self.button4 = gtk.Button(' List ')
self.button4.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('skyblue2'))
self.button4.connect('clicked',self.listRecs)
self.table.attach(self.button4, 6, 7, 8, 9)
# < Button - go back one record
self.button9 = gtk.Button(' < ')
self.button9.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('lightgrey'))
self.button9.connect('clicked',self.prevRec)
self.table.attach(self.button9, 7, 8, 8, 9)
# > Button - go forward one record
self.button10 = gtk.Button(' > ')
self.button10.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('lightgrey'))
self.button10.connect('clicked',self.nextRec)
self.table.attach(self.button10, 8, 9, 8, 9)
# Song List
## this creates what is called a liststore and the similar treestore to show a number of records (in this instane the songs on the CD) in one area of the window.
self.Sliststore = gtk.ListStore(str) # create liststore with one string column
Streestore = gtk.TreeStore(self.Sliststore) # copy the listore into a treestore
Streeview = gtk.TreeView(self.Sliststore) # a treeview allows a hierachical list
tvcolumn = gtk.TreeViewColumn('Songs') # create one column in the treeview called 'Songs'
Streeview.append_column(tvcolumn) # add the column to the treeview
Ssw = gtk.ScrolledWindow() # create a scrollable window to display the treeview
Ssw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
Ssw.add(Streeview) # attach the treeview to the scroll window
## the next 3 lines formats the data in each line of the scrolled window as text, since one can display pictures too, in tree views
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell,True)
tvcolumn.add_attribute(cell,'text', 0)
self.table.attach(Ssw, 9, 20, 0, 9)
# show window
## display the window and run the loadAll routine
self.window.show_all()
self.loadAll(self)
#######################################
## this adds the data in the currently view entry boxes as a new record in the database.
def addEntry(self, widget):
# execute the SQL line, substituting the values retrieved from the form for the ?s in the SQL string
self.conn.execute("insert into cds (fname, lname, cdtitle, cdgenre, cdlabel, cdnumber, cdyear, cdcomment) values (?,?,?,?,?,?,?,?)", (self.fname.get_text(), self.lname.get_text(), self.cdtitle.get_text(), self.cdgenre.get_text(), self.cdlabel.get_text(), self.cdnumber.get_text(), self.cdyear.get_text(), self.cdcomment.get_text(),)) # ALWAYS use parameter substitution
self.connection.commit() # flush the cache so the data is written properly
self.loadAll(self)
#######################################
## this opens a new window and lists the CDS
def listRecs(self, widget):
# run a query on the database
self.conn.execute("SELECT fname, lname, cdtitle FROM cds INNER JOIN tempRecList ON cds.cdid=tempRecList.RLid ORDER BY lname, fname, cdtitle;")
queryList=self.conn.fetchall() # this actually retreives the data from the previously run query
# setup window
Lwindow = gtk.Window(gtk.WINDOW_TOPLEVEL)
Lwindow.set_title('List')
Lwindow.set_size_request(750, 500)
Lwindow.set_border_width(2)
# setup data
liststore = gtk.ListStore(str,str, str)
treestore = gtk.TreeStore(liststore)
for data in queryList:
liststore.append(data) # append all the data to a list store for displaying
# setup treeview
treeview = gtk.TreeView(liststore)
tvcolumn = gtk.TreeViewColumn('First Name')
tvcolumn1 = gtk.TreeViewColumn('Last Name')
tvcolumn2 = gtk.TreeViewColumn('CD Title')
treeview.append_column(tvcolumn)
treeview.append_column(tvcolumn1)
treeview.append_column(tvcolumn2)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
sw.add(treeview)
# configure each column in the treeview
cell = gtk.CellRendererText()
tvcolumn.pack_start(cell,True)
tvcolumn1.pack_start(cell,True)
tvcolumn2.pack_start(cell,True)
tvcolumn.add_attribute(cell,'text', 0)
tvcolumn1.add_attribute(cell,'text', 1)
tvcolumn2.add_attribute(cell,'text', 2)
Lwindow.add(sw)
Lwindow.show_all()
#######################################
def loadAll(self, widget):
## deletes the current values in the tempoary table and retrieves the primary key of each CD record and places it into the temporary table. This means that we are actually just storing the key and only retrieve the complete record when needed for displaying in the main form.
# delete current RLids
self.conn.execute("DELETE FROM tempRecList;")
self.connection.commit()
# insert all cdids into tempRecList.RLids
self.conn.execute("INSERT INTO tempRecList (RLid) SELECT cdid FROM cds;")
self.connection.commit()
# get all records
self.conn.execute("SELECT CAST(cdid as INT) FROM cds ORDER BY lower(lname), lower(fname), lower(cdtitle);")
self.idRecs=self.conn.fetchall()
self.idList = [y[0] for y in self.idRecs] # tuples are returned from queries so one must retrieve the first element of each tuple.
self.i=0 # set a 'pointer' to the first element of the idList (which is the list of primary keys). As we navigate through the idList, the self.i will be the index number of the the currently selected idList value
self.qentry.set_text('') # remove any query entry text
self.loadForm(self)
#######################################
def loadForm(self, widget):
## this loads the complete record information into the form.
v1=str(self.idList[self.i]) # retrieve the value of the ith element in ther idList and turn it into a string for the query.
self.conn.execute("SELECT cdid, fname, lname, cdtitle, cdgenre, cdlabel, cdnumber, CAST(cdyear AS TEXT), cdcomment FROM cds WHERE cdid = ?",(v1,))
formData=self.conn.fetchall() # get the values in all the fields of the record
# load data into variables
self.fname.set_text(formData[0][1])
self.lname.set_text(formData[0][2])
self.cdtitle.set_text(formData[0][3])
self.cdgenre.set_text(formData[0][4])
self.cdlabel.set_text(formData[0][5])
self.cdnumber.set_text(formData[0][6])
self.cdyear.set_text(formData[0][7])
self.cdcomment.set_text(formData[0][8])
# insert song data
self.conn.execute("SELECT song FROM songs WHERE cdid = ? ORDER BY songid",(v1,))
SongList=self.conn.fetchall()
self.Sliststore.clear()
for data in SongList:
self.Sliststore.append(data)
#######################################
def nextRec(self, widget):
## go to the next record if one exists (this routine add one to self.i so it points to the next element in the idList
if self.i != len(self.idList)-1:
self.i += 1
self.loadForm(self)
#######################################
def prevRec(self, widget):
# and go back one if possible
if self.i != 0:
self.i -= 1
self.loadForm(self)
#######################################
def queryDB(self, widget):
## look up records that contain the text in the qentry text entry.
self.idRecs=[]; self.idList=[]
qv=str(self.qentry.get_text()) # get the value from the qentry entry box.
qslist=qv.split(' ') # split the value into words.
# delete current RLids
self.conn.execute("DELETE FROM tempRecList;")
self.connection.commit()
for qs in qslist:
qs = "%" + qs + "%"
# insert queried ids into tempRecList for ListRec()
## query the CDs table for any field that has the qentry words in it
self.conn.execute("INSERT INTO tempRecList (RLid) SELECT cdid FROM cds WHERE ((fname like ?) OR (lname like ?) OR (cdtitle like ?) OR (cdgenre like ?) OR (cdcomment like ?));",(qs,qs,qs,qs,qs,))
self.connection.commit()
# retrieve ids where query string is found
## get the primary keys of the records and place therm into the idList. The user can then just navigate only the queried records
self.conn.execute("SELECT cdid FROM cds WHERE ((fname like ?) OR (lname like ?) OR (cdtitle like ?) OR (cdgenre like ?) OR (cdcomment like ?)) ORDER BY lower(lname), lower(fname), lower(cdtitle);",(qs,qs,qs,qs,qs,))
self.idRecs=self.conn.fetchall()
for idR in self.idRecs:
self.idList.append(idR[0])
# display data if it exsts else show all records
self.i=0
if len(self.idList) == 0:
self.loadAll(self)
if len(self.idList) != 0:
self.loadForm(self)
#######################################
def updateEntry(self, widget):
## similar to addEntry but updates the database using the primary key
v1=str(self.idList[self.i])
self.conn.execute("update cds set fname=?, lname=?, cdtitle=?, cdgenre=?, cdlabel=?, cdnumber=?, cdyear=?, cdcomment=? where cdid=?",(self.fname.get_text(), self.lname.get_text(), self.cdtitle.get_text(), self.cdgenre.get_text(), self.cdlabel.get_text(), self.cdnumber.get_text(), self.cdyear.get_text(), self.cdcomment.get_text(), v1,))
self.connection.commit()
self.loadAll(self)
#######################################
dbfile = sys.argv[1]
cdsdb(dbfile)
gtk.main()
########################################

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

CAPTCHA
We can't accept links (unless you obfuscate them). You also need to negotiate the following CAPTCHA...

Username:   Password:
Create Account | About TuxRadar