Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
MIT License

Copyright (C) 2023 Abdullah O. Mustapha
Copyright (c) 2023 Abdullah Mustapha

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
149 changes: 118 additions & 31 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QFileDialog, QFontDialog, QVBoxLayout, QWidget, QMenuBar, QMessageBox, QPlainTextEdit
from PyQt5.QtCore import QDateTime, QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QFileDialog, QFontDialog, QMessageBox, QPlainTextEdit, QStatusBar, QInputDialog
from PyQt5.QtCore import QDateTime, QUrl, QTextCodec
from PyQt5.QtGui import QIcon, QFont, QDesktopServices
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter




class PlainTextEdit(QPlainTextEdit):
Expand All @@ -17,7 +20,6 @@ def __init__(self, parent=None):
self.setFont(default_font)

def insertFromMimeData(self, mime_data):
# Override insertFromMimeData to prevent the automatic formatting of pasted text
cursor = self.textCursor()
cursor.insertText(mime_data.text())
self.setTextCursor(cursor)
Expand All @@ -30,11 +32,19 @@ def __init__(self):
# Initialize UI
self.init_ui()

self.new_notepad = None

def init_ui(self):
# Create a QTextEdit widget
self.text_edit = PlainTextEdit(self)
self.setCentralWidget(self.text_edit)

# Increase font size for the menu bar
menubar = self.menuBar()
menubar_font = menubar.font()
menubar_font.setPointSize(11) # Adjust the font size as needed
menubar.setFont(menubar_font)

# Create Find dialog
self.setWindowIcon(QIcon('icon.ico'))
# Create a menu bar
Expand All @@ -44,22 +54,27 @@ def init_ui(self):
file_menu = menubar.addMenu('File')

new_action = QAction('New', self)
new_action.setShortcut("Ctrl+N")
new_action.triggered.connect(self.new_file)
file_menu.addAction(new_action)

new_window_action = QAction('New Window', self)
new_window_action.setShortcut("Ctrl+Shift+N")
new_window_action.triggered.connect(self.new_window)
file_menu.addAction(new_window_action)

open_action = QAction('Open', self)
open_action.setShortcut("Ctrl+O")
open_action.triggered.connect(self.open_file)
file_menu.addAction(open_action)

save_action = QAction('Save', self)
save_action.setShortcut("Ctrl+S")
save_action.triggered.connect(self.save_file)
file_menu.addAction(save_action)

save_as_action = QAction('Save As...', self)
save_as_action.setShortcut("Ctrl+Shift+S")
save_as_action.triggered.connect(self.save_file_as)
file_menu.addAction(save_as_action)

Expand All @@ -70,67 +85,67 @@ def init_ui(self):
file_menu.addAction(page_setup_action)

print_action = QAction('Print', self)
print_action.setShortcut("Ctrl+P")
print_action.triggered.connect(self.print_file)
file_menu.addAction(print_action)

file_menu.addSeparator()

exit_action = QAction('Exit', self)
exit_action.setShortcut("Alt+F4")
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)

# Create Edit menu
edit_menu = menubar.addMenu('Edit')

undo_action = QAction('Undo', self)
undo_action.setShortcut("Ctrl+Z")
undo_action.triggered.connect(self.text_edit.undo)
edit_menu.addAction(undo_action)

redo_action = QAction('Redo', self)
redo_action.setShortcut("Ctrl+Y")
redo_action.triggered.connect(self.text_edit.redo)
edit_menu.addAction(redo_action)

edit_menu.addSeparator()

cut_action = QAction('Cut', self)
cut_action.setShortcut("Ctrl+X")
cut_action.triggered.connect(self.text_edit.cut)
edit_menu.addAction(cut_action)

copy_action = QAction('Copy', self)
copy_action.setShortcut("Ctrl+C")
copy_action.triggered.connect(self.text_edit.copy)
edit_menu.addAction(copy_action)

paste_action = QAction('Paste', self)
paste_action.setShortcut("Ctrl+V")
paste_action.triggered.connect(self.text_edit.paste)
edit_menu.addAction(paste_action)

delete_action = QAction('Delete', self)
delete_action.setShortcut("Del")
delete_action.triggered.connect(self.text_edit.cut) # Delete is equivalent to Cut
edit_menu.addAction(delete_action)

edit_menu.addSeparator()

find_action = QAction('Find', self)
find_action.triggered.connect(self.find_dialog)
edit_menu.addAction(find_action)

replace_action = QAction('Replace', self)
replace_action.triggered.connect(self.replace)
edit_menu.addAction(replace_action)

edit_menu.addSeparator()

goto_action = QAction('Go To', self)
goto_action.triggered.connect(self.goto_dialog)
edit_menu.addAction(goto_action)

edit_menu.addSeparator()

select_all_action = QAction('Select All', self)
select_all_action.setShortcut("Ctrl+A")
select_all_action.triggered.connect(self.text_edit.selectAll)
edit_menu.addAction(select_all_action)

time_date_action = QAction('Time/Date', self)
time_date_action.setShortcut("Ctrl+T")
time_date_action.triggered.connect(self.insert_time_date)
edit_menu.addAction(time_date_action)

Expand All @@ -141,9 +156,37 @@ def init_ui(self):
font_action.triggered.connect(self.change_font)
format_menu.addAction(font_action)

wordWrap_action = QAction('Word wrap', self)
wordWrap_action.setCheckable(True)
format_menu.addAction(wordWrap_action)

# Create View menu
view_menu = menubar.addMenu('View')

