¿Cuanto browser entra en 128 líneas de código?
Lo que me gustaba de ese browser de 42 líneas era que no era el ejemplo típico, donde meten una vista de Webkit en una ventana, cargan una página y te tratan de convencer de que son unos bananas. Esa versión son 7 líneas:
import sys from PyQt4 import QtGui,QtCore,QtWebKit app=QtGui.QApplication(sys.argv) wb=QtWebKit.QWebView() wb.setUrl(QtCore.QUrl('http://www.python.org')) wb.show() sys.exit(app.exec_())
O 6 si lo soportara un poco más feo.
¡Pero igual, el de 42 se veía útil!
Esos botones que se ven funcionaban correctamente, habilitando y deshabilitandose en el momento correcto, la entrada de URL cambiaba cuando hacías click en un link, y otras cositas así.
Ahí decidí empezar un pequeño proyecto intermitente de code golf: meter el mejor browser que pueda en 128 líneas de código (sin contar comentarios ni blancos), usando solo PyQt4.
Eso tiene un propósito útil: siempre sospeché que si uno asume PyQt como parte del sistema base, la mayoría de las aplicaciones entrarían en diskettes. Esta entra unas 500 veces en uno de 1.44MB (¡así que podés usar los de 360 de commodore sin duplidisk!)
hasta ahora van 50 líneas, y tiene los siguientes features:
Zoom in (Ctrl++)
Zoom out (Ctrl+-)
Reset Zoom (Ctrl+=)
Buscar (Ctrl+F)
Esconder búsqueda (Esc)
Botones de atrás/adelante y recargar
Entrada de URL que coincide con la página + autocompletado desde la historia + arregla la URL puesta a mano (agrega http://, esas cosas)
Plugins (incluído flash, que hay que bajar aparte ;-)
El título de la ventana muestra el título de la página (sin propaganda del browser)
Barra de progreso para la carga de la página
Barra de estado que muestra el destino de los links cuando pasas el mouse
Toma una URL en la línea de comando (o abre http://python.org
Multiplataforma (funciona donde funciona QtWebKit)
Faltan tabs y soporte de proxy. Espero que lleven unas 40 líneas más, pero creo que ya es el más capaz de todos estos browsers de ejemplo.
El código... no es tan terrible. Uso muchos lambdas, y los argumentos keyword de PyQt para conectar señales, que hacen que algunas líneas sean muy largas, pero no muy difíciles. Se podría achicar bastante todavía!
Aquí está en acción:
Y aquí está el código:
#!/usr/bin/env python "A web browser that will never exceed 128 lines of code. (not counting blanks)" import sys from PyQt4 import QtGui,QtCore,QtWebKit class MainWindow(QtGui.QMainWindow): def __init__(self, url): QtGui.QMainWindow.__init__(self) self.sb=self.statusBar() self.pbar = QtGui.QProgressBar() self.pbar.setMaximumWidth(120) self.wb=QtWebKit.QWebView(loadProgress = self.pbar.setValue, loadFinished = self.pbar.hide, loadStarted = self.pbar.show, titleChanged = self.setWindowTitle) self.setCentralWidget(self.wb) self.tb=self.addToolBar("Main Toolbar") for a in (QtWebKit.QWebPage.Back, QtWebKit.QWebPage.Forward, QtWebKit.QWebPage.Reload): self.tb.addAction(self.wb.pageAction(a)) self.url = QtGui.QLineEdit(returnPressed = lambda:self.wb.setUrl(QtCore.QUrl.fromUserInput(self.url.text()))) self.tb.addWidget(self.url) self.wb.urlChanged.connect(lambda u: self.url.setText(u.toString())) self.wb.urlChanged.connect(lambda: self.url.setCompleter(QtGui.QCompleter(QtCore.QStringList([QtCore.QString(i.url().toString()) for i in self.wb.history().items()]), caseSensitivity = QtCore.Qt.CaseInsensitive))) self.wb.statusBarMessage.connect(self.sb.showMessage) self.wb.page().linkHovered.connect(lambda l: self.sb.showMessage(l, 3000)) self.search = QtGui.QLineEdit(returnPressed = lambda: self.wb.findText(self.search.text())) self.search.hide() self.showSearch = QtGui.QShortcut("Ctrl+F", self, activated = lambda: (self.search.show() , self.search.setFocus())) self.hideSearch = QtGui.QShortcut("Esc", self, activated = lambda: (self.search.hide(), self.wb.setFocus())) self.quit = QtGui.QShortcut("Ctrl+Q", self, activated = self.close) self.zoomIn = QtGui.QShortcut("Ctrl++", self, activated = lambda: self.wb.setZoomFactor(self.wb.zoomFactor()+.2)) self.zoomOut = QtGui.QShortcut("Ctrl+-", self, activated = lambda: self.wb.setZoomFactor(self.wb.zoomFactor()-.2)) self.zoomOne = QtGui.QShortcut("Ctrl+=", self, activated = lambda: self.wb.setZoomFactor(1)) self.wb.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True) self.sb.addPermanentWidget(self.search) self.sb.addPermanentWidget(self.pbar) self.wb.load(url) if __name__ == "__main__": app=QtGui.QApplication(sys.argv) if len(sys.argv) > 1: url = QtCore.QUrl.fromUserInput(sys.argv[1]) else: url = QtCore.QUrl('http://www.python.org') wb=MainWindow(url) wb.show() sys.exit(app.exec_())