# Add close button to tab
close_btn = QPushButton("×")
close_btn.setFixedSize(20, 20)
close_btn.setStyleSheet("""
QPushButton {
background: rgba(255, 255, 255, 0.1);
border: none;
border-radius: 10px;
color: white;
font-weight: bold;
}
QPushButton:hover {
background: rgba(255, 0, 0, 0.7);
}
""")
close_btn.clicked.connect(lambda: self.close_tab(i))
self.tabs.tabBar().setTabButton(i, QTabBar.RightSide,
close_btn)
# Update address bar
if qurl.toString() != "quarix://start":
self.address_bar.setText(qurl.toString())
else:
self.address_bar.setText("")
def get_start_page_html(self):
"""Generate beautiful start page HTML"""
return """
<!DOCTYPE html>
<html>
<head>
<title>Quarix Start</title>
<style>
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana,
sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%,
#16213e 50%, #0f3460 100%);
color: white;
overflow-x: hidden;
}
.wave-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: -1;
}
.wave {
position: absolute;
top: 50%;
left: 50%;
width: 200%;
height: 200%;
background: radial-gradient(circle,
rgba(0,120,212,0.1) 0%, transparent 70%);
animation: wave 10s infinite linear;
transform-origin: center;
}
.wave:nth-child(2) {
animation-delay: -5s;
background: radial-gradient(circle,
rgba(16,110,190,0.1) 0%, transparent 70%);
}
@keyframes wave {
0% { transform: translate(-50%, -50%)
rotate(0deg); }
100% { transform: translate(-50%, -50%)
rotate(360deg); }
}
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 20px;
position: relative;
z-index: 1;
}
.logo {
font-size: 4rem;
font-weight: bold;
margin-bottom: 20px;
background: linear-gradient(45deg, #0078d4,
#00bcf2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 0 0 30px rgba(0,120,212,0.5);
animation: glow 2s ease-in-out infinite alternate;
}
@keyframes glow {
from { text-shadow: 0 0 30px
rgba(0,120,212,0.5); }
to { text-shadow: 0 0 50px rgba(0,120,212,0.8), 0
0 60px rgba(0,188,242,0.6); }
}
.tagline {
font-size: 1.5rem;
margin-bottom: 40px;
text-align: center;
opacity: 0.9;
}
.search-container {
width: 100%;
max-width: 600px;
margin-bottom: 40px;
position: relative;
}
.search-box {
width: 100%;
padding: 20px 25px;
font-size: 18px;
border: 2px solid rgba(0,120,212,0.3);
border-radius: 50px;
background: rgba(255,255,255,0.1);
color: white;
outline: none;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
}
.search-box:focus {
border-color: #0078d4;
box-shadow: 0 0 30px rgba(0,120,212,0.3);
background: rgba(255,255,255,0.15);
}
.search-box::placeholder {
color: rgba(255,255,255,0.7);
}
.quick-links {
display: grid;
grid-template-columns: repeat(auto-fit,
minmax(200px, 1fr));
gap: 20px;
width: 100%;
max-width: 800px;
margin-bottom: 40px;
}
.quick-link {
background: rgba(255,255,255,0.1);
border: 1px solid rgba(0,120,212,0.3);
border-radius: 15px;
padding: 20px;
text-align: center;
text-decoration: none;
color: white;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.quick-link:hover {
background: rgba(0,120,212,0.2);
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,120,212,0.3);
}
.quick-link-icon {
font-size: 2rem;
margin-bottom: 10px;
display: block;
}
.quick-link-title {
font-weight: bold;
margin-bottom: 5px;
}
.quick-link-desc {
font-size: 0.9rem;
opacity: 0.8;
}
.features {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 30px;
margin-top: 40px;
}
.feature {
text-align: center;
max-width: 200px;
}
.feature-icon {
font-size: 2.5rem;
margin-bottom: 10px;
display: block;
}
.feature-title {
font-weight: bold;
margin-bottom: 5px;
}
.feature-desc {
font-size: 0.9rem;
opacity: 0.8;
}
@media (max-width: 768px) {
.logo { font-size: 3rem; }
.tagline { font-size: 1.2rem; }
.search-box { padding: 15px 20px; font-size: 16px;
}
.quick-links { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="wave-container">
<div class="wave"></div>
<div class="wave"></div>
</div>
<div class="container">
<div class="logo">🚀 QUARIX</div>
<div class="tagline">Next Generation Web Browser</div>
<div class="search-container">
<input type="text" class="search-box"
placeholder="🔍 Search the web or enter URL..."
onkeypress="if(event.key==='Enter')
window.location.href='https://www.google.com/search?
q='+encodeURIComponent(this.value)">
</div>
<div class="quick-links">
<a href="https://www.google.com" class="quick-
link">
<span class="quick-link-icon">🔍</span>
<div class="quick-link-title">Google
Search</div>
<div class="quick-link-desc">Search the
web</div>
</a>
<a href="https://www.youtube.com" class="quick-
link">
<span class="quick-link-icon">📺</span>
<div class="quick-link-title">YouTube</div>
<div class="quick-link-desc">Watch
videos</div>
</a>
<a href="https://www.github.com" class="quick-
link">
<span class="quick-link-icon">💻</span>
<div class="quick-link-title">GitHub</div>
<div class="quick-link-desc">Code
repository</div>
</a>
<a href="https://www.reddit.com" class="quick-
link">
<span class="quick-link-icon">💬</span>
<div class="quick-link-title">Reddit</div>
<div class="quick-link-desc">Social news</div>
</a>
</div>
<div class="features">
<div class="feature">
<span class="feature-icon">🤖</span>
<div class="feature-title">AI Assistant</div>
<div class="feature-desc">Chat with Quarix
AI</div>
</div>
<div class="feature">
<span class="feature-icon"></span>
<div class="feature-title">Privacy First</div>
<div class="feature-desc">Built-in ad
blocker</div>
</div>
<div class="feature">
<span class="feature-icon">⚡</span>
<div class="feature-title">Lightning
Fast</div>
<div class="feature-desc">Optimized
performance</div>
</div>
<div class="feature">
<span class="feature-icon">🎨</span>
<div class="feature-title">Beautiful UI</div>
<div class="feature-desc">Modern design</div>
</div>
</div>
</div>
</body>
</html>
"""
def send_quarix_message(self):
"""Send message to Quarix AI with real Gemini API"""
message = self.chat_input.toPlainText().strip()
if not message:
return
# Clear input
self.chat_input.clear()
# Add user message to chat
user_html = f"""
<div style='margin: 15px 0; padding: 12px; background:
rgba(0,120,212,0.2);
border-radius: 15px 15px 5px 15px; border-left:
4px solid #0078d4;'>
<strong style='color: #0078d4;'>👤 You:</strong><br>
<span style='color: white; margin-top: 5px; display:
block;'>{message}</span>
</div>
"""
self.chat_display.insertHtml(user_html)
# Show typing indicator
typing_html = """
<div id='typing' style='margin: 15px 0; padding: 12px;
background: rgba(40,40,40,0.8);
border-radius: 15px 15px 15px 5px;
border-left: 4px solid #00bcf2;'>
<strong style='color: #00bcf2;'>🤖 Quarix:</strong><br>
<span style='color: #cccccc; font-style:
italic;'>Thinking... 💭</span>
</div>
"""
self.chat_display.insertHtml(typing_html)
self.chat_display.verticalScrollBar().setValue(self.chat_display.verti
calScrollBar().maximum())
# Send to AI in separate thread
threading.Thread(target=self.get_real_quarix_response,
args=(message,), daemon=True).start()
def get_real_quarix_response(self, message):
"""Get real response from Gemini AI"""
try:
if self.gemini_model is None:
response = "I'm sorry, but I need a valid Gemini API
key to function. Please add your API key in the settings."
else:
# Create context-aware prompt
context = f"""
You are Quarix, an advanced AI assistant built into
the Quarix Browser.
You are helpful, intelligent, and focused on web
browsing, technology, and user assistance.
Current context:
- User is browsing with Quarix Browser
- Current URL: {self.get_current_url()}
- Browser features: AI chat, ad blocking, privacy
protection, bookmarks, history
User message: {message}
Respond as Quarix in a helpful, friendly manner. Keep
responses concise but informative.
"""
response = self.gemini_model.generate_content(context)
response_text = response.text
# Save to database
self.save_chat_to_db(message, response_text)
except Exception as e:
response_text = f"I apologize, but I'm experiencing some
technical difficulties right now. Error: {str(e)[:100]}..."
# Update UI in main thread
QTimer.singleShot(0, lambda:
self.display_quarix_response(response_text))
def display_quarix_response(self, response):
"""Display Quarix response in chat"""
# Remove typing indicator
html = self.chat_display.toHtml()
html = html.replace('<div id=\'typing\'', '<div id=\'typing\'
style=\'display:none;\'')
# Add Quarix response
response_html = f"""
<div style='margin: 15px 0; padding: 12px; background:
rgba(40,40,40,0.8);
border-radius: 15px 15px 15px 5px; border-left:
4px solid #00bcf2;'>
<strong style='color: #00bcf2;'>🤖 Quarix:</strong><br>
<span style='color: white; margin-top: 5px; display:
block; line-height: 1.4;'>{response}</span>
</div>
"""
self.chat_display.insertHtml(response_html)
self.chat_display.verticalScrollBar().setValue(self.chat_display.verti
calScrollBar().maximum())
def save_chat_to_db(self, user_message, quarix_response):
"""Save chat conversation to database"""
cursor = self.conn.cursor()
cursor.execute("""
INSERT INTO quarix_chats (user_message, quarix_response,
timestamp, session_id)
VALUES (?, ?, ?, ?)
""", (user_message, quarix_response, datetime.now(),
"default"))
self.conn.commit()
def clear_chat(self):
"""Clear chat history"""
self.chat_display.clear()
welcome_msg = """
<div style='color: #0078d4; font-weight: bold; margin-bottom:
10px;'>
🚀 Chat cleared! How can I help you?
</div>
"""
self.chat_display.setHtml(welcome_msg)
def get_current_url(self):
"""Get current tab URL"""
current_tab = self.tabs.currentWidget()
if current_tab:
return current_tab.url().toString()
return ""
def navigate_to_url(self):
"""Enhanced URL navigation with smart detection"""
url = self.address_bar.text().strip()
if not url:
return
# Smart URL detection
if url.startswith('quarix://'):
# Handle special Quarix URLs
if url == 'quarix://start':
current_tab = self.tabs.currentWidget()
current_tab.setHtml(self.get_start_page_html())
return
elif not url.startswith(('http://', 'https://')):
if self.is_url(url):
url = 'https://' + url
else:
# Search query
search_engine = self.settings.get('search_engine',
'google')
if search_engine == 'google':
url = f"https://www.google.com/search?
q={requests.utils.quote(url)}"
elif search_engine == 'bing':
url = f"https://www.bing.com/search?
q={requests.utils.quote(url)}"
elif search_engine == 'duckduckgo':
url = f"https://duckduckgo.com/?
q={requests.utils.quote(url)}"
# Navigate
qurl = QUrl(url)
current_tab = self.tabs.currentWidget()
current_tab.setUrl(qurl)
# Add to history
self.add_to_history(url, "")
def is_url(self, text):
"""Check if text is a URL"""
return ('.' in text and
' ' not in text and
len(text.split('.')) >= 2 and
not text.startswith('search '))
def toggle_quarix_ai(self):
"""Toggle Quarix AI panel with animation"""
if self.ai_panel.isVisible():
# Animate hide
self.ai_panel.hide()
else:
# Animate show
self.ai_panel.show()
# Focus on input
self.chat_input.setFocus()
def update_url_bar(self, qurl, browser=None):
"""Update address bar with current URL"""
if browser == self.tabs.currentWidget():
url_string = qurl.toString()
if url_string.startswith('quarix://'):
self.address_bar.setText("")
else:
self.address_bar.setText(url_string)
self.update_security_indicator(qurl)
def update_title(self, browser):
"""Update tab title with favicon"""
if browser == self.tabs.currentWidget():
title = browser.page().title()
if title:
i = self.tabs.currentIndex()
# Truncate long titles
display_title = title[:25] + "..." if len(title) > 25
else title
self.tabs.setTabText(i, display_title)
self.tabs.setTabToolTip(i, title)
def update_tab_title(self, title, browser):
"""Update specific tab title"""
for i in range(self.tabs.count()):
if self.tabs.widget(i) == browser:
display_title = title[:25] + "..." if len(title) > 25
else title
self.tabs.setTabText(i, display_title)
self.tabs.setTabToolTip(i, title)
break
def update_progress(self, progress):
"""Update loading progress with visual feedback"""
if progress < 100:
self.page_status.setText(f"⏳ Loading... {progress}%")
# Update tab with loading indicator
current_index = self.tabs.currentIndex()
current_text = self.tabs.tabText(current_index)
if not current_text.startswith("⏳"):
self.tabs.setTabText(current_index, f"⏳
{current_text}")
else:
self.page_status.setText("✅ Ready")
# Remove loading indicator
current_index = self.tabs.currentIndex()
current_text = self.tabs.tabText(current_index)
if current_text.startswith("⏳"):
self.tabs.setTabText(current_index, current_text[2:])
def update_security_indicator(self, qurl):
"""Update security indicator with detailed info"""
if qurl.scheme() == 'https':
self.security_indicator.setText("🔒")
self.security_indicator.setToolTip("Secure HTTPS
connection")
self.security_status.setText(" Secure")
elif qurl.scheme() == 'http':
self.security_indicator.setText("⚠️")
self.security_indicator.setToolTip("Insecure HTTP
connection")
self.security_status.setText("⚠️Not Secure")
else:
self.security_indicator.setText("ℹ️")
self.security_indicator.setToolTip("Local or special
page")
self.security_status.setText("ℹ️ Local")
def close_tab(self, i):
"""Close tab with confirmation for important tabs"""
if self.tabs.count() <= 1:
# Don't close last tab, navigate to start page instead
self.tabs.currentWidget().setHtml(self.get_start_page_html())
self.address_bar.setText("")
return
# Check if tab has unsaved changes (forms, etc.)
widget = self.tabs.widget(i)
if hasattr(widget, 'hasUnsavedChanges') and
widget.hasUnsavedChanges():
reply = QMessageBox.question(
self.main_window,
'Close Tab',
'This tab may have unsaved changes. Close anyway?',
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.No:
return
self.tabs.removeTab(i)
def current_tab_changed(self, i):
"""Handle tab change with enhanced features"""
if i >= 0:
current_widget = self.tabs.widget(i)
if current_widget:
qurl = current_widget.url()
self.update_url_bar(qurl, current_widget)
# Update window title
title = current_widget.page().title()
if title:
self.main_window.setWindowTitle(f"{title} - Quarix
Browser")
else:
self.main_window.setWindowTitle("Quarix Browser -
Next Generation Web Experience")
def tab_double_clicked(self, index):
"""Handle tab double-click to rename"""
if index >= 0:
current_title = self.tabs.tabText(index)
new_title, ok = QInputDialog.getText(
self.main_window,
'Rename Tab',
'Enter new tab name:',
text=current_title
)
if ok and new_title:
self.tabs.setTabText(index, new_title)
# Navigation methods
def navigate_back(self):
"""Navigate back with history"""
current_tab = self.tabs.currentWidget()
if current_tab and current_tab.history().canGoBack():
current_tab.back()
def navigate_forward(self):
"""Navigate forward with history"""
current_tab = self.tabs.currentWidget()
if current_tab and current_tab.history().canGoForward():
current_tab.forward()
def reload_page(self):
"""Reload current page"""
current_tab = self.tabs.currentWidget()
if current_tab:
current_tab.reload()
def hard_reload(self):
"""Hard reload (bypass cache)"""
current_tab = self.tabs.currentWidget()
if current_tab:
current_tab.page().action(QWebEnginePage.ReloadAndBypassCache).trigger
()
def navigate_home(self):
"""Navigate to home page"""
home_url = self.settings.get('home_page', 'quarix://start')
if home_url == 'quarix://start':
self.tabs.currentWidget().setHtml(self.get_start_page_html())
self.address_bar.setText("")
else:
self.tabs.currentWidget().setUrl(QUrl(home_url))
def address_bar_changed(self, text):
"""Handle address bar text changes for suggestions"""
# TODO: Implement smart suggestions
pass
# Advanced features
def open_dev_tools(self):
"""Open developer tools"""
current_tab = self.tabs.currentWidget()
if current_tab:
dev_tools = QWebEngineView()
current_tab.page().setDevToolsPage(dev_tools.page())
# Create dev tools window
dev_window = QMainWindow()
dev_window.setWindowTitle("Developer Tools - Quarix
Browser")
dev_window.setCentralWidget(dev_tools)
dev_window.resize(1200, 800)
dev_window.show()
# Store reference to prevent garbage collection
if not hasattr(self, 'dev_windows'):
self.dev_windows = []
self.dev_windows.append(dev_window)
def show_performance(self):
"""Show performance metrics"""
perf_dialog = PerformanceDialog(self)
perf_dialog.exec_()
def security_scan(self):
"""Perform security scan of current page"""
current_url = self.get_current_url()
if not current_url:
QMessageBox.information(self.main_window, "Security Scan",
"No page loaded to scan.")
return
# Create security scan dialog
scan_dialog = SecurityScanDialog(self, current_url)
scan_dialog.exec_()
def open_theme_editor(self):
"""Open theme customization"""
theme_dialog = ThemeEditorDialog(self)
theme_dialog.exec_()
def toggle_mobile_view(self):
"""Toggle mobile viewport"""
current_tab = self.tabs.currentWidget()
if current_tab:
# Toggle user agent
if hasattr(current_tab, 'mobile_mode'):
current_tab.mobile_mode = not current_tab.mobile_mode
else:
current_tab.mobile_mode = True
if current_tab.mobile_mode:
# Set mobile user agent
mobile_ua = "Mozilla/5.0 (iPhone; CPU iPhone OS 14_7_1
like Mac OS X) AppleWebKit/605.1.15"
current_tab.page().profile().setHttpUserAgent(mobile_ua)
self.status_bar.showMessage("📱 Mobile view enabled",
3000)
else:
# Reset to desktop user agent
current_tab.page().profile().setHttpUserAgent("")
self.status_bar.showMessage(" Desktop view enabled",
3000)
current_tab.reload()
def new_incognito_tab(self):
"""Create new incognito tab"""
# TODO: Implement proper incognito mode
self.add_new_tab("quarix://start", " Incognito")
self.status_bar.showMessage(" Incognito mode - Your browsing
is private", 3000)
def toggle_fullscreen(self):
"""Toggle fullscreen mode"""
if self.main_window.isFullScreen():
self.main_window.showMaximized()
else:
self.main_window.showFullScreen()
def view_source(self):
"""View page source"""
current_tab = self.tabs.currentWidget()
if current_tab:
current_tab.page().toHtml(self.show_source_dialog)
def show_source_dialog(self, html):
"""Show source code dialog"""
source_dialog = QDialog(self.main_window)
source_dialog.setWindowTitle("Page Source - Quarix Browser")
source_dialog.resize(1000, 700)
layout = QVBoxLayout(source_dialog)
source_text = QTextEdit()
source_text.setPlainText(html)
source_text.setFont(QFont("Consolas", 10))
layout.addWidget(source_text)
close_btn = QPushButton("Close")
close_btn.clicked.connect(source_dialog.close)
layout.addWidget(close_btn)
source_dialog.exec_()
def open_console(self):
"""Open JavaScript console"""
self.open_dev_tools() # Dev tools include console
def clear_browsing_data(self):
"""Clear browsing data dialog"""
clear_dialog = ClearDataDialog(self)
clear_dialog.exec_()
# Window management
def show_bookmarks_manager(self):
"""Show enhanced bookmarks manager"""
if not hasattr(self, 'bookmarks_window') or not
self.bookmarks_window.isVisible():
self.bookmarks_window = EnhancedBookmarksWindow(self)
self.bookmarks_window.show()
self.bookmarks_window.raise_()
self.bookmarks_window.activateWindow()
def show_history_manager(self):
"""Show enhanced history manager"""
if not hasattr(self, 'history_window') or not
self.history_window.isVisible():
self.history_window = EnhancedHistoryWindow(self)
self.history_window.show()
self.history_window.raise_()
self.history_window.activateWindow()
def show_downloads_manager(self):
"""Show enhanced downloads manager"""
if not hasattr(self, 'downloads_window') or not
self.downloads_window.isVisible():
self.downloads_window = EnhancedDownloadsWindow(self)
self.downloads_window.show()
self.downloads_window.raise_()
self.downloads_window.activateWindow()
def show_advanced_settings(self):
"""Show advanced settings"""
if not hasattr(self, 'settings_window') or not
self.settings_window.isVisible():
self.settings_window = AdvancedSettingsWindow(self)
self.settings_window.show()
self.settings_window.raise_()
self.settings_window.activateWindow()
# Data management
def add_to_history(self, url, title):
"""Add URL to history with enhanced data"""
if self.incognito_mode:
return
cursor = self.conn.cursor()
# Check if URL already exists
cursor.execute("SELECT id, visit_count FROM history WHERE url
= ?", (url,))
existing = cursor.fetchone()
if existing:
# Update existing entry
cursor.execute("""
UPDATE history
SET visit_count = visit_count + 1, last_visit = ?,
title = ?
WHERE id = ?
""", (datetime.now(), title, existing[0]))
else:
# Insert new entry
cursor.execute("""
INSERT INTO history (url, title, timestamp,
visit_count,