diff --git a/main.py b/main.py
index 3409f4f..c59ca14 100644
--- a/main.py
+++ b/main.py
@@ -32,6 +32,206 @@ class FileSearchResults(QtWidgets.QDialog):
url = QtCore.QUrl.fromLocalFile(directory)
QtGui.QDesktopServices.openUrl(url)
+
+class WebSearchResults(QtWidgets.QDialog):
+ def __init__(self, results, parent=None):
+ super().__init__(parent)
+ self.setWindowTitle(f"Web Search Results - {results['query']}")
+ self.setMinimumSize(800, 600)
+
+ self.results = results
+
+ # Main layout
+ layout = QtWidgets.QVBoxLayout()
+
+ # Info label
+ info_text = f"Engine: {results['engine']} | Page: {results['page']}"
+ if results.get('cached'):
+ info_text += " | (Cached results)"
+ info_label = QtWidgets.QLabel(info_text)
+ info_label.setStyleSheet("color: gray; font-size: 10px; padding: 5px;")
+ layout.addWidget(info_label)
+
+ # Scroll area
+ scroll = QtWidgets.QScrollArea()
+ scroll.setWidgetResizable(True)
+ scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # type: ignore
+
+ # Container
+ container = QtWidgets.QWidget()
+ container_layout = QtWidgets.QVBoxLayout(container)
+ container_layout.setSpacing(15)
+
+ # Add infobox
+ if results.get('infobox'):
+ infobox_widget = self._create_infobox_widget(results['infobox'])
+ container_layout.addWidget(infobox_widget)
+
+ # Separator
+ line = QtWidgets.QFrame()
+ line.setFrameShape(QtWidgets.QFrame.HLine) #type: ignore
+ line.setFrameShadow(QtWidgets.QFrame.Sunken) #type: ignore
+ container_layout.addWidget(line)
+
+ # Add news
+ if results.get('news'):
+ news_label = QtWidgets.QLabel("News")
+ news_label.setStyleSheet("border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px;")
+ container_layout.addWidget(news_label)
+
+ for news_item in results['news'][:5]: # Show first 5 news items
+ news_widget = self._create_news_widget(news_item)
+ container_layout.addWidget(news_widget)
+
+ # Separator
+ line = QtWidgets.QFrame()
+ line.setFrameShape(QtWidgets.QFrame.HLine) #type: ignore
+ line.setFrameShadow(QtWidgets.QFrame.Sunken) #type: ignore
+ container_layout.addWidget(line)
+
+ # Add results
+ for result in results.get('results', []):
+ result_widget = self._create_result_widget(result)
+ container_layout.addWidget(result_widget)
+
+ container_layout.addStretch()
+ scroll.setWidget(container)
+ layout.addWidget(scroll)
+
+ # Navigation buttons
+ nav_layout = QtWidgets.QHBoxLayout()
+
+ if results['page'] > 1:
+ prev_button = QtWidgets.QPushButton("← Previous Page")
+ prev_button.clicked.connect(lambda: self.load_page(results['page'] - 1))
+ nav_layout.addWidget(prev_button)
+
+ nav_layout.addStretch()
+
+ if results.get('has_next_page'):
+ next_button = QtWidgets.QPushButton("Next Page →")
+ next_button.clicked.connect(lambda: self.load_page(results['page'] + 1))
+ nav_layout.addWidget(next_button)
+
+ layout.addLayout(nav_layout)
+
+ self.setLayout(layout)
+
+ def _create_infobox_widget(self, infobox):
+ """Create widget for infobox display."""
+ widget = QtWidgets.QFrame()
+ widget.setFrameShape(QtWidgets.QFrame.StyledPanel) #type: ignore
+ widget.setStyleSheet("border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px;")
+
+ layout = QtWidgets.QVBoxLayout(widget)
+
+ # Title
+ title = QtWidgets.QLabel(infobox.get('title', ''))
+ title.setStyleSheet("font-weight: bold; font-size: 16px;")
+ title.setWordWrap(True)
+ layout.addWidget(title)
+
+ # Subtitle
+ if infobox.get('subtitle'):
+ subtitle = QtWidgets.QLabel(infobox['subtitle'])
+ subtitle.setStyleSheet("color: gray; font-size: 12px;")
+ subtitle.setWordWrap(True)
+ layout.addWidget(subtitle)
+
+ # URL
+ if infobox.get('url'):
+ url_label = QtWidgets.QLabel(f'{infobox["url"]}')
+ url_label.setOpenExternalLinks(True)
+ url_label.setStyleSheet("color: blue; font-size: 11px;")
+ layout.addWidget(url_label)
+
+ # Description
+ if infobox.get('description'):
+ desc = QtWidgets.QLabel(infobox['description'])
+ desc.setWordWrap(True)
+ desc.setStyleSheet("margin-top: 5px;")
+ layout.addWidget(desc)
+
+ return widget
+
+ def _create_news_widget(self, news_item):
+ """Create widget for news item display."""
+ widget = QtWidgets.QFrame()
+ widget.setFrameShape(QtWidgets.QFrame.Box) #type: ignore
+ widget.setStyleSheet("border: 1px solid #e0e0e0; border-radius: 3px; padding: 8px;")
+
+ layout = QtWidgets.QVBoxLayout(widget)
+ layout.setSpacing(3)
+
+ # Source
+ source_label = QtWidgets.QLabel(news_item.get('source', ''))
+ source_label.setStyleSheet("color: green; font-size: 10px;")
+ layout.addWidget(source_label)
+
+ # Title (clickable)
+ title = QtWidgets.QLabel(f'{news_item.get("title", "")}')
+ title.setOpenExternalLinks(True)
+ title.setWordWrap(True)
+ title.setStyleSheet("font-size: 12px;")
+ layout.addWidget(title)
+
+ # Timestamp
+ if news_item.get('timestamp'):
+ time_label = QtWidgets.QLabel(news_item['timestamp'])
+ time_label.setStyleSheet("color: gray; font-size: 9px;")
+ layout.addWidget(time_label)
+
+ return widget
+
+ def _create_result_widget(self, result):
+ """Create widget for search result display."""
+ widget = QtWidgets.QFrame()
+ widget.setFrameShape(QtWidgets.QFrame.NoFrame) #type: ignore
+ widget.setStyleSheet("padding: 5px;")
+
+ layout = QtWidgets.QVBoxLayout(widget)
+ layout.setSpacing(5)
+
+ # Display URL
+ if result.get('display_url'):
+ url_label = QtWidgets.QLabel(result['display_url'])
+ url_label.setStyleSheet("color: green; font-size: 11px;")
+ layout.addWidget(url_label)
+
+ # Title
+ title = QtWidgets.QLabel(f'{result.get("title", "")}')
+ title.setOpenExternalLinks(True)
+ title.setWordWrap(True)
+ title.setStyleSheet("font-size: 14px; color: #1a0dab;")
+ layout.addWidget(title)
+
+ # Snippet
+ if result.get('snippet'):
+ snippet = QtWidgets.QLabel(result['snippet'])
+ snippet.setWordWrap(True)
+ snippet.setStyleSheet("color: #545454; font-size: 12px;")
+ layout.addWidget(snippet)
+
+ return widget
+
+ def load_page(self, page_num):
+ """Load a different page of results."""
+ try:
+ QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) # type: ignore
+ leta = MullvadLetaWrapper(engine=self.results['engine'])
+ new_results = leta.search(self.results['query'], page=page_num)
+
+ # Close current dialog and open new one
+ new_dialog = WebSearchResults(new_results, self.parent())
+ new_dialog.show()
+ self.close()
+
+ except Exception as e:
+ QtWidgets.QMessageBox.critical(self, "Search Error", str(e))
+ finally:
+ QtWidgets.QApplication.restoreOverrideCursor()
+
+
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, restart=False):
super().__init__()
@@ -143,9 +343,15 @@ class MainWindow(QtWidgets.QMainWindow):
QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) #type: ignore
leta = MullvadLetaWrapper(engine="brave")
results = leta.search(query)
- except RuntimeError as e:
+
+ if results and results.get('results'):
+ self.web_results_dialog = WebSearchResults(results, self)
+ self.web_results_dialog.show()
+ else:
+ QtWidgets.QMessageBox.information(self, "No Results", "No web search results found.")
+
+ except Exception as e:
QtWidgets.QMessageBox.critical(self, "Search Error", str(e))
- return
finally:
QtWidgets.QApplication.restoreOverrideCursor()