zoom_menu = view_menu.addMenu("Zoom...")
zoom_in = zoom_menu.addAction('Zoom in')
zoom_in.setShortcut("Ctrl+1") # Adjust the shortcut as needed
zoom_in.triggered.connect(self.zoom_in)

zoom_out = zoom_menu.addAction('Zoom out')
zoom_out.setShortcut("Ctrl+0") # Adjust the shortcut as needed
zoom_out.triggered.connect(self.zoom_out)


# Create a status bar
self.status_bar = QStatusBar(self)
self.setStatusBar(self.status_bar)

# Create a QAction for the status bar
status_bar_action = QAction('Status bar', self)
status_bar_action.setCheckable(True)
status_bar_action.setChecked(True)
status_bar_action.triggered.connect(self.toggle_status_bar)
view_menu.addAction(status_bar_action)

self.update_status_bar
self.text_edit.textChanged.connect(self.update_status_bar)

# Create Help menu
help_menu = menubar.addMenu('Help')

Expand All @@ -164,32 +207,67 @@ def init_ui(self):
# Set window properties
self.setGeometry(100, 100, 800, 600)
self.setWindowTitle('Notepad')


def toggle_status_bar(self, checked):
if checked:
self.status_bar.show()
else:
self.status_bar.hide()
def update_status_bar(self):
cursor = self.text_edit.textCursor()
block = cursor.block()
line_number = block.blockNumber() + 1
column_number = cursor.positionInBlock() + 1

# Get plain text content
plain_text = self.text_edit.toPlainText()

# Use QTextCodec to detect the encoding
codec = QTextCodec.codecForName("UTF-8")
encoding = codec.name()

status_text = f'Ln {line_number}, Col {column_number} | Encoding: {encoding}'
self.status_bar.showMessage(status_text)

def zoom_in(self):
self.text_edit.zoomIn(1)
def zoom_out(self):
self.text_edit.zoomOut(1)
def view_help(self):
feedback_url = 'https://github.com/abdullahCoder-Tech/Notepad'
feedback_url = 'https://github.com/abdullahCoder-Tech/Notepad/blob/main/README.md'
QDesktopServices.openUrl(QUrl(feedback_url))

def send_feedback(self):
# Open the feedback URL in the default web browser
feedback_url = 'https://github.com/abdullahCoder-Tech/Notepad'
feedback_url = 'https://github.com/abdullahCoder-Tech/Notepad/issues/new'
QDesktopServices.openUrl(QUrl(feedback_url))

def about_notepad(self):
about_message = (
"Notepad Application\n"
"About this app\n\n"
"Author: Abdullah O. Mustapha\n"
"Version: v1.0\n"
"License: GNU General Public License\n"
"\n\nAll Rights Reserved"
"Version: v1.0.1\n"
"License: MIT License\n"
"\n\n© 2023 Drop Dev. All rights reserved"
)
QMessageBox.information(self, 'About Notepad', about_message, QMessageBox.Ok)

def new_file(self):
self.text_edit.clear()

# def new_window(self):
# new_notepad = Notepad()
# new_notepad.show()

def new_window(self):
new_notepad = Notepad()
new_notepad.show()
# Check if a new window is already open
if self.new_notepad is None or not self.new_notepad.isVisible():
# Create a new instance of Notepad
self.new_notepad = Notepad()
self.new_notepad.show()
else:
# Bring the existing window to front
self.new_notepad.raise_()

def open_file(self):
options = QFileDialog.Options()
Expand All @@ -208,31 +286,40 @@ def save_file(self):

def save_file_as(self):
options = QFileDialog.Options()
file_name, _ = QFileDialog.getSaveFileName(self, 'Save File', '', 'Text Files (*.txt);;All Files (.)', options=options)
file_name, _ = QFileDialog.getSaveFileName(self, 'Save File', '', 'Text Files (*.txt);;C++ Files (*.cpp);;C Files(*.c);;Python Files (*.py);;All Files (.)', options=options)
if file_name:
self.current_file = file_name
self.save_file()

def page_setup(self):
QMessageBox.information(self, 'Info', 'Coming Soon', QMessageBox.Ok)
pass


def print_file(self):
QMessageBox.information(self, 'Info', 'Coming Soon', QMessageBox.Ok)
printer = QPrinter(QPrinter.HighResolution)
dialog = QPrintDialog(printer, self)
if dialog.exec_() == QPrintDialog.Accepted:
self.text_edit.print_(printer)

def change_font(self):
font, ok = QFontDialog.getFont(self.text_edit.font(), self)
if ok:
self.text_edit.setFont(font)

def goto_dialog(self):
QMessageBox.information(self, 'Info', 'Coming Soon', QMessageBox.Ok)
# Get the total number of lines in the text editor
total_lines = self.text_edit.document().blockCount()

def replace(self):
QMessageBox.information(self, 'Info', 'Coming Soon', QMessageBox.Ok)
# Display an input dialog for the user to enter the line number
line_number, ok = QInputDialog.getInt(self, 'Go To Line', 'Enter Line Number (1 - {}):'.format(total_lines), min=1, max=total_lines)

def find_dialog(self):
QMessageBox.information(self, 'Info', 'Coming Soon', QMessageBox.Ok)
if ok:
# Move the cursor to the specified line
cursor = self.text_edit.textCursor()
cursor.movePosition(cursor.Start)
for _ in range(line_number - 1):
cursor.movePosition(cursor.NextBlock)

self.text_edit.setTextCursor(cursor)

def insert_time_date(self):
current_date_time = QDateTime.currentDateTime().toString('MM/dd/yyyy hh:mm:ss AP')
Expand Down