Code Sketch
graphic_7325*
Category: Art
import javax.swing._
import javax.swing.border._
import javax.swing.table.DefaultTableModel
import java.awt._
import java.awt.event._
import java.awt.geom._
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.Date
// =============================================================================
// 1. CONFIGURATION
// =============================================================================
object AppConfig {
val AppTitle = "ALL INDIA & MAHARASHTRA RTO MAP SUITE"
val AppWidth = 1200
val AppHeight = 780
// Password: INDIA@RTO7313
// MD5 hash is generated below from the password at runtime.
private val LoginSecret = "INDIA@RTO7313"
val AuthPasswordHash: String = {
CryptoUtil.md5Hex(LoginSecret)
}
val PrimaryDark = new Color(24, 43, 73)
val AccentBlue = new Color(41, 128, 185)
val AccentGreen = new Color(39, 174, 96)
val DangerRed = new Color(192, 57, 43)
val CanvasBg = new Color(245, 248, 252)
val TextPrimary = new Color(33, 33, 33)
val TextSecondary = new Color(110, 110, 110)
}
case class MapCoordinate(xRatio: Double, yRatio: Double)
// =============================================================================
// 2. SECURITY
// =============================================================================
object CryptoUtil {
def md5Hex(text: String): String = {
try {
val md = MessageDigest.getInstance("MD5")
val bytes = md.digest(text.getBytes("UTF-8"))
bytes.map { b =>
"%02x".format(b & 0xff)
}.mkString
} catch {
case _: Exception => ""
}
}
def verifyPassword(input: String, targetHash: String): Boolean = {
md5Hex(input.trim).equalsIgnoreCase(targetHash.trim)
}
}
// =============================================================================
// 3. RTO DATABASE
// =============================================================================
object RTODatabase {
val statesAndUTs: Map[String, String] = Map(
"AP" -> "Andhra Pradesh",
"AR" -> "Arunachal Pradesh",
"AS" -> "Assam",
"BR" -> "Bihar",
"CG" -> "Chhattisgarh",
"GA" -> "Goa",
"GJ" -> "Gujarat",
"HR" -> "Haryana",
"HP" -> "Himachal Pradesh",
"JH" -> "Jharkhand",
"KA" -> "Karnataka",
"KL" -> "Kerala",
"MP" -> "Madhya Pradesh",
"MH" -> "Maharashtra",
"MN" -> "Manipur",
"ML" -> "Meghalaya",
"MZ" -> "Mizoram",
"NL" -> "Nagaland",
"OD" -> "Odisha",
"PB" -> "Punjab",
"RJ" -> "Rajasthan",
"SK" -> "Sikkim",
"TN" -> "Tamil Nadu",
"TS" -> "Telangana",
"TR" -> "Tripura",
"UK" -> "Uttarakhand",
"UP" -> "Uttar Pradesh",
"WB" -> "West Bengal",
"AN" -> "Andaman & Nicobar Islands",
"CH" -> "Chandigarh",
"DH" -> "Dadra & Nagar Haveli and Daman & Diu",
"DL" -> "Delhi",
"JK" -> "Jammu & Kashmir",
"LA" -> "Ladakh",
"LD" -> "Lakshadweep",
"PY" -> "Puducherry"
)
val maharashtraRTO: Map[String, String] = Map(
"MH01" -> "Mumbai Central (Tardeo)",
"MH02" -> "Mumbai West (Andheri)",
"MH03" -> "Mumbai East (Wadala)",
"MH04" -> "Thane",
"MH05" -> "Kalyan (Dombivli)",
"MH06" -> "Raigad (Pen)",
"MH07" -> "Sindhudurg (Oros)",
"MH08" -> "Ratnagiri",
"MH09" -> "Kolhapur",
"MH10" -> "Sangli",
"MH11" -> "Satara",
"MH12" -> "Pune City",
"MH13" -> "Solapur",
"MH14" -> "Pimpri-Chinchwad",
"MH15" -> "Nashik",
"MH16" -> "Ahmednagar",
"MH17" -> "Shrirampur (Ahmednagar Rural)",
"MH18" -> "Dhule",
"MH19" -> "Jalgaon",
"MH20" -> "Chhatrapati Sambhajinagar",
"MH21" -> "Jalna",
"MH22" -> "Parbhani",
"MH23" -> "Beed",
"MH24" -> "Latur",
"MH25" -> "Dharashiv",
"MH26" -> "Nanded",
"MH27" -> "Amravati",
"MH28" -> "Buldhana",
"MH29" -> "Yavatmal",
"MH30" -> "Akola",
"MH31" -> "Nagpur Urban",
"MH32" -> "Wardha",
"MH33" -> "Gadchiroli",
"MH34" -> "Chandrapur",
"MH35" -> "Gondia",
"MH36" -> "Bhandara",
"MH37" -> "Washim",
"MH38" -> "Hingoli",
"MH39" -> "Nandurbar",
"MH40" -> "Nagpur Rural",
"MH41" -> "Malegaon",
"MH42" -> "Baramati",
"MH43" -> "Navi Mumbai",
"MH44" -> "Ambejogai",
"MH45" -> "Akluj",
"MH46" -> "Panvel",
"MH47" -> "Borivali",
"MH48" -> "Vasai-Virar",
"MH49" -> "Nagpur East",
"MH50" -> "Karad"
)
val delhiRTO: Map[String, String] = Map(
"DL01" -> "Civil Lines",
"DL02" -> "IP Depot",
"DL03" -> "Sheikh Sarai",
"DL04" -> "Janakpuri",
"DL05" -> "Loni Road",
"DL06" -> "Sarai Kale Khan"
)
val karnatakaRTO: Map[String, String] = Map(
"KA01" -> "Bengaluru Central",
"KA02" -> "Bengaluru West",
"KA03" -> "Bengaluru East",
"KA09" -> "Mysuru West",
"KA19" -> "Mangaluru"
)
val gujaratRTO: Map[String, String] = Map(
"GJ01" -> "Ahmedabad",
"GJ03" -> "Rajkot",
"GJ05" -> "Surat",
"GJ06" -> "Vadodara"
)
val uttarPradeshRTO: Map[String, String] = Map(
"UP14" -> "Ghaziabad",
"UP16" -> "Noida",
"UP32" -> "Lucknow",
"UP78" -> "Kanpur"
)
val madhyaPradeshRTO: Map[String, String] = Map(
"MP04" -> "Bhopal",
"MP09" -> "Indore",
"MP20" -> "Jabalpur"
)
val masterDatabase: Map[String, String] =
statesAndUTs ++
maharashtraRTO ++
delhiRTO ++
karnatakaRTO ++
gujaratRTO ++
uttarPradeshRTO ++
madhyaPradeshRTO
// ---------------------------------------------------------------------------
// Approximate visual coordinates
// ---------------------------------------------------------------------------
val coordinateMap: Map[String, MapCoordinate] = Map(
"AP" -> MapCoordinate(0.46, 0.73),
"AR" -> MapCoordinate(0.86, 0.33),
"AS" -> MapCoordinate(0.79, 0.37),
"BR" -> MapCoordinate(0.61, 0.43),
"CG" -> MapCoordinate(0.51, 0.57),
"GA" -> MapCoordinate(0.33, 0.72),
"GJ" -> MapCoordinate(0.26, 0.49),
"HR" -> MapCoordinate(0.36, 0.31),
"HP" -> MapCoordinate(0.39, 0.22),
"JH" -> MapCoordinate(0.62, 0.49),
"KA" -> MapCoordinate(0.36, 0.76),
"KL" -> MapCoordinate(0.38, 0.88),
"MP" -> MapCoordinate(0.44, 0.49),
"MH" -> MapCoordinate(0.38, 0.58),
"MN" -> MapCoordinate(0.83, 0.42),
"ML" -> MapCoordinate(0.76, 0.40),
"MZ" -> MapCoordinate(0.81, 0.46),
"NL" -> MapCoordinate(0.85, 0.37),
"OD" -> MapCoordinate(0.58, 0.57),
"PB" -> MapCoordinate(0.34, 0.26),
"RJ" -> MapCoordinate(0.31, 0.39),
"SK" -> MapCoordinate(0.69, 0.34),
"TN" -> MapCoordinate(0.42, 0.85),
"TS" -> MapCoordinate(0.45, 0.64),
"TR" -> MapCoordinate(0.78, 0.44),
"UK" -> MapCoordinate(0.43, 0.27),
"UP" -> MapCoordinate(0.49, 0.39),
"WB" -> MapCoordinate(0.68, 0.48),
"DL" -> MapCoordinate(0.37, 0.30),
"JK" -> MapCoordinate(0.35, 0.16),
"LA" -> MapCoordinate(0.40, 0.13),
"CH" -> MapCoordinate(0.36, 0.26),
"DH" -> MapCoordinate(0.29, 0.58),
"PY" -> MapCoordinate(0.44, 0.83),
"LD" -> MapCoordinate(0.29, 0.86),
"AN" -> MapCoordinate(0.79, 0.80),
"MH01" -> MapCoordinate(0.30, 0.60),
"MH02" -> MapCoordinate(0.30, 0.59),
"MH03" -> MapCoordinate(0.31, 0.60),
"MH04" -> MapCoordinate(0.32, 0.59),
"MH05" -> MapCoordinate(0.33, 0.59),
"MH06" -> MapCoordinate(0.31, 0.62),
"MH07" -> MapCoordinate(0.33, 0.70),
"MH08" -> MapCoordinate(0.32, 0.66),
"MH09" -> MapCoordinate(0.34, 0.68),
"MH10" -> MapCoordinate(0.36, 0.67),
"MH11" -> MapCoordinate(0.34, 0.64),
"MH12" -> MapCoordinate(0.34, 0.62),
"MH13" -> MapCoordinate(0.39, 0.65),
"MH14" -> MapCoordinate(0.34, 0.61),
"MH15" -> MapCoordinate(0.33, 0.56),
"MH16" -> MapCoordinate(0.36, 0.60),
"MH17" -> MapCoordinate(0.36, 0.58),
"MH18" -> MapCoordinate(0.34, 0.53),
"MH19" -> MapCoordinate(0.37, 0.54),
"MH20" -> MapCoordinate(0.38, 0.57),
"MH21" -> MapCoordinate(0.40, 0.58),
"MH22" -> MapCoordinate(0.42, 0.60),
"MH23" -> MapCoordinate(0.39, 0.61),
"MH24" -> MapCoordinate(0.41, 0.63),
"MH25" -> MapCoordinate(0.39, 0.63),
"MH26" -> MapCoordinate(0.44, 0.62),
"MH27" -> MapCoordinate(0.43, 0.53),
"MH28" -> MapCoordinate(0.40, 0.54),
"MH29" -> MapCoordinate(0.44, 0.56),
"MH30" -> MapCoordinate(0.41, 0.54),
"MH31" -> MapCoordinate(0.49, 0.52),
"MH32" -> MapCoordinate(0.47, 0.54),
"MH33" -> MapCoordinate(0.51, 0.58),
"MH34" -> MapCoordinate(0.48, 0.58),
"MH35" -> MapCoordinate(0.52, 0.52),
"MH36" -> MapCoordinate(0.50, 0.52),
"MH37" -> MapCoordinate(0.42, 0.56),
"MH38" -> MapCoordinate(0.43, 0.58),
"MH39" -> MapCoordinate(0.33, 0.52),
"MH40" -> MapCoordinate(0.49, 0.53),
"MH41" -> MapCoordinate(0.33, 0.55),
"MH42" -> MapCoordinate(0.35, 0.63),
"MH43" -> MapCoordinate(0.31, 0.60),
"MH44" -> MapCoordinate(0.40, 0.61),
"MH45" -> MapCoordinate(0.38, 0.64),
"MH46" -> MapCoordinate(0.32, 0.61),
"MH47" -> MapCoordinate(0.30, 0.59),
"MH48" -> MapCoordinate(0.30, 0.58),
"MH49" -> MapCoordinate(0.50, 0.53),
"MH50" -> MapCoordinate(0.34, 0.65),
"DL01" -> MapCoordinate(0.37, 0.30),
"DL04" -> MapCoordinate(0.36, 0.31),
"KA01" -> MapCoordinate(0.37, 0.77),
"KA09" -> MapCoordinate(0.36, 0.79),
"GJ01" -> MapCoordinate(0.27, 0.49),
"GJ05" -> MapCoordinate(0.28, 0.53),
"UP32" -> MapCoordinate(0.52, 0.39),
"UP14" -> MapCoordinate(0.38, 0.31),
"MP04" -> MapCoordinate(0.42, 0.51),
"MP09" -> MapCoordinate(0.38, 0.51)
)
}
// =============================================================================
// 4. VECTOR MAP
// =============================================================================
class EnhancedIndiaMapPanel extends JPanel {
private var activeCode = ""
private var activeTitle = ""
setDoubleBuffered(true)
setBackground(AppConfig.CanvasBg)
def setSelectedLocation(code: String, label: String): Unit = {
activeCode = code
activeTitle = label
repaint()
}
def clearSelection(): Unit = {
activeCode = ""
activeTitle = ""
repaint()
}
override def paintComponent(g: Graphics): Unit = {
super.paintComponent(g)
val g2 = g.asInstanceOf[Graphics2D]
g2.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
)
g2.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY
)
val w = getWidth
val h = getHeight
// Background grid
g2.setColor(new Color(236, 240, 245))
var gx = 0
while (gx < w) {
g2.drawLine(gx, 0, gx, h)
gx += 40
}
var gy = 0
while (gy < h) {
g2.drawLine(0, gy, w, gy)
gy += 40
}
// Header
g2.setColor(AppConfig.PrimaryDark)
g2.setFont(new Font("Arial", Font.BOLD, 18))
g2.drawString("ALL INDIA VISUAL MAP ENGINE", 25, 30)
g2.setColor(AppConfig.TextSecondary)
g2.setFont(new Font("Arial", Font.PLAIN, 12))
g2.drawString(
"Territorial pinpointing & RTO coordinate tracker",
25,
48
)
val offsetTop = 60
val offsetBottom = 40
val offsetSide = 30
val drawW = w - offsetSide * 2
val drawH = h - offsetTop - offsetBottom
val startX = offsetSide
val startY = offsetTop
// Approximate India outline
val indiaShape = new Path2D.Double()
val points = Array(
(0.35, 0.08),
(0.42, 0.12),
(0.43, 0.20),
(0.50, 0.25),
(0.55, 0.32),
(0.68, 0.33),
(0.75, 0.30),
(0.85, 0.32),
(0.88, 0.38),
(0.80, 0.42),
(0.72, 0.44),
(0.68, 0.52),
(0.60, 0.58),
(0.52, 0.72),
(0.42, 0.92),
(0.38, 0.94),
(0.36, 0.88),
(0.32, 0.75),
(0.30, 0.65),
(0.22, 0.58),
(0.18, 0.50),
(0.24, 0.42),
(0.26, 0.30),
(0.33, 0.18)
)
val first = points.head
indiaShape.moveTo(
startX + drawW * first._1,
startY + drawH * first._2
)
for (pt <- points.tail) {
indiaShape.lineTo(
startX + drawW * pt._1,
startY + drawH * pt._2
)
}
indiaShape.closePath()
// Shadow
g2.setColor(new Color(0, 0, 0, 25))
val shadowTransform =
AffineTransform.getTranslateInstance(4, 4)
g2.fill(
shadowTransform.createTransformedShape(indiaShape)
)
// India
g2.setColor(new Color(228, 241, 226))
g2.fill(indiaShape)
g2.setColor(new Color(95, 145, 100))
g2.setStroke(new BasicStroke(2.0f))
g2.draw(indiaShape)
// Maharashtra highlight
val mhArea = new Path2D.Double()
val mhPts = Array(
(0.30, 0.55),
(0.42, 0.52),
(0.50, 0.54),
(0.48, 0.62),
(0.38, 0.67),
(0.32, 0.67),
(0.30, 0.60)
)
mhArea.moveTo(
startX + drawW * mhPts.head._1,
startY + drawH * mhPts.head._2
)
for (pt <- mhPts.tail) {
mhArea.lineTo(
startX + drawW * pt._1,
startY + drawH * pt._2
)
}
mhArea.closePath()
g2.setColor(new Color(254, 235, 185))
g2.fill(mhArea)
g2.setColor(new Color(214, 160, 50))
g2.setStroke(
new BasicStroke(
1.5f,
BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND,
0,
Array(4.0f, 4.0f),
0
)
)
g2.draw(mhArea)
// -------------------------------------------------------------------------
// Pin
// -------------------------------------------------------------------------
val targetCoord =
if (RTODatabase.coordinateMap.contains(activeCode)) {
Some(RTODatabase.coordinateMap(activeCode))
}
else if (
activeCode.length >= 2 &&
RTODatabase.coordinateMap.contains(activeCode.substring(0, 2))
) {
Some(
RTODatabase.coordinateMap(
activeCode.substring(0, 2)
)
)
}
else {
None
}
if (activeCode.nonEmpty && targetCoord.isDefined) {
val coord = targetCoord.get
val pinPixelX =
startX + (drawW * coord.xRatio).toInt
val pinPixelY =
startY + (drawH * coord.yRatio).toInt
// Glow
g2.setColor(new Color(231, 76, 60, 90))
g2.fillOval(
pinPixelX - 16,
pinPixelY - 16,
32,
32
)
// Pin
g2.setColor(AppConfig.DangerRed)
g2.fillOval(
pinPixelX - 7,
pinPixelY - 7,
14,
14
)
g2.setColor(Color.WHITE)
g2.fillOval(
pinPixelX - 3,
pinPixelY - 3,
6,
6
)
// Badge
val badgeText =
activeCode + " : " + activeTitle
g2.setFont(
new Font(
"Arial",
Font.BOLD,
12
)
)
val fm = g2.getFontMetrics
val textW =
fm.stringWidth(badgeText)
val boxX = pinPixelX + 14
val boxY = pinPixelY - 12
val boxW = textW + 16
val boxH = fm.getHeight + 6
g2.setColor(AppConfig.PrimaryDark)
g2.fillRoundRect(
boxX,
boxY,
boxW,
boxH,
8,
8
)
g2.setColor(Color.WHITE)
g2.drawString(
badgeText,
boxX + 8,
boxY + fm.getAscent + 2
)
g2.setColor(AppConfig.PrimaryDark)
g2.setStroke(new BasicStroke(1.5f))
g2.drawLine(
pinPixelX,
pinPixelY,
boxX,
boxY + boxH / 2
)
}
// Legend
val lx = w - 230
val ly = h - 65
g2.setColor(new Color(255, 255, 255, 220))
g2.fillRoundRect(
lx,
ly,
215,
45,
8,
8
)
g2.setColor(new Color(200, 205, 215))
g2.drawRoundRect(
lx,
ly,
215,
45,
8,
8
)
g2.setColor(AppConfig.DangerRed)
g2.fillOval(
lx + 12,
ly + 16,
12,
12
)
g2.setColor(AppConfig.TextPrimary)
g2.setFont(new Font("Arial", Font.PLAIN, 12))
g2.drawString(
"RTO Location",
lx + 30,
ly + 27
)
}
}
// =============================================================================
// 5. MAIN APPLICATION
// =============================================================================
class RTOMapApplication {
val frame =
new JFrame(AppConfig.AppTitle)
frame.setSize(
AppConfig.AppWidth,
AppConfig.AppHeight
)
frame.setLocationRelativeTo(null)
frame.setDefaultCloseOperation(
WindowConstants.EXIT_ON_CLOSE
)
private val mapCanvas =
new EnhancedIndiaMapPanel()
private val searchTextField =
new JTextField(10)
private val searchResultArea =
new JTextArea()
private val historyTableModel =
new DefaultTableModel()
private val historyTable =
new JTable(historyTableModel)
private val statusLabel =
new JLabel("Ready")
private val resultCountBadge =
new JLabel("0 results")
// ===========================================================================
// START
// ===========================================================================
def start(): Unit = {
displayLoginScreen()
frame.setVisible(true)
}
// ===========================================================================
// LOGIN SCREEN
// ===========================================================================
def displayLoginScreen(): Unit = {
frame.getContentPane.removeAll()
val rootPanel =
new JPanel(new BorderLayout())
rootPanel.setBackground(
AppConfig.CanvasBg
)
val headerPanel =
new JPanel(
new FlowLayout(
FlowLayout.CENTER,
20,
25
)
)
headerPanel.setBackground(
AppConfig.PrimaryDark
)
val appHeaderTitle =
new JLabel(
"INDIA RTO DIRECTORY & GEOLOCATION SUITE"
)
appHeaderTitle.setFont(
new Font(
"Arial",
Font.BOLD,
24
)
)
appHeaderTitle.setForeground(
Color.WHITE
)
headerPanel.add(appHeaderTitle)
rootPanel.add(
headerPanel,
BorderLayout.NORTH
)
val centerContainer =
new JPanel(
new GridBagLayout()
)
centerContainer.setOpaque(false)
val cardPanel =
new JPanel()
cardPanel.setLayout(
new BoxLayout(
cardPanel,
BoxLayout.Y_AXIS
)
)
cardPanel.setBackground(
Color.WHITE
)
cardPanel.setBorder(
BorderFactory.createCompoundBorder(
new LineBorder(
new Color(220, 226, 235),
1,
true
),
new EmptyBorder(
35,
45,
35,
45
)
)
)
val lockSymbol =
new JLabel("LOCKED")
lockSymbol.setFont(
new Font(
"Arial",
Font.BOLD,
28
)
)
lockSymbol.setAlignmentX(
Component.CENTER_ALIGNMENT
)
val loginPrompt =
new JLabel(
"Secure Login"
)
loginPrompt.setFont(
new Font(
"Arial",
Font.BOLD,
20
)
)
loginPrompt.setForeground(
AppConfig.PrimaryDark
)
loginPrompt.setAlignmentX(
Component.CENTER_ALIGNMENT
)
val hintText =
new JLabel(
"Enter your password to continue"
)
hintText.setFont(
new Font(
"Arial",
Font.PLAIN,
13
)
)
hintText.setForeground(
AppConfig.TextSecondary
)
hintText.setAlignmentX(
Component.CENTER_ALIGNMENT
)
val passwordField =
new JPasswordField(16)
passwordField.setFont(
new Font(
"Arial",
Font.PLAIN,
18
)
)
passwordField.setMaximumSize(
new Dimension(300, 42)
)
passwordField.setPreferredSize(
new Dimension(300, 42)
)
passwordField.setHorizontalAlignment(
SwingConstants.CENTER
)
// Password characters are hidden
passwordField.setEchoChar('?')
passwordField.setAlignmentX(
Component.CENTER_ALIGNMENT
)
val errorNotice =
new JLabel(" ")
errorNotice.setFont(
new Font(
"Arial",
Font.BOLD,
13
)
)
errorNotice.setForeground(
AppConfig.DangerRed
)
errorNotice.setAlignmentX(
Component.CENTER_ALIGNMENT
)
val submitButton =
new JButton("LOGIN")
submitButton.setFont(
new Font(
"Arial",
Font.BOLD,
15
)
)
submitButton.setForeground(
Color.WHITE
)
submitButton.setBackground(
AppConfig.AccentBlue
)
submitButton.setFocusPainted(false)
submitButton.setPreferredSize(
new Dimension(300, 42)
)
submitButton.setMaximumSize(
new Dimension(300, 42)
)
submitButton.setAlignmentX(
Component.CENTER_ALIGNMENT
)
submitButton.setCursor(
new Cursor(
Cursor.HAND_CURSOR
)
)
cardPanel.add(lockSymbol)
cardPanel.add(
Box.createVerticalStrut(12)
)
cardPanel.add(loginPrompt)
cardPanel.add(
Box.createVerticalStrut(6)
)
cardPanel.add(hintText)
cardPanel.add(
Box.createVerticalStrut(20)
)
cardPanel.add(passwordField)
cardPanel.add(
Box.createVerticalStrut(10)
)
cardPanel.add(errorNotice)
cardPanel.add(
Box.createVerticalStrut(10)
)
cardPanel.add(submitButton)
centerContainer.add(cardPanel)
rootPanel.add(
centerContainer,
BorderLayout.CENTER
)
def performAuthentication(): Unit = {
val enteredString =
new String(
passwordField.getPassword
)
if (
CryptoUtil.verifyPassword(
enteredString,
AppConfig.AuthPasswordHash
)
) {
displayMainApplicationView()
} else {
errorNotice.setText(
"Incorrect password!"
)
passwordField.setText("")
passwordField.requestFocus()
}
}
submitButton.addActionListener(
(_: ActionEvent) =>
performAuthentication()
)
passwordField.addActionListener(
(_: ActionEvent) =>
performAuthentication()
)
frame.setContentPane(rootPanel)
frame.revalidate()
frame.repaint()
passwordField.requestFocus()
}
// ===========================================================================
// MAIN VIEW
// ===========================================================================
def displayMainApplicationView(): Unit = {
frame.getContentPane.removeAll()
val rootPanel =
new JPanel(
new BorderLayout()
)
rootPanel.setBackground(
AppConfig.CanvasBg
)
rootPanel.add(
constructTopNavigationBar(),
BorderLayout.NORTH
)
rootPanel.add(
constructCentralWorkspace(),
BorderLayout.CENTER
)
rootPanel.add(
constructBottomStatusBar(),
BorderLayout.SOUTH
)
frame.setContentPane(rootPanel)
frame.revalidate()
frame.repaint()
searchTextField.requestFocus()
}
// ===========================================================================
// TOP BAR
// ===========================================================================
private def constructTopNavigationBar(): JPanel = {
val topPanel =
new JPanel(
new BorderLayout()
)
topPanel.setBackground(
AppConfig.PrimaryDark
)
topPanel.setBorder(
new EmptyBorder(
12,
20,
12,
20
)
)
val brandBox =
new JPanel(
new GridLayout(2, 1, 0, 2)
)
brandBox.setOpaque(false)
val brandTitle =
new JLabel(
"ALL INDIA RTO INFORMATION & MAP SYSTEM"
)
brandTitle.setFont(
new Font(
"Arial",
Font.BOLD,
20
)
)
brandTitle.setForeground(
Color.WHITE
)
val brandSubtitle =
new JLabel(
"India States, Union Territories & RTO Code Directory"
)
brandSubtitle.setFont(
new Font(
"Arial",
Font.PLAIN,
12
)
)
brandSubtitle.setForeground(
new Color(
189,
195,
199
)
)
brandBox.add(brandTitle)
brandBox.add(brandSubtitle)
topPanel.add(
brandBox,
BorderLayout.WEST
)
val searchBarPanel =
new JPanel(
new FlowLayout(
FlowLayout.RIGHT,
10,
5
)
)
searchBarPanel.setOpaque(false)
val searchPromptLabel =
new JLabel(
"State / RTO Code:"
)
searchPromptLabel.setFont(
new Font(
"Arial",
Font.BOLD,
14
)
)
searchPromptLabel.setForeground(
Color.WHITE
)
searchTextField.setFont(
new Font(
"Arial",
Font.BOLD,
16
)
)
searchTextField.setPreferredSize(
new Dimension(130, 36)
)
searchTextField.setHorizontalAlignment(
SwingConstants.CENTER
)
searchTextField.setToolTipText(
"Examples: GJ, KA, UP, DL, MH12"
)
val searchActionBtn =
new JButton("SEARCH")
styleButton(
searchActionBtn,
AppConfig.AccentBlue,
Color.WHITE
)
val resetActionBtn =
new JButton("CLEAR")
styleButton(
resetActionBtn,
new Color(127, 140, 141),
Color.WHITE
)
val logoutActionBtn =
new JButton("LOGOUT")
styleButton(
logoutActionBtn,
AppConfig.DangerRed,
Color.WHITE
)
searchBarPanel.add(
searchPromptLabel
)
searchBarPanel.add(
searchTextField
)
searchBarPanel.add(
searchActionBtn
)
searchBarPanel.add(
resetActionBtn
)
searchBarPanel.add(
logoutActionBtn
)
topPanel.add(
searchBarPanel,
BorderLayout.EAST
)
searchActionBtn.addActionListener(
(_: ActionEvent) =>
executeLookup()
)
searchTextField.addActionListener(
(_: ActionEvent) =>
executeLookup()
)
resetActionBtn.addActionListener(
(_: ActionEvent) =>
clearAllFields()
)
logoutActionBtn.addActionListener(
(_: ActionEvent) =>
displayLoginScreen()
)
topPanel
}
// ===========================================================================
// BUTTON STYLE
// ===========================================================================
private def styleButton(
btn: JButton,
bg: Color,
fg: Color
): Unit = {
btn.setBackground(bg)
btn.setForeground(fg)
btn.setFont(
new Font(
"Arial",
Font.BOLD,
12
)
)
btn.setFocusPainted(false)
btn.setBorder(
new EmptyBorder(
8,
14,
8,
14
)
)
btn.setCursor(
new Cursor(
Cursor.HAND_CURSOR
)
)
}
// ===========================================================================
// CENTRAL WORKSPACE
// ===========================================================================
private def constructCentralWorkspace(): JPanel = {
val workspacePanel =
new JPanel(
new GridLayout(
1,
2,
10,
0
)
)
workspacePanel.setBackground(
AppConfig.CanvasBg
)
workspacePanel.setBorder(
new EmptyBorder(
10,
15,
10,
15
)
)
workspacePanel.add(
constructDataExplorerPanel()
)
workspacePanel.add(
mapCanvas
)
workspacePanel
}
// ===========================================================================
// DATA EXPLORER
// ===========================================================================
private def constructDataExplorerPanel(): JPanel = {
val explorerPanel =
new JPanel(
new BorderLayout(
0,
10
)
)
explorerPanel.setOpaque(false)
val resultWrapper =
new JPanel(
new BorderLayout()
)
resultWrapper.setBackground(
Color.WHITE
)
resultWrapper.setBorder(
BorderFactory.createCompoundBorder(
new LineBorder(
new Color(
218,
225,
233
),
1,
true
),
new EmptyBorder(
10,
10,
10,
10
)
)
)
val resultHeader =
new JPanel(
new BorderLayout()
)
resultHeader.setOpaque(false)
val resultTitle =
new JLabel(
"SEARCH OUTPUT"
)
resultTitle.setFont(
new Font(
"Arial",
Font.BOLD,
15
)
)
resultTitle.setForeground(
AppConfig.PrimaryDark
)
resultCountBadge.setFont(
new Font(
"Arial",
Font.BOLD,
11
)
)
resultCountBadge.setForeground(
AppConfig.AccentBlue
)
resultHeader.add(
resultTitle,
BorderLayout.WEST
)
resultHeader.add(
resultCountBadge,
BorderLayout.EAST
)
resultWrapper.add(
resultHeader,
BorderLayout.NORTH
)
searchResultArea.setEditable(false)
searchResultArea.setLineWrap(true)
searchResultArea.setWrapStyleWord(true)
searchResultArea.setFont(
new Font(
"Monospaced",
Font.PLAIN,
13
)
)
searchResultArea.setBackground(
new Color(
250,
252,
255
)
)
searchResultArea.setBorder(
new EmptyBorder(
8,
8,
8,
8
)
)
populateDefaultInstructions()
val textScroll =
new JScrollPane(
searchResultArea
)
textScroll.setBorder(
new LineBorder(
new Color(
230,
235,
245
),
1
)
)
resultWrapper.add(
textScroll,
BorderLayout.CENTER
)
explorerPanel.add(
resultWrapper,
BorderLayout.CENTER
)
// History
val historyPanel =
new JPanel(
new BorderLayout(
0,
5
)
)
historyPanel.setPreferredSize(
new Dimension(
500,
210
)
)
historyPanel.setBackground(
Color.WHITE
)
historyPanel.setBorder(
BorderFactory.createCompoundBorder(
new LineBorder(
new Color(
218,
225,
233
),
1,
true
),
new EmptyBorder(
8,
10,
8,
10
)
)
)
val historyTitle =
new JLabel(
"RECENT SEARCHES"
)
historyTitle.setFont(
new Font(
"Arial",
Font.BOLD,
13
)
)
historyTitle.setForeground(
AppConfig.PrimaryDark
)
historyPanel.add(
historyTitle,
BorderLayout.NORTH
)
historyTableModel.addColumn("Time")
historyTableModel.addColumn("Code")
historyTableModel.addColumn("Location")
historyTableModel.addColumn("Type")
historyTable.setFont(
new Font(
"Arial",
Font.PLAIN,
11
)
)
historyTable.setRowHeight(22)
historyTable.getTableHeader.setFont(
new Font(
"Arial",
Font.BOLD,
11
)
)
historyTable.getTableHeader.setBackground(
new Color(
240,
243,
248
)
)
val tableScroll =
new JScrollPane(
historyTable
)
tableScroll.setBorder(
new LineBorder(
new Color(
230,
235,
245
),
1
)
)
historyPanel.add(
tableScroll,
BorderLayout.CENTER
)
explorerPanel.add(
historyPanel,
BorderLayout.SOUTH
)
explorerPanel
}
// ===========================================================================
// STATUS BAR
// ===========================================================================
private def constructBottomStatusBar(): JPanel = {
val bar =
new JPanel(
new BorderLayout()
)
bar.setBackground(
Color.WHITE
)
bar.setBorder(
BorderFactory.createCompoundBorder(
new MatteBorder(
1,
0,
0,
0,
new Color(
220,
225,
230
)
),
new EmptyBorder(
6,
20,
6,
20
)
)
)
statusLabel.setFont(
new Font(
"Arial",
Font.BOLD,
12
)
)
statusLabel.setForeground(
AppConfig.AccentGreen
)
bar.add(
statusLabel,
BorderLayout.WEST
)
val systemInfo =
new JLabel(
"Active Records: " +
RTODatabase.masterDatabase.size +
" | Vector Engine Active"
)
systemInfo.setFont(
new Font(
"Arial",
Font.PLAIN,
11
)
)
systemInfo.setForeground(
AppConfig.TextSecondary
)
bar.add(
systemInfo,
BorderLayout.EAST
)
bar
}
// ===========================================================================
// SEARCH
// ===========================================================================
def executeLookup(): Unit = {
val rawInput =
searchTextField.getText
val query =
rawInput
.trim
.toUpperCase
.replaceAll(
"\\s+",
""
)
if (query.isEmpty) {
statusLabel.setText(
"Please enter a state or RTO code."
)
statusLabel.setForeground(
AppConfig.DangerRed
)
searchResultArea.setText(
"""SEARCH HELP
|
|Try:
| GJ
| KA
| UP
| DL
| MH
| MH12
| MH14
|""".stripMargin
)
mapCanvas.clearSelection()
resultCountBadge.setText(
"0 results"
)
return
}
val timestamp =
new SimpleDateFormat(
"HH:mm:ss"
).format(
new Date()
)
if (
RTODatabase.masterDatabase.contains(query)
) {
val locationName =
RTODatabase.masterDatabase(query)
val isStateOnly =
RTODatabase.statesAndUTs.contains(query)
val childCodes =
RTODatabase.masterDatabase.keys
.filter(
k =>
k.startsWith(query) &&
k != query
)
.toSeq
.sorted
val sb =
new StringBuilder()
sb.append(
"=================================================================\n"
)
sb.append(
" RTO SEARCH RESULT\n"
)
sb.append(
"=================================================================\n\n"
)
sb.append(
"Code : " +
query +
"\n"
)
sb.append(
"Location : " +
locationName +
"\n"
)
sb.append(
"Category : " +
(
if (isStateOnly)
"State / Union Territory"
else
"RTO Office"
) +
"\n"
)
sb.append(
"Time : " +
timestamp +
"\n\n"
)
if (childCodes.nonEmpty) {
sb.append(
"-----------------------------------------------------------------\n"
)
sb.append(
"Child RTO / Records (" +
childCodes.size +
"):\n"
)
sb.append(
"-----------------------------------------------------------------\n"
)
for (c <- childCodes) {
val subName =
RTODatabase.masterDatabase(c)
sb.append(
"%-8s -> %s\n"
.format(
c,
subName
)
)
}
} else {
sb.append(
"No child RTO records available.\n"
)
}
sb.append(
"\n=================================================================\n"
)
sb.append(
"Vector map pin updated for the selected location."
)
searchResultArea.setText(
sb.toString()
)
searchResultArea.setCaretPosition(0)
mapCanvas.setSelectedLocation(
query,
locationName
)
val recType =
if (isStateOnly)
"State Authority"
else
"District RTO"
historyTableModel.insertRow(
0,
Array[AnyRef](
timestamp,
query,
locationName,
recType
)
)
statusLabel.setText(
"Found: " +
query +
" -> " +
locationName
)
statusLabel.setForeground(
AppConfig.AccentGreen
)
resultCountBadge.setText(
(childCodes.size + 1) +
" records"
)
} else {
val partialMatches =
RTODatabase.masterDatabase.keys
.filter(
_.startsWith(query)
)
.toSeq
.sorted
if (partialMatches.nonEmpty) {
val sb =
new StringBuilder()
sb.append(
"=================================================================\n"
)
sb.append(
" PARTIAL MATCHES\n"
)
sb.append(
"=================================================================\n\n"
)
sb.append(
"Matches for '" +
query +
"':\n\n"
)
for (m <- partialMatches) {
val loc =
RTODatabase.masterDatabase(m)
sb.append(
"%-8s -> %s\n"
.format(
m,
loc
)
)
}
sb.append(
"\nSelect one of the codes above and search again."
)
searchResultArea.setText(
sb.toString()
)
searchResultArea.setCaretPosition(0)
mapCanvas.clearSelection()
historyTableModel.insertRow(
0,
Array[AnyRef](
timestamp,
query,
partialMatches.size +
" partial matches",
"Partial Match"
)
)
statusLabel.setText(
partialMatches.size +
" partial matches found."
)
statusLabel.setForeground(
AppConfig.AccentBlue
)
resultCountBadge.setText(
partialMatches.size +
" matches"
)
} else {
searchResultArea.setText(
"'" +
query +
"' was not found.\n\n" +
"Examples: GJ, KA, UP, DL, MP, RJ, TN, MH12"
)
searchResultArea.setCaretPosition(0)
mapCanvas.clearSelection()
historyTableModel.insertRow(
0,
Array[AnyRef](
timestamp,
query,
"Not Found",
"Invalid Code"
)
)
statusLabel.setText(
"'" +
query +
"' not found."
)
statusLabel.setForeground(
AppConfig.DangerRed
)
resultCountBadge.setText(
"0 records"
)
}
}
}
// ===========================================================================
// CLEAR
// ===========================================================================
private def clearAllFields(): Unit = {
searchTextField.setText("")
populateDefaultInstructions()
mapCanvas.clearSelection()
statusLabel.setText(
"Search cleared."
)
statusLabel.setForeground(
AppConfig.TextSecondary
)
resultCountBadge.setText(
"0 results"
)
searchTextField.requestFocus()
}
// ===========================================================================
// DEFAULT HELP
// ===========================================================================
private def populateDefaultInstructions(): Unit = {
val defaultText =
"""=================================================================
| INDIA RTO DIRECTORY
|=================================================================
|
|HOW TO SEARCH
|
|1. Enter a State / UT code or RTO code.
|2. Press SEARCH or Enter.
|3. The matching location will appear on the map.
|
|STATE EXAMPLES
|
|GJ = Gujarat
|KA = Karnataka
|UP = Uttar Pradesh
|MP = Madhya Pradesh
|DL = Delhi
|RJ = Rajasthan
|MH = Maharashtra
|
|MAHARASHTRA RTO EXAMPLES
|
|MH01 = Mumbai Central
|MH12 = Pune City
|MH14 = Pimpri-Chinchwad
|MH15 = Nashik
|MH31 = Nagpur Urban
|
|The map displays an approximate visual pin for the
|selected state / RTO location.
|
|================================================================="""
.stripMargin
searchResultArea.setText(
defaultText
)
searchResultArea.setCaretPosition(0)
}
}
// =============================================================================
// 6. APPLICATION ENTRY POINT
// =============================================================================
val appInstance =
new RTOMapApplication()
appInstance.start()