SF.net SVN: fclient:[789] trunk/fclient/src/fclient/impl
Status: Pre-Alpha
Brought to you by:
jurner
|
From: <jU...@us...> - 2008-07-27 20:05:24
|
Revision: 789
http://fclient.svn.sourceforge.net/fclient/?rev=789&view=rev
Author: jUrner
Date: 2008-07-27 20:05:32 +0000 (Sun, 27 Jul 2008)
Log Message:
-----------
reworked SaveKeyToDisk ++ add to dls widget
Modified Paths:
--------------
trunk/fclient/src/fclient/impl/DlgDownloadKeyToDisk.py
trunk/fclient/src/fclient/impl/ViewBrowser.py
trunk/fclient/src/fclient/impl/ViewDownloads.py
trunk/fclient/src/fclient/impl/tpls/DlgDownloadKeyToDiskTpl.ui
trunk/fclient/src/fclient/impl/tpls/Ui_DlgDownloadKeyToDiskTpl.py
Modified: trunk/fclient/src/fclient/impl/DlgDownloadKeyToDisk.py
===================================================================
--- trunk/fclient/src/fclient/impl/DlgDownloadKeyToDisk.py 2008-07-27 20:02:55 UTC (rev 788)
+++ trunk/fclient/src/fclient/impl/DlgDownloadKeyToDisk.py 2008-07-27 20:05:32 UTC (rev 789)
@@ -1,3 +1,10 @@
+#***************************************************************************************
+#TODO:
+# x. have to inject (..whatebver) a checkbox into msg box invalid key warning <x don't show this message again>
+# x. save dialog pos/size on exit
+#
+#*************************************************************************************
+
from __future__ import absolute_import
if __name__ == '__main__': # see --> http://bugs.python.org/issue1510172 . works only current dir and below
import os; __path__ = [os.path.dirname(__file__)]
@@ -6,18 +13,18 @@
from PyQt4 import QtCore, QtGui
from . import config
-from .lib.compactpath.qt4 import pathlabelwrap
+from .lib import fcp2
-
from .tpls.Ui_DlgDownloadKeyToDiskTpl import Ui_DlgDownloadKeyToDisk
#**********************************************************************************
#
#**********************************************************************************
class DlgDownloadKeyToDisk(QtGui.QDialog, Ui_DlgDownloadKeyToDisk):
- IdLabelKey = 'labelKey'
- IdEdDownloadFileName = 'edDownloadFileName'
- IdBtChooseDownloadFileName = 'btChooseDownloadFileName'
+ IdEdKey = 'edKey'
+ IdEdFileName = 'edFileName'
+ IdEdDirectory = 'edDirectory'
+ IdBtChooseDirectory = 'btChooseDirectory'
def __init__(self, parent=None, fcpKey=None):
@@ -26,52 +33,100 @@
self.setupUi(self)
self.setWindowTitle(config.FclientAppName + self.trUtf8(' - Download key..'))
- self._filePath = None
+ self._fileName = None
self._fcpKey = fcpKey
- self.pathLabelWrap = pathlabelwrap.PathLabelWrap(
- self.labelKey,
- fpath=unicode(self.labelKey.text()),
- path_module=config.CompactPathFcpKeyModule
- )
- self.connect(self.btChooseDownloadFileName, QtCore.SIGNAL('clicked()'), self.onChooseDownloadFileName)
+ # setup key editbox
+ ed = self.controlById(self.IdEdKey)
+ if fcpKey is not None:
+ ed.setText(fcpKey.toString())
+
+ # setup filename editbox
+ ed = self.controlById(self.IdEdFileName)
+ if fcpKey is not None:
+ # find out fileName to dl key to
+ fileName = config.guessFileNameFromKey(self._fcpKey)
+ if fileName is None:
+ fileName = self.trUtf8('UNKNOWN')
+ ed.setText(fileName)
+
+ # setup directory editbox
+ ed = self.controlById(self.IdEdDirectory)
+ ed.setText(unicode(config.settings.value('DownloadDir')))
+ bt = self.controlById(self.IdBtChooseDirectory)
+ self.connect(bt, QtCore.SIGNAL('clicked()'), self.onChooseDirectory)
- # find out fileName to dl key to
- fileName = config.guessFileNameFromKey(fcpKey)
- if fileName is None:
- fileName = self.trUtf8('UNKNOWN')
- self._filePath = os.path.join(unicode(config.settings.value('DownloadDir')), unicode(fileName))
- self.edDownloadFileName.setText(self._filePath)
- if self._fcpKey is not None:
- self.pathLabelWrap.setPath(self._fcpKey.toString())
-
- def filePath(self):
- return self._filePath
+ ##############################
+ ## methods
+ ##############################
+ def controlById(self, idControl):
+ return getattr(self, idControl)
- def onChooseDownloadFileName(self):
- filePath = QtGui.QFileDialog.getSaveFileName(
+ def fileName(self):
+ return self._fileName
+
+ def fcpKey(self):
+ return self._fcpKey
+
+ ##############################
+ ## overwritten methods
+ ##############################
+ def accept(self):
+ edKey = self.controlById(self.IdEdKey)
+ edFileName = self.controlById(self.IdEdFileName)
+ edDirectory = self.controlById(self.IdEdDirectory)
+
+ key = unicode(edKey.text())
+ if not key:
+ return QtGui.QMessageBox.critical(self, self.windowTitle(), 'Please enter a key to download')
+ try:
+ self._fcpKey = fcp2.Key(key)
+ except fcp2.ErrorKey:
+ result = QtGui.QMessageBox.warning(self,
+ self.windowTitle(),
+ 'Looks like the key entered is not valid. \nProceed anyways?',
+ QtGui.QMessageBox.Yes | QtGui.QMessageBox.No
+ )
+ if result == QtGui.QMessageBox.Yes:
+ self._fcpKey = fcp2.KeyAny(key)
+ else:
+ return
+
+ fileName = edFileName.text()
+ if fileName.isEmpty():
+ return QtGui.QMessageBox.critical(self, self.windowTitle(), 'Please enter a filename for the key')
+
+ directory = edDirectory.text()
+ if directory.isEmpty():
+ return QtGui.QMessageBox.critical(self, self.windowTitle(), 'Please enter a directory under wich to save the key')
+
+ self._fileName = os.path.join(unicode(directory), unicode(fileName))
+ self.done(self.Accepted)
+
+ ##############################
+ ## event handlers
+ ##############################
+ def onChooseDirectory(self):
+ edDirectory = self.controlById(self.IdEdDirectory)
+ directory = QtGui.QFileDialog.getExistingDirectory(
self,
- config.FclientAppName + self.trUtf8(' - Save key To..'),
- self.edDownloadFileName.text(),
+ config.FclientAppName + self.trUtf8(' - Download key to..'),
+ edDirectory.text(),
)
- if filePath:
- self._filePath = filePath
- self.edDownloadFileName.setText(filePath)
-
-
+ if directory:
+ edDirectory.setText(directory)
+
#**********************************************************************************
#
#**********************************************************************************
if __name__ == '__main__':
import sys
- class DummyKey(object):
- KeyType = 'USK@'
- def __init__(self): self.key = 'USG@qweqqweqwe'
- def toString(self): return self.key
-
app = QtGui.QApplication(sys.argv)
- w = DownloadKeyToDiskDlg(None, fcpKey=DummyKey())
+ w = DlgDownloadKeyToDisk(
+ #None,
+ fcpKey=fcp2.KeyKSK('foo.txt')
+ )
w.show()
res = app.exec_()
sys.exit(res)
Modified: trunk/fclient/src/fclient/impl/ViewBrowser.py
===================================================================
--- trunk/fclient/src/fclient/impl/ViewBrowser.py 2008-07-27 20:02:55 UTC (rev 788)
+++ trunk/fclient/src/fclient/impl/ViewBrowser.py 2008-07-27 20:05:32 UTC (rev 789)
@@ -23,6 +23,7 @@
# x. browser settings - QWebSettings
# x. shortcuts
# x. user staring gui for first time. maybe we should not connext untill the user connects explicitely
+# x. looks like on error loading page reload does not work
#******************************************************************************************
"""
@@ -545,16 +546,15 @@
if fcpKey is not None:
dlg = DlgDownloadKeyToDisk.DlgDownloadKeyToDisk(self, fcpKey=fcpKey)
if dlg.exec_() == dlg.Accepted:
- filePath = dlg.filePath()
+ fileName = dlg.fileName()
downloadsWidget = config.ObjectRegistry.get(config.IdViewCDownloadsWidget, None)
if downloadsWidget is None:
raise ValueError('no downloads widget found')
downloadsWidget.downloadFile(
fcpKey,
- filePath,
+ fileName,
persistence=fcp2.ConstPersistence.Forever,
handleFilenameCollision=True,
-
)
return True
return False
Modified: trunk/fclient/src/fclient/impl/ViewDownloads.py
===================================================================
--- trunk/fclient/src/fclient/impl/ViewDownloads.py 2008-07-27 20:02:55 UTC (rev 788)
+++ trunk/fclient/src/fclient/impl/ViewDownloads.py 2008-07-27 20:05:32 UTC (rev 789)
@@ -33,6 +33,7 @@
from . import config
from .lib import fcp2
from .lib.fcp2.lib import pmstruct
+from . import DlgDownloadKeyToDisk
from .tpls.Ui_ViewDownloadsWidgetTpl import Ui_ViewDownloadsWidget
#**********************************************************************************
@@ -47,8 +48,81 @@
self.displayName=self.trUtf8('Downloads')
self.icon=QtGui.QIcon()
+
+
#**********************************************************************************
#
+#**********************************************************************************
+class DownloadsWidgetGlobalFeedback(config.GlobalFeedbackBase):
+ """wrapper for global statusbar widgets, menus"""
+
+ def __init__(self, parent, idGlobalFeedback):
+ config.GlobalFeedbackBase.__init__(self, parent, idGlobalFeedback)
+
+ # menus
+ self.menus = []
+ if self.menuBar is not None and hasattr(parent, 'fcViewObject'):
+ menu = QtGui.QMenu(parent.fcViewObject.displayName, self.menuBar)
+ parent.populateMenu(menu)
+ self.menus.append(menu)
+ self.menuBar.addViewMenu(menu)
+
+ # status bar widgets
+ self.labelStatus = None
+ self.progress = None
+ self.labelFeedbackWrap = None
+ #if self.statusBar is not None:
+ # self.labelStatus = QtGui.QLabel(QtCore.QString(), self.statusBar)
+ # self.statusBar.addWidget(self.labelStatus)
+ #
+ # self.progress = QtGui.QProgressBar(self.statusBar)
+ # self.progress.setRange(0, Browser.MaxProgress)
+ # self.progress.setValue(0)
+ # self.statusBar.addWidget(self.progress)
+ #
+ # label = QtGui.QLabel(self.statusBar)
+ # label.setFrameStyle(QtGui.QLabel.Sunken | QtGui.QLabel.Box)
+ # self.labelFeedbackWrap = pathlabelwrap.PathLabelWrap(
+ # label,
+ # path_module=config.CompactPathFcpKeyModule,
+ # )
+ # self.statusBar.addWidget(self.labelFeedbackWrap.label, 1)
+
+
+ def setVisible(self, flag):
+ if self.menuBar is not None:
+ for menu in self.menus:
+ menu.children()[0].setVisible(flag)
+ #if self.statusBar is not None:
+ # self.progress.setVisible(flag)
+ # self.labelStatus.setVisible(flag)
+ # self.labelFeedbackWrap.label.setVisible(flag)
+
+ #def setProgress(self, n):
+ # if self.progress is not None:
+ # self.progress.setValue(n)
+
+ #def setStatusMessage(self, qString):
+ # if self.labelStatus is not None:
+ # self.labelStatus.setText(qString)
+
+ #def setFeedback(self, qString):
+ # if self.labelFeedbackWrap is not None:
+ # self.labelFeedbackWrap.setPath(unicode(qString))
+
+class DownloadsWidgetActions(config.ActionsBase):
+
+ def __init__(self, parent):
+ config.ActionsBase.__init__(self, parent)
+
+ self.action(
+ name='ActionDownloadKeyToDisk',
+ text=self.trUtf8('Download &key...'),
+ trigger=parent.onDownloadKey,
+ )
+
+#**********************************************************************************
+#
#**********************************************************************************
class PersistentRequestData(pmstruct.PMStruct):
_fields_ = (
@@ -138,8 +212,9 @@
self.setupUi(self)
config.ObjectRegistry.register(self)
-
+ self.fcActions = DownloadsWidgetActions(self)
self.fcViewObject = DownloadsViewObject(self)
+ self.fcGlobalFeedback = DownloadsWidgetGlobalFeedback(self, idGlobalFeedback)
self.fcpEvents = (
(config.fcpClient.events.ConfigData, self.onFcpConfigData),
(config.fcpClient.events.RequestCompleted, self.onFcpRequestCompleted),
@@ -188,6 +263,12 @@
self.viewClose()
+ def hideEvent(self, event):
+ self.fcGlobalFeedback.setVisible(False)
+
+ def showEvent(self, event):
+ self.fcGlobalFeedback.setVisible(True)
+
def viewClose(self):
config.fcpClient.events -= self.fcpEvents
@@ -201,10 +282,12 @@
persistentUserData=PersistentRequestData(ClientName=unicode(self.objectName())).dump(),
**kws
)
- item = self._createItemFromFcpRequest(config.fcpClient.getRequest(cpIdentifier))
+ item = self._createItemFromFcpRequest(config.fcpClient.getRequest(fcpIdentifier))
+ def populateMenu(self, menu):
+ menu.addAction(self.fcActions['ActionDownloadKeyToDisk'])
+ return menu
-
#########################################
## methods
@@ -213,6 +296,19 @@
return getattr(idGlobalFeedback, idControl)
#########################################
+ ## event handlers
+ #########################################
+ def onDownloadKey(self, action):
+ dlg = DlgDownloadKeyToDisk.DlgDownloadKeyToDisk(self, fcpKey=None)
+ if dlg.exec_() == dlg.Accepted:
+ self.downloadFile(
+ dlg.fcpKey(),
+ dlg.fileName(),
+ persistence=fcp2.ConstPersistence.Forever,
+ handleFilenameCollision=True,
+ )
+
+ #########################################
## fcp event handlers
#########################################
def onFcpConfigData(self, fcpEvent, fcpRequest):
Modified: trunk/fclient/src/fclient/impl/tpls/DlgDownloadKeyToDiskTpl.ui
===================================================================
--- trunk/fclient/src/fclient/impl/tpls/DlgDownloadKeyToDiskTpl.ui 2008-07-27 20:02:55 UTC (rev 788)
+++ trunk/fclient/src/fclient/impl/tpls/DlgDownloadKeyToDiskTpl.ui 2008-07-27 20:05:32 UTC (rev 789)
@@ -6,7 +6,7 @@
<x>0</x>
<y>0</y>
<width>431</width>
- <height>175</height>
+ <height>243</height>
</rect>
</property>
<property name="windowTitle" >
@@ -18,43 +18,45 @@
<item>
<widget class="QLabel" name="label" >
<property name="text" >
- <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Key:</span></p></body></html></string>
+ <string><b>Key:</b></string>
</property>
</widget>
</item>
<item>
- <widget class="QLabel" name="labelKey" >
+ <widget class="QLineEdit" name="edKey" >
+ <property name="dragEnabled" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3" >
<property name="text" >
- <string>USK@qwweqweqweqwe.../foo</string>
+ <string><b>File name:</b></string>
</property>
</widget>
</item>
<item>
+ <widget class="QLineEdit" name="edFileName" />
+ </item>
+ <item>
<widget class="QLabel" name="label_2" >
<property name="text" >
- <string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
-<html><head><meta name="qrichtext" content="1" /><style type="text/css">
-p, li { white-space: pre-wrap; }
-</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
-<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Download to:</span></p></body></html></string>
+ <string><b>Directory:</b></string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<item>
- <widget class="QLineEdit" name="edDownloadFileName" >
+ <widget class="QLineEdit" name="edDirectory" >
<property name="dragEnabled" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
- <widget class="QPushButton" name="btChooseDownloadFileName" >
+ <widget class="QPushButton" name="btChooseDirectory" >
<property name="text" >
<string>...</string>
</property>
Modified: trunk/fclient/src/fclient/impl/tpls/Ui_DlgDownloadKeyToDiskTpl.py
===================================================================
--- trunk/fclient/src/fclient/impl/tpls/Ui_DlgDownloadKeyToDiskTpl.py 2008-07-27 20:02:55 UTC (rev 788)
+++ trunk/fclient/src/fclient/impl/tpls/Ui_DlgDownloadKeyToDiskTpl.py 2008-07-27 20:05:32 UTC (rev 789)
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/tpls/DlgDownloadKeyToDiskTpl.ui'
+# Form implementation generated from reading ui file '/home/me/src/proj/fclient/trunk/fclient/src/fclient/impl/tpls/DlgDownloadKeyToDiskTpl.ui'
#
-# Created: Thu Jul 24 10:12:00 2008
+# Created: Sun Jul 27 21:01:10 2008
# by: PyQt4 UI code generator 4.4.3-snapshot-20080705
#
# WARNING! All changes made in this file will be lost!
@@ -12,7 +12,7 @@
class Ui_DlgDownloadKeyToDisk(object):
def setupUi(self, DlgDownloadKeyToDisk):
DlgDownloadKeyToDisk.setObjectName("DlgDownloadKeyToDisk")
- DlgDownloadKeyToDisk.resize(431, 175)
+ DlgDownloadKeyToDisk.resize(431, 243)
self.gridLayout = QtGui.QGridLayout(DlgDownloadKeyToDisk)
self.gridLayout.setObjectName("gridLayout")
self.verticalLayout = QtGui.QVBoxLayout()
@@ -20,21 +20,28 @@
self.label = QtGui.QLabel(DlgDownloadKeyToDisk)
self.label.setObjectName("label")
self.verticalLayout.addWidget(self.label)
- self.labelKey = QtGui.QLabel(DlgDownloadKeyToDisk)
- self.labelKey.setObjectName("labelKey")
- self.verticalLayout.addWidget(self.labelKey)
+ self.edKey = QtGui.QLineEdit(DlgDownloadKeyToDisk)
+ self.edKey.setDragEnabled(True)
+ self.edKey.setObjectName("edKey")
+ self.verticalLayout.addWidget(self.edKey)
+ self.label_3 = QtGui.QLabel(DlgDownloadKeyToDisk)
+ self.label_3.setObjectName("label_3")
+ self.verticalLayout.addWidget(self.label_3)
+ self.edFileName = QtGui.QLineEdit(DlgDownloadKeyToDisk)
+ self.edFileName.setObjectName("edFileName")
+ self.verticalLayout.addWidget(self.edFileName)
self.label_2 = QtGui.QLabel(DlgDownloadKeyToDisk)
self.label_2.setObjectName("label_2")
self.verticalLayout.addWidget(self.label_2)
self.horizontalLayout = QtGui.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
- self.edDownloadFileName = QtGui.QLineEdit(DlgDownloadKeyToDisk)
- self.edDownloadFileName.setDragEnabled(True)
- self.edDownloadFileName.setObjectName("edDownloadFileName")
- self.horizontalLayout.addWidget(self.edDownloadFileName)
- self.btChooseDownloadFileName = QtGui.QPushButton(DlgDownloadKeyToDisk)
- self.btChooseDownloadFileName.setObjectName("btChooseDownloadFileName")
- self.horizontalLayout.addWidget(self.btChooseDownloadFileName)
+ self.edDirectory = QtGui.QLineEdit(DlgDownloadKeyToDisk)
+ self.edDirectory.setDragEnabled(True)
+ self.edDirectory.setObjectName("edDirectory")
+ self.horizontalLayout.addWidget(self.edDirectory)
+ self.btChooseDirectory = QtGui.QPushButton(DlgDownloadKeyToDisk)
+ self.btChooseDirectory.setObjectName("btChooseDirectory")
+ self.horizontalLayout.addWidget(self.btChooseDirectory)
self.verticalLayout.addLayout(self.horizontalLayout)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
spacerItem = QtGui.QSpacerItem(20, 15, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
@@ -57,18 +64,10 @@
def retranslateUi(self, DlgDownloadKeyToDisk):
DlgDownloadKeyToDisk.setWindowTitle(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
- self.label.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
-"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
-"p, li { white-space: pre-wrap; }\n"
-"</style></head><body style=\" font-family:\'Sans Serif\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
-"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600;\">Key:</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
- self.labelKey.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "USK@qwweqweqweqwe.../foo", None, QtGui.QApplication.UnicodeUTF8))
- self.label_2.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
-"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
-"p, li { white-space: pre-wrap; }\n"
-"</style></head><body style=\" font-family:\'Sans Serif\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
-"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600;\">Download to:</span></p></body></html>", None, QtGui.QApplication.UnicodeUTF8))
- self.btChooseDownloadFileName.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "...", None, QtGui.QApplication.UnicodeUTF8))
+ self.label.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "<b>Key:</b>", None, QtGui.QApplication.UnicodeUTF8))
+ self.label_3.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "<b>File name:</b>", None, QtGui.QApplication.UnicodeUTF8))
+ self.label_2.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "<b>Directory:</b>", None, QtGui.QApplication.UnicodeUTF8))
+ self.btChooseDirectory.setText(QtGui.QApplication.translate("DlgDownloadKeyToDisk", "...", None, QtGui.QApplication.UnicodeUTF8))
if __name__ == "__main__":
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|